adjustments for singbox 1.11.0

This commit is contained in:
Alireza Ahmadi
2025-01-06 15:49:43 +01:00
parent 2d8b56208d
commit d53d9b80f5
18 changed files with 347 additions and 139 deletions
+66 -3
View File
@@ -113,6 +113,11 @@ func moveJsonToDb(db *gorm.DB) error {
inbObj["out_json"] = json.RawMessage("{}") inbObj["out_json"] = json.RawMessage("{}")
inbObj["addrs"] = json.RawMessage("[]") inbObj["addrs"] = json.RawMessage("[]")
} }
// Delete deprecated fields
delete(inbObj, "sniff")
delete(inbObj, "sniff_override_destination")
delete(inbObj, "sniff_timeout")
delete(inbObj, "domain_strategy")
inbJson, _ := json.Marshal(inbObj) inbJson, _ := json.Marshal(inbObj)
var newInbound model.Inbound var newInbound model.Inbound
@@ -127,6 +132,9 @@ func moveJsonToDb(db *gorm.DB) error {
} }
delete(oldConfig, "inbounds") delete(oldConfig, "inbounds")
blockOutboundTags := []string{}
dnsOutboundTags := []string{}
oldOutbounds := oldConfig["outbounds"].([]interface{}) oldOutbounds := oldConfig["outbounds"].([]interface{})
db.Migrator().DropTable(&model.Outbound{}, &model.Endpoint{}) db.Migrator().DropTable(&model.Outbound{}, &model.Endpoint{})
db.AutoMigrate(&model.Outbound{}, &model.Endpoint{}) db.AutoMigrate(&model.Outbound{}, &model.Endpoint{})
@@ -149,14 +157,69 @@ func moveJsonToDb(db *gorm.DB) error {
if err != nil { if err != nil {
return err return err
} }
err = db.Create(&newOutbound).Error // Delete deprecated fields
if err != nil { if newOutbound.Type == "direct" {
return err var options map[string]interface{}
json.Unmarshal(newOutbound.Options, &options)
delete(options, "override_address")
delete(options, "override_port")
newOutbound.Options, _ = json.Marshal(options)
}
switch newOutbound.Type {
case "dns":
dnsOutboundTags = append(dnsOutboundTags, newOutbound.Tag)
case "block":
blockOutboundTags = append(blockOutboundTags, newOutbound.Tag)
default:
err = db.Create(&newOutbound).Error
if err != nil {
return err
}
} }
} }
} }
delete(oldConfig, "outbounds") delete(oldConfig, "outbounds")
// Check routing rules
if routingRules, ok := oldConfig["route"].(map[string]interface{}); ok {
if rules, hasRules := routingRules["rules"].([]interface{}); hasRules {
hasDns := false
for index, rule := range rules {
ruleObj, _ := rule.(map[string]interface{})
isBlock := false
isDns := false
outboundTag, _ := ruleObj["outbound"].(string)
for _, tag := range blockOutboundTags {
if tag == outboundTag {
isBlock = true
delete(ruleObj, "outbound")
ruleObj["action"] = "reject"
break
}
}
for _, tag := range dnsOutboundTags {
if tag == outboundTag {
isDns = true
hasDns = true
delete(ruleObj, "outbound")
ruleObj["action"] = "hijack-dns"
break
}
}
if !isBlock && !isDns {
ruleObj["action"] = "route"
}
rules[index] = ruleObj
}
if hasDns {
rules = append(rules, map[string]interface{}{"action": "sniff"})
}
routingRules["rules"] = rules
}
oldConfig["route"] = routingRules
}
// Remove v2rayapi and clashapi from experimental config // Remove v2rayapi and clashapi from experimental config
experimental := oldConfig["experimental"].(map[string]interface{}) experimental := oldConfig["experimental"].(map[string]interface{})
delete(experimental, "v2ray_api") delete(experimental, "v2ray_api")
-39
View File
@@ -29,24 +29,6 @@
v-model="inbound.detour"> v-model="inbound.detour">
</v-select> </v-select>
</v-col> </v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="inbound.sniff" color="primary" :label="$t('listen.sniffing')" hide-details></v-switch>
</v-col>
</v-row>
<v-row v-if="inbound.sniff">
<v-col cols="12" sm="6" md="4">
<v-switch v-model="inbound.sniff_override_destination" color="primary" :label="$t('listen.sniffingOverride')" hide-details></v-switch>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
:label="$t('listen.sniffingTimeout')"
hide-details
type="number"
min="50"
step="50"
:suffix="$t('date.ms')"
v-model.number="sniffTimeout"></v-text-field>
</v-col>
</v-row> </v-row>
<v-row v-if="optionTCP"> <v-row v-if="optionTCP">
<v-col cols="12" sm="6" md="4"> <v-col cols="12" sm="6" md="4">
@@ -70,16 +52,6 @@
v-model.number="udpTimeout"></v-text-field> v-model.number="udpTimeout"></v-text-field>
</v-col> </v-col>
</v-row> </v-row>
<v-row v-if="optionDS">
<v-col cols="12" sm="6" md="4">
<v-select
hide-details
:label="$t('listen.domainStrategy')"
:items="['prefer_ipv4','prefer_ipv6','ipv4_only','ipv6_only']"
v-model="inbound.domain_strategy">
</v-select>
</v-col>
</v-row>
<v-card-actions class="pt-0" v-if="inbound.type != 'tun'"> <v-card-actions class="pt-0" v-if="inbound.type != 'tun'">
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-menu v-model="menu" :close-on-content-click="false" location="start"> <v-menu v-model="menu" :close-on-content-click="false" location="start">
@@ -97,9 +69,6 @@
<v-list-item> <v-list-item>
<v-switch v-model="optionUDP" color="primary" :label="$t('listen.udpOptions')" hide-details></v-switch> <v-switch v-model="optionUDP" color="primary" :label="$t('listen.udpOptions')" hide-details></v-switch>
</v-list-item> </v-list-item>
<v-list-item>
<v-switch v-model="optionDS" color="primary" :label="$t('listen.domainStrategy')" hide-details></v-switch>
</v-list-item>
</v-list> </v-list>
</v-card> </v-card>
</v-menu> </v-menu>
@@ -120,10 +89,6 @@ export default {
get() { return this.$props.inbound.udp_timeout ? parseInt(this.$props.inbound.udp_timeout.replace('m','')) : 5 }, get() { return this.$props.inbound.udp_timeout ? parseInt(this.$props.inbound.udp_timeout.replace('m','')) : 5 },
set(newValue:number) { this.$props.inbound.udp_timeout = newValue > 0 ? newValue + 'm' : '5m' } set(newValue:number) { this.$props.inbound.udp_timeout = newValue > 0 ? newValue + 'm' : '5m' }
}, },
sniffTimeout: {
get() { return this.$props.inbound.sniff_timeout ? parseInt(this.$props.inbound.sniff_timeout.replace('ms','')) : 300 },
set(newValue:number) { this.$props.inbound.sniff_timeout = newValue > 0 ? newValue + 'ms' : '300ms' }
},
optionTCP: { optionTCP: {
get(): boolean { get(): boolean {
return this.$props.inbound.tcp_fast_open != undefined && return this.$props.inbound.tcp_fast_open != undefined &&
@@ -147,10 +112,6 @@ export default {
optionDetour: { optionDetour: {
get(): boolean { return this.$props.inbound.detour != undefined }, get(): boolean { return this.$props.inbound.detour != undefined },
set(v:boolean) { this.$props.inbound.detour = v ? this.inTags[0]?? '' : undefined } set(v:boolean) { this.$props.inbound.detour = v ? this.inTags[0]?? '' : undefined }
},
optionDS: {
get(): boolean { return this.$props.inbound.domain_strategy != undefined },
set(v:boolean) { this.$props.inbound.domain_strategy = v ? 'prefer_ipv4' : undefined }
} }
} }
} }
+2 -2
View File
@@ -1,7 +1,7 @@
<template> <template>
<v-card subtitle="Direct"> <v-card subtitle="Direct">
<v-row> <v-row>
<v-col cols="12" sm="6" md="4" v-if="direction == 'in'"> <v-col cols="12" sm="6" md="4">
<Network :data="data" /> <Network :data="data" />
</v-col> </v-col>
<v-col cols="12" sm="6" md="4"> <v-col cols="12" sm="6" md="4">
@@ -28,7 +28,7 @@
import Network from '@/components/Network.vue' import Network from '@/components/Network.vue'
export default { export default {
props: ['direction','data'], props: ['data'],
data() { data() {
return {} return {}
}, },
-5
View File
@@ -252,11 +252,6 @@ export default {
], ],
fingerprints: [ fingerprints: [
{ title: "Chrome", value: "chrome" }, { title: "Chrome", value: "chrome" },
{ title: "Chrome PSK", value: "chrome_psk" },
{ title: "Chrome PSK Shuffle", value: "chrome_psk_shuffle" },
{ title: "Chrome Padding PSK Shuffle", value: "chrome_padding_psk_shuffle" },
{ title: "Chrome Post-Quantum", value: "chrome_pq" },
{ title: "Chrome Post-Quantum PSK", value: "chrome_pq_psk" },
{ title: "Firefox", value: "firefox" }, { title: "Firefox", value: "firefox" },
{ title: "Microsoft Edge", value: "edge" }, { title: "Microsoft Edge", value: "edge" },
{ title: "Apple Safari", value: "safari" }, { title: "Apple Safari", value: "safari" },
+2 -3
View File
@@ -70,15 +70,14 @@
</v-row> </v-row>
<v-row> <v-row>
<v-col> <v-col>
<v-combobox <v-select
v-model="clientInbounds" v-model="clientInbounds"
:items="inboundTags" :items="inboundTags"
:label="$t('client.inboundTags')" :label="$t('client.inboundTags')"
:return-object="false"
multiple multiple
chips chips
hide-details hide-details
></v-combobox> ></v-select>
</v-col> </v-col>
</v-row> </v-row>
</v-window-item> </v-window-item>
+1 -1
View File
@@ -40,7 +40,7 @@
<v-window v-model="side" style="margin-top: 10px;"> <v-window v-model="side" style="margin-top: 10px;">
<v-window-item value="s"> <v-window-item value="s">
<Listen :inbound="inbound" :inTags="inTags" /> <Listen :inbound="inbound" :inTags="inTags" />
<Direct v-if="inbound.type == inTypes.Direct" direction="in" :data="inbound" /> <Direct v-if="inbound.type == inTypes.Direct" :data="inbound" />
<Shadowsocks v-if="inbound.type == inTypes.Shadowsocks" direction="in" :data="inbound" /> <Shadowsocks v-if="inbound.type == inTypes.Shadowsocks" direction="in" :data="inbound" />
<Hysteria v-if="inbound.type == inTypes.Hysteria" direction="in" :data="inbound" /> <Hysteria v-if="inbound.type == inTypes.Hysteria" direction="in" :data="inbound" />
<Hysteria2 v-if="inbound.type == inTypes.Hysteria2" direction="in" :data="inbound" /> <Hysteria2 v-if="inbound.type == inTypes.Hysteria2" direction="in" :data="inbound" />
+2 -3
View File
@@ -48,7 +48,6 @@
</v-text-field> </v-text-field>
</v-col> </v-col>
</v-row> </v-row>
<Direct v-if="outbound.type == outTypes.Direct" direction="out" :data="outbound" />
<Socks v-if="outbound.type == outTypes.SOCKS" :data="outbound" /> <Socks v-if="outbound.type == outTypes.SOCKS" :data="outbound" />
<Http v-if="outbound.type == outTypes.HTTP" :data="outbound" /> <Http v-if="outbound.type == outTypes.HTTP" :data="outbound" />
<Shadowsocks v-if="outbound.type == outTypes.Shadowsocks" direction="out" :data="outbound" /> <Shadowsocks v-if="outbound.type == outTypes.Shadowsocks" direction="out" :data="outbound" />
@@ -139,8 +138,8 @@ export default {
link: "", link: "",
loading: false, loading: false,
outTypes: OutTypes, outTypes: OutTypes,
NoDial: [OutTypes.Block, OutTypes.DNS, OutTypes.Selector, OutTypes.URLTest], NoDial: [OutTypes.Selector, OutTypes.URLTest],
NoServer: [OutTypes.Direct, OutTypes.Block, OutTypes.DNS, OutTypes.Selector, OutTypes.URLTest, OutTypes.Tor], NoServer: [OutTypes.Direct, OutTypes.Selector, OutTypes.URLTest, OutTypes.Tor],
} }
}, },
methods: { methods: {
+177 -25
View File
@@ -12,7 +12,7 @@
</v-col> </v-col>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-col cols="auto" v-if="logical" justify="center" align="center"> <v-col cols="auto" v-if="logical" justify="center" align="center">
<v-btn color="primary" @click="ruleData.rules.push({})" hide-details>{{ $t('actions.add') + " " + $t('objects.rule') }}</v-btn> <v-btn color="primary" @click="ruleData.rules.push(<rule>{})" hide-details>{{ $t('actions.add') + " " + $t('objects.rule') }}</v-btn>
</v-col> </v-col>
</v-row> </v-row>
<v-card style="background-color: inherit; margin-bottom: 5px;" v-for="(r, index) in ruleData.rules" v-if="ruleData.type == 'logical'"> <v-card style="background-color: inherit; margin-bottom: 5px;" v-for="(r, index) in ruleData.rules" v-if="ruleData.type == 'logical'">
@@ -35,12 +35,12 @@
:rsTags="rsTags" /> :rsTags="rsTags" />
<v-row> <v-row>
<v-col cols="12" sm="6" md="4"> <v-col cols="12" sm="6" md="4">
<v-combobox <v-select
v-model="ruleData.outbound" v-model="ruleData.action"
:items="outTags" :items="actions"
:label="$t('objects.outbound')" :label="$t('admin.action')"
hide-details hide-details
></v-combobox> ></v-select>
</v-col> </v-col>
<v-col cols="12" sm="6" md="4" v-if="logical"> <v-col cols="12" sm="6" md="4" v-if="logical">
<v-combobox <v-combobox
@@ -54,6 +54,95 @@
<v-switch color="primary" v-model="ruleData.invert" :label="$t('rule.invert')" hide-details></v-switch> <v-switch color="primary" v-model="ruleData.invert" :label="$t('rule.invert')" hide-details></v-switch>
</v-col> </v-col>
</v-row> </v-row>
<v-card subtitle="Route" v-if="ruleData.action == 'route'">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
v-model="ruleData.outbound"
:items="outTags"
:label="$t('objects.outbound')"
hide-details
></v-select>
</v-col>
</v-row>
</v-card>
<v-card subtitle="Route Option" v-if="ruleData.action == 'route-options'">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="ruleData.override_address" :label="$t('types.direct.overrideAddr')" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
v-model.number="ruleData.override_port"
type="number"
min="0"
max="65534"
:label="$t('types.direct.overridePort')"
hide-details>
</v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="ruleData.udp_disable_domain_unmapping" :label="$t('rule.udpDisableDomainUnmapping')" hide-details></v-switch>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="ruleData.udp_connect" :label="$t('rule.udpConnect')" hide-details></v-switch>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="ruleData.udp_timeout" :label="$t('rule.udpTimeout')" hide-details></v-text-field>
</v-col>
</v-row>
</v-card>
<v-card subtitle="Reject" v-if="ruleData.action == 'reject'">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
v-model="ruleData.method"
:items="[{ title: 'Default', value: 'default' },{ title: 'Drop', value: 'drop'}]"
:label="$t('rule.method')"
clearable
@click:clear="delete ruleData.method"
hide-details>
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-switch v-model="ruleData.no_drop" :label="$t('rule.noDrop')" hide-details></v-switch>
</v-col>
</v-row>
</v-card>
<v-card subtitle="Sniff" v-if="ruleData.action == 'sniff'">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
v-model="ruleData.sniff"
:items="sniffers"
:label="$t('rule.sniffer')"
multiple
chips
hide-details>
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="ruleData.timeout" :label="$t('rule.timeout')" hide-details></v-text-field>
</v-col>
</v-row>
</v-card>
<v-card subtitle="Resolve" v-if="ruleData.action == 'resolve'">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-select
v-model="ruleData.strategy"
:items="strategies"
:label="$t('rule.strategy')"
clearable
@click:clear="delete ruleData.strategy"
hide-details>
</v-select>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model="ruleData.server" :label="$t('basic.dns.server')" hide-details></v-text-field>
</v-col>
</v-row>
</v-card>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
@@ -78,8 +167,9 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { logicalRule, rule } from '@/types/rules' import { logicalRule, rule, actionKeys } from '@/types/rules'
import RuleOptions from '@/components/Rule.vue' import RuleOptions from '@/components/Rule.vue'
import { title } from 'process';
export default { export default {
props: ['visible', 'data', 'index', 'clients', 'inTags', 'outTags', 'rsTags'], props: ['visible', 'data', 'index', 'clients', 'inTags', 'outTags', 'rsTags'],
emits: ['close', 'save'], emits: ['close', 'save'],
@@ -87,13 +177,39 @@ export default {
return { return {
title: 'add', title: 'add',
loading: false, loading: false,
ruleData: <logicalRule>{ ruleData: <any>{
type: 'logical', type: 'logical',
mode: 'and', mode: 'and',
rules: <rule[]>[{}], rules: <rule[]>[{}],
invert: false, invert: false,
action: 'route',
outbound: 'direct', outbound: 'direct',
} },
actions: [
{ title: 'Route', value: 'route'},
{ title: 'Route Options', value: 'route-options'},
{ title: 'Reject', value: 'reject'},
{ title: 'Hijack DNS', value: 'hijack-dns'},
{ title: 'Sniff', value: 'sniff'},
{ title: 'Resolve', value: 'resolve'}
],
sniffers: [
{ title: 'HTTP', value: 'http' },
{ title: 'TLS', value: 'tls' },
{ title: 'QUIC', value: 'quic' },
{ title: 'STUN', value: 'stun' },
{ title: 'DNS', value: 'dns' },
{ title: 'BitTorrent', value: 'bittorrent' },
{ title: 'DTLS', value: 'dtls' },
{ title: 'SSH', value: 'ssh' },
{ title: 'RDP', value: 'rdp' },
],
strategies: [
{ title: 'Prefer IPv4', value: 'prefer_ipv4' },
{ title: 'Prefer IPv6', value: 'prefer_ipv6' },
{ title: 'IPv4 Only', value: 'ipv4_only' },
{ title: 'IPv6 Only', value: 'ipv6_only' },
]
} }
}, },
methods: { methods: {
@@ -103,13 +219,18 @@ export default {
if (newData.type) { if (newData.type) {
this.ruleData = newData this.ruleData = newData
} else { } else {
this.ruleData = <logicalRule>{ this.ruleData = {
type: 'simple', type: 'simple',
mode: 'and', mode: 'and',
rules: <rule[]>[{...newData}], rules: <rule[]>[{}],
invert: newData.invert,
outbound: newData.outbound,
} }
Object.keys(newData).forEach(key => {
if (actionKeys.includes(key)) {
this.ruleData[key] = newData[key]
} else {
this.ruleData.rules[0][key] = newData[key]
}
})
} }
this.title = 'edit' this.title = 'edit'
} }
@@ -119,6 +240,7 @@ export default {
mode: 'and', mode: 'and',
rules: <rule[]>[{}], rules: <rule[]>[{}],
invert: false, invert: false,
action: 'route',
outbound: this.$props.outTags[0]?? 'direct', outbound: this.$props.outTags[0]?? 'direct',
} }
this.title = 'add' this.title = 'add'
@@ -130,11 +252,48 @@ export default {
}, },
saveChanges() { saveChanges() {
this.loading = true this.loading = true
if (this.ruleData.type == 'simple'){ let newRule = <any>{
this.ruleData.rules[0].outbound = this.ruleData.outbound action: this.ruleData.action,
this.ruleData.rules[0].invert = this.ruleData.invert invert: this.ruleData.invert,
} }
this.$emit('save', this.ruleData)
// Filter action data
switch (newRule.action){
case 'route':
newRule.outbound = this.ruleData.outbound
break
case 'route-options':
newRule.override_address = this.ruleData.override_address.length > 0 ? this.ruleData.override_address : undefined
newRule.override_port = this.ruleData.override_port > 0 ? this.ruleData.override_port : undefined
newRule.network_strategy = this.ruleData.network_strategy.length > 0 ? this.ruleData.network_strategy : undefined
newRule.fallback_delay = this.ruleData.fallback_delay.length > 0 ? this.ruleData.fallback_delay : undefined
newRule.udp_disable_domain_unmapping = this.ruleData.udp_disable_domain_unmapping? true : undefined
newRule.udp_connect = this.ruleData.udp_connect? true : undefined
newRule.udp_timeout = this.ruleData.udp_timeout.length > 0 ? this.ruleData.udp_timeout : undefined
break
case 'reject':
newRule.method = this.ruleData.method.length > 0 ? this.ruleData.method : undefined
newRule.no_drop = this.ruleData.no_drop? true : undefined
break
case 'sniff':
newRule.sniffer = this.ruleData.sniffer.length > 0 ? this.ruleData.sniffer : undefined
newRule.timeout = this.ruleData.timeout.length > 0 ? this.ruleData.timeout : undefined
break
case 'resolve':
newRule.strategy = this.ruleData.strategy.length > 0 ? this.ruleData.strategy : undefined
newRule.server = this.ruleData.server.length > 0 ? this.ruleData.server : undefined
break
}
// Add rules
if (this.ruleData.type == 'simple'){
newRule = { ...this.ruleData.rules[0], ...newRule }
} else {
newRule.type = 'logical'
newRule.mode = this.ruleData.mode
newRule.rules = this.ruleData.rules
}
this.$emit('save', newRule)
this.loading = false this.loading = false
}, },
deleteRule(index:number) { deleteRule(index:number) {
@@ -145,14 +304,7 @@ export default {
logical: { logical: {
get() { return this.ruleData.type == 'logical' }, get() { return this.ruleData.type == 'logical' },
set(v:boolean) { set(v:boolean) {
if (v) { this.ruleData.type = v? 'logical' : 'simple'
this.ruleData.type = 'logical'
this.ruleData.outbound = this.ruleData.rules[0].outbound?? this.$props.outTags[0]
delete this.ruleData.rules[0].outbound
} else {
this.ruleData.type = 'simple'
this.ruleData.rules[0].outbound = this.ruleData.outbound
}
} }
} }
}, },
+8 -4
View File
@@ -88,7 +88,6 @@ export default {
tls: "TLS", tls: "TLS",
multiplex: "Multiplex", multiplex: "Multiplex",
transport: "Transport", transport: "Transport",
method: "Method",
headers: "Headers", headers: "Headers",
key: "Key", key: "Key",
value: "Value", value: "Value",
@@ -260,9 +259,6 @@ export default {
mdOption: "Multi Domain Options", mdOption: "Multi Domain Options",
}, },
listen: { listen: {
sniffing: "Sniffing",
sniffingTimeout: "Sniffing Timeout",
sniffingOverride: "Override Destation",
options: "Listen Options", options: "Listen Options",
tcpOptions: "TCP Options", tcpOptions: "TCP Options",
udpOptions: "UDP Options", udpOptions: "UDP Options",
@@ -328,6 +324,14 @@ export default {
domainRules: "Domain/IP", domainRules: "Domain/IP",
srcIpRules: "Source IP", srcIpRules: "Source IP",
srcPortRules: "Source Port", srcPortRules: "Source Port",
udpDisableDomainUnmapping: "UDP Disable Domain Unmapping",
udpConnect: "UDP Connect",
udpTimeout: "UDP Timeout",
method: "Method",
noDrop: "No Drop",
sniffer: "Sniffer",
timeout: "Timeout",
strategy: "Strategy",
}, },
ruleset: { ruleset: {
add: "Add Ruleset", add: "Add Ruleset",
+8 -3
View File
@@ -259,9 +259,6 @@ export default {
mdOption: "گزینه‌های دامنه چندگانه", mdOption: "گزینه‌های دامنه چندگانه",
}, },
listen: { listen: {
sniffing: "شنود آدرس",
sniffingTimeout: "مهلت شنود آدرس",
sniffingOverride: "جایگزینی مقصد",
options: "گزینه‌های گوش‌دادن", options: "گزینه‌های گوش‌دادن",
tcpOptions: "گزینه‌های TCP", tcpOptions: "گزینه‌های TCP",
udpOptions: "گزینه‌های UDP", udpOptions: "گزینه‌های UDP",
@@ -327,6 +324,14 @@ export default {
domainRules: "دامنه/آدرس", domainRules: "دامنه/آدرس",
srcIpRules: "آدرس مبدا", srcIpRules: "آدرس مبدا",
srcPortRules: "پورت مبدا", srcPortRules: "پورت مبدا",
udpDisableDomainUnmapping: "عدم تبدیل مسیریابی دامنه",
udpConnect: "اتصال UDP",
udpTimeout: "مهلت UDP",
method: "روش",
noDrop: "عدم رهاکردن",
sniffer: "شنود کننده",
timeout: "مهلت",
strategy: "استراتژی",
}, },
ruleset: { ruleset: {
add: "ایجاد مجموعه", add: "ایجاد مجموعه",
+8 -4
View File
@@ -88,7 +88,6 @@ export default {
tls: "TLS", tls: "TLS",
multiplex: "Мультиплекс", multiplex: "Мультиплекс",
transport: "Транспорт", transport: "Транспорт",
method: "Метод",
headers: "Заголовки", headers: "Заголовки",
key: "Ключ", key: "Ключ",
value: "Значение", value: "Значение",
@@ -260,9 +259,6 @@ export default {
mdOption: "Параметры мультидомена", mdOption: "Параметры мультидомена",
}, },
listen: { listen: {
sniffing: "Обнаружение",
sniffingTimeout: "Таймаут обнаружения",
sniffingOverride: "Переопределение назначения",
options: "Параметры прослушивания", options: "Параметры прослушивания",
tcpOptions: "Параметры TCP", tcpOptions: "Параметры TCP",
udpOptions: "Параметры UDP", udpOptions: "Параметры UDP",
@@ -328,6 +324,14 @@ export default {
domainRules: "Домен/IP", domainRules: "Домен/IP",
srcIpRules: "Источник IP", srcIpRules: "Источник IP",
srcPortRules: "Источник порта", srcPortRules: "Источник порта",
udpDisableDomainUnmapping: "Отключить перенос доменных имен",
udpConnect: "Подключение UDP",
udpTimeout: "Таймаут UDP",
method: "Метод",
noDrop: "Не сбрасывать",
sniffer: "Обнаружение",
timeout: "Таймаут",
strategy: "Стратегия",
}, },
ruleset: { ruleset: {
add: "Добавить набор правил", add: "Добавить набор правил",
+9 -5
View File
@@ -86,7 +86,6 @@ export default {
tls: "TLS", tls: "TLS",
multiplex: "Ghép đa truyền thông ", multiplex: "Ghép đa truyền thông ",
transport: "Giao thông", transport: "Giao thông",
method: "Phương pháp",
headers: "Tiêu đề", headers: "Tiêu đề",
key: "Chìa khóa", key: "Chìa khóa",
value: "Giá trị", value: "Giá trị",
@@ -249,7 +248,6 @@ export default {
in: { in: {
addr: "Địa chỉ", addr: "Địa chỉ",
port: "Cổng", port: "Cổng",
sniffing: "Đang Sniffing",
clients: "Kích hoạt khách hàng", clients: "Kích hoạt khách hàng",
ssMethod: "Phương thức", ssMethod: "Phương thức",
sSide: "Phía Máy chủ", sSide: "Phía Máy chủ",
@@ -259,9 +257,6 @@ export default {
mdOption: "Tùy chọn Nhiều Tên miền", mdOption: "Tùy chọn Nhiều Tên miền",
}, },
listen: { listen: {
sniffing: "Đang Sniffing",
sniffingTimeout: "Thời gian Chờ Sniffing",
sniffingOverride: "Ghi đè Đích",
options: "Tùy chọn Nghe", options: "Tùy chọn Nghe",
tcpOptions: "Tùy chọn TCP", tcpOptions: "Tùy chọn TCP",
udpOptions: "Tùy chọn UDP", udpOptions: "Tùy chọn UDP",
@@ -327,6 +322,15 @@ export default {
domainRules: "Tên miền/IP", domainRules: "Tên miền/IP",
srcIpRules: "IP Nguồn", srcIpRules: "IP Nguồn",
srcPortRules: "Cổng Nguồn", srcPortRules: "Cổng Nguồn",
udpDisableDomainUnmapping: "Không màm mạng tiền lập tên miền",
udpFallbackDelay: "Thời gian Chờ Fallback",
udpConnect: "Kết nối UDP",
udpTimeout: "Thời gian Chờ UDP",
method: "Phương pháp",
noDrop: "Không Tháp",
sniffer: "Kiểm tra Sniffer",
timeout: "Thời gian Chờ Sniffing",
strategy: "Chiến lệ",
}, },
ruleset: { ruleset: {
add: "Thêm Bộ quy tắc", add: "Thêm Bộ quy tắc",
+8 -5
View File
@@ -86,7 +86,6 @@ export default {
tls: "TLS", tls: "TLS",
multiplex: "多路复用", multiplex: "多路复用",
transport: "传输", transport: "传输",
method: "方法",
headers: "标头", headers: "标头",
key: "键", key: "键",
value: "值", value: "值",
@@ -249,7 +248,6 @@ export default {
in: { in: {
addr: "地址", addr: "地址",
port: "端口", port: "端口",
sniffing: "嗅探",
clients: "启用客户端", clients: "启用客户端",
ssMethod: "方法", ssMethod: "方法",
sSide: "服务器端", sSide: "服务器端",
@@ -259,9 +257,6 @@ export default {
mdOption: "多域名选项", mdOption: "多域名选项",
}, },
listen: { listen: {
sniffing: "嗅探",
sniffingTimeout: "嗅探超时",
sniffingOverride: "覆盖目标地址",
options: "监听选项", options: "监听选项",
tcpOptions: "TCP 选项", tcpOptions: "TCP 选项",
udpOptions: "UDP 选项", udpOptions: "UDP 选项",
@@ -327,6 +322,14 @@ export default {
domainRules: "域名/IP", domainRules: "域名/IP",
srcIpRules: "源 IP", srcIpRules: "源 IP",
srcPortRules: "源端口", srcPortRules: "源端口",
udpDisableDomainUnmapping: "禁用域名解析映射",
udpConnect: "启用 UDP 连接",
udpTimeout: "UDP 超时",
method: "方法",
noDrop: "不丢弃",
sniffer: "嗅探",
timeout: "超时",
strategy: "策略",
}, },
ruleset: { ruleset: {
add: "添加规则集", add: "添加规则集",
+8 -5
View File
@@ -87,7 +87,6 @@ export default {
tls: "TLS", tls: "TLS",
multiplex: "多路復用", multiplex: "多路復用",
transport: "傳輸", transport: "傳輸",
method: "方法",
headers: "方法", headers: "方法",
key: "鑰匙", key: "鑰匙",
value: "價值", value: "價值",
@@ -250,7 +249,6 @@ export default {
in: { in: {
addr: "地址", addr: "地址",
port: "端口", port: "端口",
sniffing: "嗅探",
clients: "啟用客戶端", clients: "啟用客戶端",
ssMethod: "方法", ssMethod: "方法",
sSide: "服務器端", sSide: "服務器端",
@@ -260,9 +258,6 @@ export default {
mdOption: "多域名選項", mdOption: "多域名選項",
}, },
listen: { listen: {
sniffing: "嗅探",
sniffingTimeout: "嗅探超時",
sniffingOverride: "覆蓋目的地",
options: "監聽選項", options: "監聽選項",
tcpOptions: "TCP 選項", tcpOptions: "TCP 選項",
udpOptions: "UDP 選項", udpOptions: "UDP 選項",
@@ -328,6 +323,14 @@ export default {
domainRules: "域名/IP", domainRules: "域名/IP",
srcIpRules: "源 IP", srcIpRules: "源 IP",
srcPortRules: "源端口", srcPortRules: "源端口",
udpDisableDomainUnmapping: "禁用域名解析映射",
udpConnect: "啟用 UDP 連接",
udpTimeout: "UDP 超時",
method: "方法",
noDrop: "不丟弃",
sniffer: "嗅探",
timeout: "超時",
strategy: "策略",
}, },
ruleset: { ruleset: {
add: "添加規則集", add: "添加規則集",
-5
View File
@@ -41,10 +41,6 @@ export interface Listen {
udp_fragment?: boolean udp_fragment?: boolean
udp_timeout?: string udp_timeout?: string
detour?: string detour?: string
sniff?: boolean
sniff_override_destination?: boolean
sniff_timeout?: string
domain_strategy?: string
} }
interface InboundBasics extends Listen { interface InboundBasics extends Listen {
@@ -180,7 +176,6 @@ export interface Tun extends InboundBasics {
udp_timeout?: string udp_timeout?: string
stack?: string stack?: string
auto_route?: boolean auto_route?: boolean
// gso?: boolean
// strict_route?: boolean // strict_route?: boolean
// iproute2_table_index?: number // iproute2_table_index?: number
// iproute2_rule_index?: number // iproute2_rule_index?: number
+1 -12
View File
@@ -4,7 +4,6 @@ import { Transport } from "./transport"
export const OutTypes = { export const OutTypes = {
Direct: 'direct', Direct: 'direct',
Block: 'block',
SOCKS: 'socks', SOCKS: 'socks',
HTTP: 'http', HTTP: 'http',
Shadowsocks: 'shadowsocks', Shadowsocks: 'shadowsocks',
@@ -17,7 +16,6 @@ export const OutTypes = {
Hysteria2: 'hysteria2', Hysteria2: 'hysteria2',
Tor: 'tor', Tor: 'tor',
SSH: 'ssh', SSH: 'ssh',
DNS: 'dns',
Selector: 'selector', Selector: 'selector',
URLTest: 'urltest', URLTest: 'urltest',
} }
@@ -54,12 +52,7 @@ export interface WgPeer {
reserved?: number[] reserved?: number[]
} }
export interface Direct extends OutboundBasics, Dial { export interface Direct extends OutboundBasics, Dial {}
override_address?: string
override_port?: number
}
export interface Block extends OutboundBasics {}
export interface SOCKS extends OutboundBasics, Dial { export interface SOCKS extends OutboundBasics, Dial {
server: string server: string
@@ -209,8 +202,6 @@ export interface SSH extends OutboundBasics, Dial {
client_version?: string client_version?: string
} }
export interface DNS extends OutboundBasics {}
export interface Selector extends OutboundBasics { export interface Selector extends OutboundBasics {
outbounds: string[] outbounds: string[]
url?: string url?: string
@@ -240,7 +231,6 @@ export type Outbound = InterfaceMap[keyof InterfaceMap]
// Create defaultValues object dynamically // Create defaultValues object dynamically
const defaultValues: Record<OutType, Outbound> = { const defaultValues: Record<OutType, Outbound> = {
direct: { type: OutTypes.Direct }, direct: { type: OutTypes.Direct },
block: { type: OutTypes.Block },
socks: { type: OutTypes.SOCKS, version: "5" }, socks: { type: OutTypes.SOCKS, version: "5" },
http: { type: OutTypes.HTTP, tls: {} }, http: { type: OutTypes.HTTP, tls: {} },
shadowsocks: { type: OutTypes.Shadowsocks, method: 'none', multiplex: {} }, shadowsocks: { type: OutTypes.Shadowsocks, method: 'none', multiplex: {} },
@@ -253,7 +243,6 @@ const defaultValues: Record<OutType, Outbound> = {
hysteria2: { type: OutTypes.Hysteria2, tls: { enabled: true } }, hysteria2: { type: OutTypes.Hysteria2, tls: { enabled: true } },
tor: { type: OutTypes.Tor, executable_path: './tor', data_directory: '$HOME/.cache/tor', torrc: { ClientOnly: 1 } }, tor: { type: OutTypes.Tor, executable_path: './tor', data_directory: '$HOME/.cache/tor', torrc: { ClientOnly: 1 } },
ssh: { type: OutTypes.SSH }, ssh: { type: OutTypes.SSH },
dns: { type: OutTypes.DNS },
selector: { type: OutTypes.Selector }, selector: { type: OutTypes.Selector },
urltest: { type: OutTypes.URLTest }, urltest: { type: OutTypes.URLTest },
} }
+35 -6
View File
@@ -1,12 +1,43 @@
export interface logicalRule { interface generalRule {
invert: boolean
action: 'route' | 'route-options' | 'reject' | 'hijack-dns' | 'sniff' | 'resolve'
outbound?: string
override_address?: string
override_port?: number
udp_disable_domain_unmapping?: boolean
udp_connect?: boolean
udp_timeout?: string
method?: string
no_drop?: boolean
sniffer: string[]
timeout: string
strategy: string
server: string
}
export const actionKeys = [
'invert',
'action',
'outbound',
'override_address',
'override_port',
'udp_disable_domain_unmapping',
'udp_connect',
'udp_timeout',
'method',
'no_drop',
'sniffer',
'timeout',
'strategy',
'server'
]
export interface logicalRule extends generalRule {
type: 'logical' | 'simple' type: 'logical' | 'simple'
mode: 'and' | 'or' mode: 'and' | 'or'
rules: rule[] rules: rule[]
invert: boolean
outbound: string
} }
export interface rule { export interface rule extends generalRule {
inbound?: string[] inbound?: string[]
ip_version?: 4 | 6 ip_version?: 4 | 6
network?: string[] network?: string[]
@@ -32,8 +63,6 @@ export interface rule {
clash_mode?: string clash_mode?: string
rule_set?: string[] rule_set?: string[]
rule_set_ipcidr_match_source?: boolean rule_set_ipcidr_match_source?: boolean
invert?: boolean
outbound?: string
} }
export interface ruleset { export interface ruleset {
+12 -9
View File
@@ -96,16 +96,22 @@
</v-row> </v-row>
</v-card-subtitle> </v-card-subtitle>
<v-card-text> <v-card-text>
<v-row>
<v-col>{{ $t('admin.action') }}</v-col>
<v-col>
{{ item.action }}
</v-col>
</v-row>
<v-row> <v-row>
<v-col>{{ $t('objects.outbound') }}</v-col> <v-col>{{ $t('objects.outbound') }}</v-col>
<v-col> <v-col>
{{ item.outbound }} {{ item.outbound?? '-' }}
</v-col> </v-col>
</v-row> </v-row>
<v-row> <v-row>
<v-col>{{ $t('pages.rules') }}</v-col> <v-col>{{ $t('pages.rules') }}</v-col>
<v-col> <v-col>
{{ item.rules ? item.rules.length : Object.keys(item).filter(r => !["rule_set_ipcidr_match_source","invert","outbound"].includes(r)).length }} {{ item.rules ? item.rules.length : Object.keys(item).filter(r => !actionKeys.includes(r)).length }}
</v-col> </v-col>
</v-row> </v-row>
<v-row> <v-row>
@@ -151,7 +157,7 @@ import { computed, ref, onMounted } from 'vue'
import RuleVue from '@/layouts/modals/Rule.vue' import RuleVue from '@/layouts/modals/Rule.vue'
import RulesetVue from '@/layouts/modals/Ruleset.vue' import RulesetVue from '@/layouts/modals/Ruleset.vue'
import { Config } from '@/types/config' import { Config } from '@/types/config'
import { logicalRule, ruleset } from '@/types/rules' import { actionKeys, ruleset } from '@/types/rules'
import { FindDiff } from '@/plugins/utils' import { FindDiff } from '@/plugins/utils'
const oldConfig = ref({}) const oldConfig = ref({})
@@ -239,15 +245,12 @@ const closeRuleModal = () => {
ruleModal.value.visible = false ruleModal.value.visible = false
} }
const saveRuleModal = (data:logicalRule) => { const saveRuleModal = (data:any) => {
// Logical or simple
const ruleData = data.type == 'logical' ? data : data.rules[0]
// New or Edit // New or Edit
if (ruleModal.value.index == -1) { if (ruleModal.value.index == -1) {
rules.value.push(ruleData) rules.value.push(data)
} else { } else {
rules.value[ruleModal.value.index] = ruleData rules.value[ruleModal.value.index] = data
} }
ruleModal.value.visible = false ruleModal.value.visible = false
} }