[ server ] [ xray ] - 完成Xray Json的生成功能 - 1

This commit is contained in:
zeaslity
2023-02-10 17:17:26 +08:00
parent 70c48f11a3
commit a7caec8853
17 changed files with 360 additions and 90 deletions

View File

@@ -6,23 +6,25 @@ import io.wdd.func.xray.beans.xray.transport.StreamSettingsObject;
import io.wdd.func.xray.beans.xray.transport.TcpObject; import io.wdd.func.xray.beans.xray.transport.TcpObject;
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.VMESS; import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.VMESS;
import static io.wdd.func.xray.beans.config.TcpHttpHeaderTemplate.HttpRequestTemplate;
import static io.wdd.func.xray.beans.config.TcpHttpHeaderTemplate.HttpResponseTemplate; import static io.wdd.func.xray.beans.config.TcpHttpHeaderTemplate.HttpResponseTemplate;
public class InboundVmessHTTPTemplate { public class InboundVmessHTTPTemplateClass {
public static InboundObject InboundTemplate; public static InboundObject InboundVmessHTTPTemplate;
public static final String ListenAddress = "0.0.0.0";
static { static {
InboundTemplate = new VMESS(); InboundVmessHTTPTemplate = new VMESS();
// 构建 settings- vmess-tcp-http的对象 // 构建 settings- vmess-tcp-http的对象
TcpObject tcpObject = new TcpObject(); TcpObject tcpObject = new TcpObject();
// 构建RequestHttp属性对象 // 构建RequestHttp属性对象
HttpHeaderObject httpHeaderObject = new HttpHeaderObject(); HttpHeaderObject httpHeaderObject = new HttpHeaderObject();
httpHeaderObject.setRequest(HttpRequestTemplate); // httpHeaderObject.setRequest(HttpRequestTemplate);
// 服务端接收VMESS才是用Response
httpHeaderObject.setResponse(HttpResponseTemplate); httpHeaderObject.setResponse(HttpResponseTemplate);
tcpObject.setHeader(httpHeaderObject); tcpObject.setHeader(httpHeaderObject);
@@ -30,7 +32,7 @@ public class InboundVmessHTTPTemplate {
// 设置 settings属性 // 设置 settings属性
StreamSettingsObject streamSettingsObject = new StreamSettingsObject(); StreamSettingsObject streamSettingsObject = new StreamSettingsObject();
streamSettingsObject.setTcpSettings(tcpObject); streamSettingsObject.setTcpSettings(tcpObject);
InboundTemplate.setStreamSettings(streamSettingsObject); InboundVmessHTTPTemplate.setStreamSettings(streamSettingsObject);
} }
} }

View File

@@ -0,0 +1,19 @@
package io.wdd.func.xray.beans.config;
import io.wdd.func.xray.beans.xray.LogObject;
public class LogTemplateClass {
public static LogObject LogTemplate;
static {
LogTemplate = new LogObject();
LogTemplate.setAccess("/var/log/xray/access.log");
LogTemplate.setError("/var/log/xray/error.log");
LogTemplate.setLoglevel("warning");
}
}

View File

@@ -1,34 +0,0 @@
package io.wdd.func.xray.beans.config;
import io.wdd.func.xray.beans.xray.protocol.outbound.OutboundConfigurationObject;
import io.wdd.func.xray.beans.xray.protocol.outbound.VMESS;
import io.wdd.func.xray.beans.xray.transport.HttpHeaderObject;
import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import io.wdd.func.xray.beans.xray.transport.TcpObject;
import static io.wdd.func.xray.beans.config.TcpHttpHeaderTemplate.HttpResponseTemplate;
/**
* outbound 不具备此形式
*/
@Deprecated
public class OutboundVmessHTTPTemplate {
static {
OutboundConfigurationObject OutboundTemplate = new VMESS();
// 构造TCP
TcpObject tcpObject = new TcpObject();
HttpHeaderObject httpHeaderObject = new HttpHeaderObject();
httpHeaderObject.setResponse(HttpResponseTemplate);
tcpObject.setHeader(httpHeaderObject);
}
}

View File

@@ -0,0 +1,47 @@
package io.wdd.func.xray.beans.config;
import io.wdd.func.xray.beans.xray.protocol.outbound.VMESS;
import io.wdd.func.xray.beans.xray.transport.*;
import static io.wdd.func.xray.beans.config.TcpHttpHeaderTemplate.HttpRequestTemplate;
public class OutboundVmessHTTPTemplateClass {
public static OutboundObject OutboundVmessHTTPTemplate;
public static OutboundObject OutboundFree;
public static OutboundObject OutboundBlackHole;
static {
OutboundVmessHTTPTemplate = new VMESS();
// 构造TCP
TcpObject tcpObject = new TcpObject();
HttpHeaderObject httpHeaderObject = new HttpHeaderObject();
httpHeaderObject.setRequest(HttpRequestTemplate);
tcpObject.setHeader(httpHeaderObject);
StreamSettingsObject streamSettingsObject = new StreamSettingsObject();
streamSettingsObject.setTcpSettings(tcpObject);
OutboundVmessHTTPTemplate.setStreamSettings(streamSettingsObject);
MuxObject muxObject = new MuxObject();
muxObject.setConcurrency(-1);
muxObject.setEnabled(Boolean.FALSE);
OutboundVmessHTTPTemplate.setMux(muxObject);
OutboundFree = new OutboundObject();
OutboundFree.setProtocol("free");
OutboundBlackHole = new OutboundObject();
OutboundBlackHole.setProtocol("blackhole");
OutboundBlackHole.setTag("block");
}
}

View File

@@ -1,8 +1,14 @@
package io.wdd.func.xray.beans.xray; package io.wdd.func.xray.beans.xray;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data @Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
public class Client { public class Client {
private String id; private String id;

View File

@@ -13,25 +13,6 @@ public class RoutingObject {
} }
@Data
class RuleObject {
private String type;
private List<String> domain;
private List<String> ip;
private String port;
private String sourcePort;
private String network;
private List<String> source;
private List<String> user;
private List<String> inboundTag;
private String protocol;
private String attrs;
private String outboundTag;
private String balancerTag;
}
@Data @Data
class BalancerObject { class BalancerObject {

View File

@@ -0,0 +1,30 @@
package io.wdd.func.xray.beans.xray;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.SuperBuilder;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
@AllArgsConstructor
@NotNull
@SuperBuilder(toBuilder = true)
public class RuleObject {
private String type;
private List<String> domain;
private List<String> ip;
private String port;
private String sourcePort;
private String network;
private List<String> source;
private List<String> user;
private List<String> inboundTag;
private String protocol;
private String attrs;
private String outboundTag;
private String balancerTag;
}

View File

@@ -4,12 +4,20 @@ package io.wdd.func.xray.beans.xray;
import io.wdd.func.xray.beans.xray.transport.InboundObject; import io.wdd.func.xray.beans.xray.transport.InboundObject;
import io.wdd.func.xray.beans.xray.transport.OutboundObject; import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import io.wdd.func.xray.beans.xray.transport.TransportObject; import io.wdd.func.xray.beans.xray.transport.TransportObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List; import java.util.List;
/** /**
* https://github.com/LarryZeta/xray-manager/blob/master/src/main/java/cc/larryzeta/manager/entity/XrayConfig.java * https://github.com/LarryZeta/xray-manager/blob/master/src/main/java/cc/larryzeta/manager/entity/XrayConfig.java
*/ */
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
public class XrayConfig { public class XrayConfig {
private LogObject log; private LogObject log;

View File

@@ -1,9 +1,15 @@
package io.wdd.func.xray.beans.xray.protocol.inbound.vmess; package io.wdd.func.xray.beans.xray.protocol.inbound.vmess;
import io.wdd.func.xray.beans.xray.Client; import io.wdd.func.xray.beans.xray.Client;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@Data @Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public class ClientObject extends Client { public class ClientObject extends Client {
private Integer level; private Integer level;

View File

@@ -0,0 +1,28 @@
package io.wdd.func.xray.beans.xray.protocol.inbound.vmess;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
public class InboundConfigurationObject {
private List<ClientObject> clients;
private DetourObject detour;
@JsonProperty("default")
private DefaultObject _default;
/**
* 是否禁止客户端使用不安全的加密方式当客户端指定下列加密方式时服务器会主动断开连接。默认值为false。
*/
boolean disableInsecureEncryption;
}

View File

@@ -5,6 +5,6 @@ import lombok.Data;
@Data @Data
public class VMESS extends InboundObject { public class VMESS extends InboundObject {
private VmessConfig settings; private InboundConfigurationObject settings;
} }

View File

@@ -1,16 +0,0 @@
package io.wdd.func.xray.beans.xray.protocol.inbound.vmess;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class VmessConfig {
private List<ClientObject> clients;
private DetourObject detour;
@JsonProperty("default")
private DefaultObject _default;
}

View File

@@ -1,6 +1,7 @@
package io.wdd.func.xray.beans.xray.protocol.outbound; package io.wdd.func.xray.beans.xray.protocol.outbound;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.ClientObject;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -21,7 +22,7 @@ public abstract class OutboundConfigurationObject {
@JsonProperty("port") @JsonProperty("port")
private Integer port; private Integer port;
@JsonProperty("users") @JsonProperty("users")
private List<UserObject> users; private List<ClientObject> users;
@NoArgsConstructor @NoArgsConstructor
@Data @Data

View File

@@ -4,7 +4,7 @@ import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import lombok.Data; import lombok.Data;
@Data @Data
public class VMESS extends OutboundConfigurationObject { public class VMESS extends OutboundObject {
} }

View File

@@ -0,0 +1,12 @@
package io.wdd.func.xray.beans.xray.transport;
import lombok.Data;
@Data
public
class MuxObject {
private Boolean enabled;
private Integer concurrency;
}

View File

@@ -31,10 +31,3 @@ class ProxySettingsObject {
private String tag; private String tag;
} }
@Data
class MuxObject {
private Boolean enabled;
private Integer concurrency;
}

View File

@@ -1,14 +1,25 @@
package io.wdd.func.xray.service; package io.wdd.func.xray.service;
import io.wdd.func.xray.beans.node.ProxyNode; import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.xray.RoutingObject;
import io.wdd.func.xray.beans.xray.RuleObject;
import io.wdd.func.xray.beans.xray.XrayConfig; import io.wdd.func.xray.beans.xray.XrayConfig;
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.ClientObject;
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.InboundConfigurationObject;
import io.wdd.func.xray.beans.xray.protocol.inbound.vmess.VMESS;
import io.wdd.func.xray.beans.xray.protocol.outbound.OutboundConfigurationObject;
import io.wdd.func.xray.beans.xray.transport.OutboundObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.lang.reflect.InvocationTargetException;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.InboundVmessHTTPTemplate;
import static io.wdd.func.xray.beans.config.InboundVmessHTTPTemplateClass.ListenAddress;
import static io.wdd.func.xray.beans.config.LogTemplateClass.LogTemplate;
import static io.wdd.func.xray.beans.config.OutboundVmessHTTPTemplateClass.*;
import static io.wdd.func.xray.beans.node.ProxyNodeSet.*; import static io.wdd.func.xray.beans.node.ProxyNodeSet.*;
@Service @Service
@@ -88,17 +99,193 @@ public class XrayCoreServiceImpl implements XrayCoreService {
private void generateXrayJsonSinglePath(ArrayList<ProxyNode> networkPathList, HashMap<String, String> interfaceMap, HashMap<ProxyNode, XrayConfig> resultMap) { private void generateXrayJsonSinglePath(ArrayList<ProxyNode> networkPathList, HashMap<String, String> interfaceMap, HashMap<ProxyNode, XrayConfig> resultMap) {
int pathLength = networkPathList.size(); int pathLength = networkPathList.size();
if (pathLength < 2) { if (pathLength == 1) {
log.error("网络路径节点不能小于2"); log.error("网络路径节点仅为一");
return; return;
} }
ArrayList<XrayConfig> tmpXrayConfigList = new ArrayList<>();
// 采用 VMESS + websocket的形式形成 链状代理 // 采用 VMESS + websocket的形式形成 链状代理
// 由于 Vlss+XTLS的形式形成 链状结构 // 由于 Vlss+XTLS的形式形成 链状结构
String tag = generatePathTag(networkPathList);
// 通用内容生成
String uuid = UUID
.randomUUID()
.toString();
ClientObject clientObject = ClientObject
.builder()
.id(uuid)
.level(0)
.alterId(23)
.email(tag + "@octopus.io")
.build();
for (int pos = 0; pos < pathLength; pos++) {
XrayConfig xrayConfig = new XrayConfig();
if (pos == pathLength - 1) {
// 最后一个节点,形式不一样
buildInbound(xrayConfig, clientObject);
// 设置FreeOut
buildOutboundFree(xrayConfig, tag);
// 设置 路由信息
buildRouting(xrayConfig, tag);
// 添加到临时缓存中
tmpXrayConfigList.add(xrayConfig);
return;
}
// 设置Log属性
xrayConfig.setLog(LogTemplate);
// 初始化 InBound
buildInbound(xrayConfig, clientObject);
// 设置 outbounds的信息
buildOutbound(xrayConfig, networkPathList, pos, clientObject);
// 设置 路由信息
buildRouting(xrayConfig, tag);
// 添加到临时缓存中
tmpXrayConfigList.add(xrayConfig);
// 调试
System.out.println("xrayConfig = " + xrayConfig);
}
}
private void buildOutboundFree(XrayConfig xrayConfig, String tag) {
OutboundObject freeOut = new OutboundObject();
freeOut.setProtocol("freedom");
freeOut.setTag(tag);
xrayConfig.setOutbounds(new ArrayList<>(
List.of(freeOut)
));
}
private void buildRouting(XrayConfig xrayConfig, String tag) {
RoutingObject routingObject = new RoutingObject();
routingObject.setDomainStrategy("IPIfNonMatch");
RuleObject ruleObject = RuleObject
.builder()
.type("field")
.inboundTag(List.of(tag))
.outboundTag(tag)
.build();
routingObject.setRules(
new ArrayList<>(
List.of(ruleObject)
)
);
xrayConfig.setRouting(routingObject);
}
private void buildOutbound(XrayConfig xrayConfig, ArrayList<ProxyNode> networkPathList, int pos, ClientObject clientObject) {
OutboundObject outboundObject = new OutboundObject();
try {
BeanUtils.copyProperties(outboundObject,
OutboundVmessHTTPTemplate
);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
// 设置出口信息
OutboundConfigurationObject.ServerObject serverObject = outboundObject
.getSettings()
.getVnext()
.get(0);
// 出口的IP应该为下一节点
serverObject.setAddress(networkPathList.get(pos+1).getPublicIPv4());
serverObject.setUsers(
List.of(clientObject)
);
xrayConfig.setOutbounds(
new ArrayList<>(
List.of(
outboundObject,
OutboundFree,
OutboundBlackHole
)
)
);
}
private void buildInbound(XrayConfig xrayConfig, ClientObject clientObject) {
VMESS inboundObject = new VMESS();
try {
BeanUtils.copyProperties(inboundObject,
InboundVmessHTTPTemplate
);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
// todo port怎么办
inboundObject.setPort(19999);
// 设置 listen地址
inboundObject.setListen(ListenAddress);
// 配置用户信息
InboundConfigurationObject inboundConfigurationObject = InboundConfigurationObject
.builder()
.clients(List.of(clientObject))
.build();
inboundObject.setSettings(inboundConfigurationObject);
xrayConfig.setInbounds(
new ArrayList<>(
List.of(
inboundObject
)
)
);
}
/**
* shanghai->seoul2->tokyo2
*
* @param networkPathList 网络路径节点
* @return 路径Tag
*/
private String generatePathTag(ArrayList<ProxyNode> networkPathList) {
StringBuilder sb = new StringBuilder();
networkPathList
.stream()
.forEach(
networkPath -> {
sb.append(networkPath.getName());
sb.append("->");
}
);
return sb.toString();
} }
} }