diff --git a/sub/default.json b/sub/default.json
index d98a03ef..3f8c86a6 100644
--- a/sub/default.json
+++ b/sub/default.json
@@ -74,7 +74,7 @@
}
},
"routing": {
- "domainStrategy": "AsIs",
+ "domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
diff --git a/sub/sub.go b/sub/sub.go
index 26dbcd2c..8fe025bc 100644
--- a/sub/sub.go
+++ b/sub/sub.go
@@ -92,9 +92,21 @@ func (s *Server) initRouter() (*gin.Engine, error) {
SubJsonFragment = ""
}
+ SubJsonMux, err := s.settingService.GetSubJsonMux()
+ if err != nil {
+ SubJsonMux = ""
+ }
+
+ SubJsonRules, err := s.settingService.GetSubJsonRules()
+ if err != nil {
+ SubJsonRules = ""
+ }
+
g := engine.Group("/")
- s.sub = NewSUBController(g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates, SubJsonFragment)
+ s.sub = NewSUBController(
+ g, LinksPath, JsonPath, Encrypt, ShowInfo, RemarkModel, SubUpdates,
+ SubJsonFragment, SubJsonMux, SubJsonRules)
return engine, nil
}
diff --git a/sub/subController.go b/sub/subController.go
index 58d638d7..325d4519 100644
--- a/sub/subController.go
+++ b/sub/subController.go
@@ -26,6 +26,8 @@ func NewSUBController(
rModel string,
update string,
jsonFragment string,
+ jsonMux string,
+ jsonRules string,
) *SUBController {
sub := NewSubService(showInfo, rModel)
a := &SUBController{
@@ -35,7 +37,7 @@ func NewSUBController(
updateInterval: update,
subService: sub,
- subJsonService: NewSubJsonService(jsonFragment, sub),
+ subJsonService: NewSubJsonService(jsonFragment, jsonMux, jsonRules, sub),
}
a.initRouter(g)
return a
diff --git a/sub/subJsonService.go b/sub/subJsonService.go
index d50e9644..0467e311 100644
--- a/sub/subJsonService.go
+++ b/sub/subJsonService.go
@@ -21,12 +21,13 @@ type SubJsonService struct {
configJson map[string]interface{}
defaultOutbounds []json_util.RawMessage
fragment string
+ mux string
inboundService service.InboundService
SubService *SubService
}
-func NewSubJsonService(fragment string, subService *SubService) *SubJsonService {
+func NewSubJsonService(fragment string, mux string, rules string, subService *SubService) *SubJsonService {
var configJson map[string]interface{}
var defaultOutbounds []json_util.RawMessage
json.Unmarshal([]byte(defaultJson), &configJson)
@@ -37,6 +38,17 @@ func NewSubJsonService(fragment string, subService *SubService) *SubJsonService
}
}
+ if rules != "" {
+ var newRules []interface{}
+ routing, _ := configJson["routing"].(map[string]interface{})
+ defaultRules, _ := routing["rules"].([]interface{})
+ json.Unmarshal([]byte(rules), &newRules)
+ defaultRules = append(newRules, defaultRules...)
+ fmt.Printf("routing: %#v\n\nRules: %#v\n\n", routing, defaultRules)
+ routing["rules"] = defaultRules
+ configJson["routing"] = routing
+ }
+
if fragment != "" {
defaultOutbounds = append(defaultOutbounds, json_util.RawMessage(fragment))
}
@@ -45,6 +57,7 @@ func NewSubJsonService(fragment string, subService *SubService) *SubJsonService
configJson: configJson,
defaultOutbounds: defaultOutbounds,
fragment: fragment,
+ mux: mux,
SubService: subService,
}
}
@@ -174,6 +187,7 @@ func (s *SubJsonService) getConfig(inbound *model.Inbound, client model.Client,
}
newConfigJson["outbounds"] = newOutbounds
newConfigJson["remarks"] = s.SubService.genRemark(inbound, client.Email, extPrxy["remark"].(string))
+
newConfig, _ := json.MarshalIndent(newConfigJson, "", " ")
newJsonArray = append(newJsonArray, newConfig)
}
@@ -277,6 +291,9 @@ func (s *SubJsonService) genVnext(inbound *model.Inbound, streamSettings json_ut
outbound.Protocol = string(inbound.Protocol)
outbound.Tag = "proxy"
+ if s.mux != "" {
+ outbound.Mux = json_util.RawMessage(s.mux)
+ }
outbound.StreamSettings = streamSettings
outbound.Settings = OutboundSettings{
Vnext: vnextData,
@@ -313,6 +330,9 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u
outbound.Protocol = string(inbound.Protocol)
outbound.Tag = "proxy"
+ if s.mux != "" {
+ outbound.Mux = json_util.RawMessage(s.mux)
+ }
outbound.StreamSettings = streamSettings
outbound.Settings = OutboundSettings{
Servers: serverData,
@@ -326,7 +346,7 @@ type Outbound struct {
Protocol string `json:"protocol"`
Tag string `json:"tag"`
StreamSettings json_util.RawMessage `json:"streamSettings"`
- Mux map[string]interface{} `json:"mux,omitempty"`
+ Mux json_util.RawMessage `json:"mux,omitempty"`
ProxySettings map[string]interface{} `json:"proxySettings,omitempty"`
Settings OutboundSettings `json:"settings,omitempty"`
}
diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js
index 286535d7..a60c0df6 100644
--- a/web/assets/js/model/setting.js
+++ b/web/assets/js/model/setting.js
@@ -31,9 +31,11 @@ class AllSetting {
this.subUpdates = 0;
this.subEncrypt = true;
this.subShowInfo = false;
- this.subURI = '';
- this.subJsonURI = '';
- this.subJsonFragment = '';
+ this.subURI = "";
+ this.subJsonURI = "";
+ this.subJsonFragment = "";
+ this.subJsonMux = "";
+ this.subJsonRules = "";
this.timeLocation = "Asia/Tehran";
diff --git a/web/entity/entity.go b/web/entity/entity.go
index 7b50341e..cb173394 100644
--- a/web/entity/entity.go
+++ b/web/entity/entity.go
@@ -50,6 +50,8 @@ type AllSetting struct {
SubJsonPath string `json:"subJsonPath" form:"subJsonPath"`
SubJsonURI string `json:"subJsonURI" form:"subJsonURI"`
SubJsonFragment string `json:"subJsonFragment" form:"subJsonFragment"`
+ SubJsonMux string `json:"subJsonMux" form:"subJsonMux"`
+ SubJsonRules string `json:"subJsonRules" form:"subJsonRules"`
}
func (s *AllSetting) CheckValid() error {
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index d887e401..85fe78d0 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -209,6 +209,8 @@
+
+
@@ -232,6 +234,36 @@
+
+
+
+
+
+
+
+
+
+
+
+ [[ p ]]
+
+
+
+
+
+
+
+
+
+
+
@@ -280,6 +312,40 @@
}
}
},
+ defaultMux: {
+ enabled: true,
+ concurrency: 8,
+ xudpConcurrency: 16,
+ xudpProxyUDP443: "reject"
+ },
+ defaultRules: [
+ {
+ type: "field",
+ outboundTag: "direct",
+ domain: [
+ "geosite:category-ir",
+ "geosite:cn"
+ ],
+ "enabled": true
+ },
+ {
+ type: "field",
+ outboundTag: "direct",
+ ip: [
+ "geoip:private",
+ "geoip:ir",
+ "geoip:cn"
+ ],
+ enabled: true
+ },
+ ],
+ countryOptions: [
+ { label: 'Private IP/Domain', value: 'private' },
+ { label: '🇮🇷 Iran', value: 'ir' },
+ { label: '🇨🇳 China', value: 'cn' },
+ { label: '🇷🇺 Russia', value: 'ru' },
+ { label: '🇻🇳 Vietnam', value: 'vn' },
+ ],
get remarkModel() {
rm = this.allSetting.remarkModel;
return rm.length>1 ? rm.substring(1).split('') : [];
@@ -397,6 +463,61 @@
}
}
},
+ enableMux: {
+ get: function() { return this.allSetting?.subJsonMux != ""; },
+ set: function (v) {
+ this.allSetting.subJsonMux = v ? JSON.stringify(this.defaultMux) : "";
+ }
+ },
+ muxConcurrency: {
+ get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).concurrency : -1; },
+ set: function(v) {
+ newMux = JSON.parse(this.allSetting.subJsonMux);
+ newMux.concurrency = v;
+ this.allSetting.subJsonMux = JSON.stringify(newMux);
+ }
+ },
+ muxXudpConcurrency: {
+ get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpConcurrency : -1; },
+ set: function(v) {
+ newMux = JSON.parse(this.allSetting.subJsonMux);
+ newMux.xudpConcurrency = v;
+ this.allSetting.subJsonMux = JSON.stringify(newMux);
+ }
+ },
+ muxXudpProxyUDP443: {
+ get: function() { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpProxyUDP443 : "reject"; },
+ set: function(v) {
+ newMux = JSON.parse(this.allSetting.subJsonMux);
+ newMux.xudpProxyUDP443 = v;
+ this.allSetting.subJsonMux = JSON.stringify(newMux);
+ }
+ },
+ enableDirect: {
+ get: function() { return this.allSetting?.subJsonRules != ""; },
+ set: function (v) {
+ this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : "";
+ }
+ },
+ directCountries: {
+ get: function() {
+ if (!this.enableDirect) return [];
+ rules = JSON.parse(this.allSetting.subJsonRules);
+ return Array.isArray(rules) ? rules[1].ip.map(d => d.replace("geoip:","")) : [];
+ },
+ set: function (v) {
+ rules = JSON.parse(this.allSetting.subJsonRules);
+ if (!Array.isArray(rules)) return;
+ rules[0].domain = [];
+ rules[1].ip = [];
+ v.forEach(d => {
+ category = ["cn","private"].includes(d) ? "" : "category-";
+ rules[0].domain.push("geosite:"+category+d);
+ rules[1].ip.push("geoip:"+d);
+ });
+ this.allSetting.subJsonRules = JSON.stringify(rules);
+ }
+ },
confAlerts: {
get: function() {
if (!this.allSetting) return [];
diff --git a/web/service/setting.go b/web/service/setting.go
index b7738194..43105411 100644
--- a/web/service/setting.go
+++ b/web/service/setting.go
@@ -59,6 +59,8 @@ var defaultValueMap = map[string]string{
"subJsonPath": "/json/",
"subJsonURI": "",
"subJsonFragment": "",
+ "subJsonMux": "",
+ "subJsonRules": "",
"warp": "",
}
@@ -403,6 +405,14 @@ func (s *SettingService) GetSubJsonFragment() (string, error) {
return s.getString("subJsonFragment")
}
+func (s *SettingService) GetSubJsonMux() (string, error) {
+ return s.getString("subJsonMux")
+}
+
+func (s *SettingService) GetSubJsonRules() (string, error) {
+ return s.getString("subJsonRules")
+}
+
func (s *SettingService) GetWarp() (string, error) {
return s.getString("warp")
}