mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-22 16:07:49 +08:00
Update On Tue Aug 19 20:36:53 CEST 2025
This commit is contained in:
@@ -1094,3 +1094,4 @@ Update On Fri Aug 15 20:40:48 CEST 2025
|
||||
Update On Sat Aug 16 20:36:37 CEST 2025
|
||||
Update On Sun Aug 17 20:39:03 CEST 2025
|
||||
Update On Mon Aug 18 20:42:30 CEST 2025
|
||||
Update On Tue Aug 19 20:36:45 CEST 2025
|
||||
|
||||
@@ -28,15 +28,16 @@ type Mieru struct {
|
||||
|
||||
type MieruOption struct {
|
||||
BasicOption
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port,omitempty"`
|
||||
PortRange string `proxy:"port-range,omitempty"`
|
||||
Transport string `proxy:"transport"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
UserName string `proxy:"username"`
|
||||
Password string `proxy:"password"`
|
||||
Multiplexing string `proxy:"multiplexing,omitempty"`
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port,omitempty"`
|
||||
PortRange string `proxy:"port-range,omitempty"`
|
||||
Transport string `proxy:"transport"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
UserName string `proxy:"username"`
|
||||
Password string `proxy:"password"`
|
||||
Multiplexing string `proxy:"multiplexing,omitempty"`
|
||||
HandshakeMode string `proxy:"handshake-mode,omitempty"`
|
||||
}
|
||||
|
||||
// DialContext implements C.ProxyAdapter
|
||||
@@ -245,6 +246,9 @@ func buildMieruClientConfig(option MieruOption) (*mieruclient.ClientConfig, erro
|
||||
Level: mierupb.MultiplexingLevel(multiplexing).Enum(),
|
||||
}
|
||||
}
|
||||
if handshakeMode, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; ok {
|
||||
config.Profile.HandshakeMode = (*mierupb.HandshakeMode)(&handshakeMode)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -294,6 +298,11 @@ func validateMieruOption(option MieruOption) error {
|
||||
return fmt.Errorf("invalid multiplexing level: %s", option.Multiplexing)
|
||||
}
|
||||
}
|
||||
if option.HandshakeMode != "" {
|
||||
if _, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; !ok {
|
||||
return fmt.Errorf("invalid handshake mode: %s", option.HandshakeMode)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -933,6 +933,8 @@ proxies: # socks5
|
||||
password: password
|
||||
# 可以使用的值包括 MULTIPLEXING_OFF, MULTIPLEXING_LOW, MULTIPLEXING_MIDDLE, MULTIPLEXING_HIGH。其中 MULTIPLEXING_OFF 会关闭多路复用功能。默认值为 MULTIPLEXING_LOW。
|
||||
# multiplexing: MULTIPLEXING_LOW
|
||||
# 如果想开启 0-RTT 握手,请设置为 HANDSHAKE_NO_WAIT,否则请设置为 HANDSHAKE_STANDARD。默认值为 HANDSHAKE_STANDARD
|
||||
# handshake-mode: HANDSHAKE_STANDARD
|
||||
|
||||
# anytls
|
||||
- name: anytls
|
||||
@@ -1475,6 +1477,7 @@ listeners:
|
||||
# masquerade: http://127.0.0.1:8080 #作为反向代理
|
||||
# masquerade: https://127.0.0.1:8080 #作为反向代理
|
||||
|
||||
# 注意,listeners中的tun仅提供给高级用户使用,普通用户应使用顶层配置中的tun
|
||||
- name: tun-in-1
|
||||
type: tun
|
||||
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ require (
|
||||
github.com/bahlo/generic-list-go v0.2.0
|
||||
github.com/coreos/go-iptables v0.8.0
|
||||
github.com/dlclark/regexp2 v1.11.5
|
||||
github.com/enfein/mieru/v3 v3.16.1
|
||||
github.com/enfein/mieru/v3 v3.19.0
|
||||
github.com/go-chi/chi/v5 v5.2.2
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gobwas/ws v1.4.0
|
||||
@@ -31,7 +31,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.7
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
|
||||
+4
-4
@@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
|
||||
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/enfein/mieru/v3 v3.19.0 h1:GXUTWoWmr8pTqGSTbh82VXfnCENJm6m5UN76c3Ynzfw=
|
||||
github.com/enfein/mieru/v3 v3.19.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
|
||||
@@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
|
||||
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd h1:VfD6UxKPAg7u9rPyxl18lQkpE9s8dZq0u2cPAgQShWs=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
|
||||
@@ -113,3 +113,11 @@ func (c realityConnWrapper) Upstream() any {
|
||||
func (c realityConnWrapper) CloseWrite() error {
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
func (c realityConnWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c realityConnWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -25,11 +25,12 @@ import (
|
||||
"github.com/metacubex/sing-vmess/vless"
|
||||
"github.com/metacubex/sing/common"
|
||||
"github.com/metacubex/sing/common/metadata"
|
||||
"github.com/metacubex/sing/common/network"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*reality.Conn](conn) // *utls.Conn
|
||||
tlsConn, loaded := network.CastReader[*reality.Conn](conn) // *utls.Conn
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -37,7 +38,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*tlsC.UConn](conn) // *utls.UConn
|
||||
tlsConn, loaded := network.CastReader[*tlsC.UConn](conn) // *utls.UConn
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*encryption.ClientConn](conn)
|
||||
tlsConn, loaded := network.CastReader[*encryption.ClientConn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -53,7 +54,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*encryption.ServerConn](conn)
|
||||
tlsConn, loaded := network.CastReader[*encryption.ServerConn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hash256 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash256[:])
|
||||
hash32 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(nfsEKeyBytes)
|
||||
i.xorKey = xorKey[:]
|
||||
@@ -79,7 +79,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
|
||||
return
|
||||
}
|
||||
|
||||
func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
if i.nfsEKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/bfe4820f2f086daf639b1957eb23dc13c843cad1
|
||||
// https://github.com/XTLS/Xray-core/commit/d1fb48521271251a8c74bd64fcc2fc8700717a3b
|
||||
// https://github.com/XTLS/Xray-core/commit/49580705f6029648399304b816a2737f991582a8
|
||||
// https://github.com/XTLS/Xray-core/commit/84835bec7d0d8555d0dd30953ed26a272de814c4
|
||||
package encryption
|
||||
|
||||
@@ -54,8 +54,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash256[:])
|
||||
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
i.xorKey = xorKey[:]
|
||||
@@ -91,7 +91,7 @@ func (i *ServerInstance) Close() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
if i.nfsDKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
l += 10
|
||||
if t == 0 {
|
||||
c.out_after0 = true
|
||||
c.out_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
|
||||
@@ -77,7 +78,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
break
|
||||
}
|
||||
_, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...))
|
||||
c.out_header = make([]byte, 0, 5) // DO NOT CHANGE
|
||||
c.out_header = c.out_header[:0]
|
||||
c.ctr.XORKeyStream(p[:need], p[:need])
|
||||
p = p[need:]
|
||||
}
|
||||
@@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
c.isHeader = false
|
||||
if t == 0 {
|
||||
c.in_after0 = true
|
||||
c.in_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
c.peerCtr.XORKeyStream(p[:need], p[:need])
|
||||
_, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...))
|
||||
c.in_header = make([]byte, 0, 5) // DO NOT CHANGE
|
||||
c.in_header = c.in_header[:0]
|
||||
p = p[need:]
|
||||
}
|
||||
return n, err
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"@mui/x-date-pickers": "8.10.0",
|
||||
"@nyanpasu/interface": "workspace:^",
|
||||
"@nyanpasu/ui": "workspace:^",
|
||||
"@tailwindcss/postcss": "4.1.11",
|
||||
"@tailwindcss/postcss": "4.1.12",
|
||||
"@tanstack/router-zod-adapter": "1.81.5",
|
||||
"@tauri-apps/api": "2.6.0",
|
||||
"@types/json-schema": "7.0.15",
|
||||
@@ -56,12 +56,12 @@
|
||||
"@csstools/normalize.css": "12.1.1",
|
||||
"@emotion/babel-plugin": "11.13.5",
|
||||
"@emotion/react": "11.14.0",
|
||||
"@iconify/json": "2.2.375",
|
||||
"@iconify/json": "2.2.376",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@tanstack/react-query": "5.84.2",
|
||||
"@tanstack/react-router": "1.131.26",
|
||||
"@tanstack/react-router-devtools": "1.131.26",
|
||||
"@tanstack/router-plugin": "1.131.26",
|
||||
"@tanstack/react-router": "1.131.27",
|
||||
"@tanstack/react-router-devtools": "1.131.27",
|
||||
"@tanstack/router-plugin": "1.131.27",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
|
||||
"@tauri-apps/plugin-dialog": "2.3.0",
|
||||
"@tauri-apps/plugin-fs": "2.4.0",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"react-error-boundary": "6.0.0",
|
||||
"react-i18next": "15.6.1",
|
||||
"react-use": "17.6.0",
|
||||
"tailwindcss": "4.1.11",
|
||||
"tailwindcss": "4.1.12",
|
||||
"vite": "7.1.2",
|
||||
"vite-tsconfig-paths": "5.1.4"
|
||||
},
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.19.12",
|
||||
"mihomo_alpha": "alpha-b481eca",
|
||||
"clash_rs": "v0.8.2",
|
||||
"mihomo_alpha": "alpha-4e20ed6",
|
||||
"clash_rs": "v0.9.0",
|
||||
"clash_premium": "2023-09-05-gdcc8d87",
|
||||
"clash_rs_alpha": "0.8.2-alpha+sha.3010e42"
|
||||
"clash_rs_alpha": "0.9.0-alpha+sha.ac11887"
|
||||
},
|
||||
"arch_template": {
|
||||
"mihomo": {
|
||||
@@ -69,5 +69,5 @@
|
||||
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
|
||||
}
|
||||
},
|
||||
"updated_at": "2025-08-17T22:21:09.107Z"
|
||||
"updated_at": "2025-08-18T22:20:44.906Z"
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
|
||||
"stylelint-order": "7.0.0",
|
||||
"stylelint-scss": "6.12.1",
|
||||
"tailwindcss": "4.1.11",
|
||||
"tailwindcss": "4.1.12",
|
||||
"tsx": "4.20.4",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.39.1"
|
||||
|
||||
Generated
+272
-249
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@
|
||||
"picocolors": "1.1.1",
|
||||
"tar": "7.4.3",
|
||||
"telegram": "2.26.22",
|
||||
"undici": "7.13.0",
|
||||
"undici": "7.14.0",
|
||||
"yargs": "18.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ friendlyarm,nanopi-r2c|\
|
||||
friendlyarm,nanopi-r2c-plus|\
|
||||
friendlyarm,nanopi-r2s|\
|
||||
friendlyarm,nanopi-r2s-plus|\
|
||||
friendlyarm,nanopi-r3s|\
|
||||
friendlyarm,nanopi-r4se|\
|
||||
friendlyarm,nanopi-r4s|\
|
||||
friendlyarm,nanopi-r6c|\
|
||||
@@ -22,10 +23,6 @@ xunlong,orangepi-r1-plus-lts)
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth0"
|
||||
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth1"
|
||||
;;
|
||||
friendlyarm,nanopi-r3s)
|
||||
ucidef_set_led_netdev "wan" "WAN" "wan_led" "eth0"
|
||||
ucidef_set_led_netdev "lan" "LAN" "lan_led" "eth1"
|
||||
;;
|
||||
friendlyarm,nanopi-r5c)
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1"
|
||||
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0"
|
||||
@@ -43,7 +40,6 @@ friendlyarm,nanopi-r6s)
|
||||
;;
|
||||
friendlyarm,nanopi-m5|\
|
||||
friendlyarm,nanopi-r76s)
|
||||
ucidef_set_led_default "power" "POWER" "red:power" "1"
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1"
|
||||
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0"
|
||||
;;
|
||||
@@ -65,6 +61,17 @@ radxa,e20c)
|
||||
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth0"
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1"
|
||||
;;
|
||||
radxa,e24c|\
|
||||
radxa,e54c)
|
||||
ucidef_set_led_netdev "lan1" "LAN1" "green:lan1" "lan1"
|
||||
ucidef_set_led_netdev "lan2" "LAN2" "green:lan2" "lan2"
|
||||
ucidef_set_led_netdev "lan3" "LAN3" "green:lan3" "lan3"
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "wan"
|
||||
;;
|
||||
radxa,e52c)
|
||||
ucidef_set_led_netdev "lan" "LAN" "green:lan" "eth1"
|
||||
ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth0"
|
||||
;;
|
||||
widora,mangopi-m28c)
|
||||
ucidef_set_led_netdev "modem" "MODEM" "blue:modem" "usb0"
|
||||
ucidef_set_led_netdev "wifi" "WIFI" "yellow:wifi" "wlan0"
|
||||
|
||||
@@ -22,6 +22,7 @@ rockchip_setup_interfaces()
|
||||
friendlyarm,nanopi-r4se|\
|
||||
friendlyarm,nanopi-r6c|\
|
||||
hinlink,opc-h66k|\
|
||||
radxa,e52c|\
|
||||
rocktech,mpc1903|\
|
||||
seewo,srcm3588-io|\
|
||||
sharevdi,h3399pc|\
|
||||
@@ -69,6 +70,10 @@ rockchip_setup_interfaces()
|
||||
lyt,t68m)
|
||||
ucidef_set_interfaces_lan_wan 'lan2 lan3 lan4' 'lan1'
|
||||
;;
|
||||
radxa,e24c|\
|
||||
radxa,e54c)
|
||||
ucidef_set_interfaces_lan_wan 'lan1 lan2 lan3' 'wan'
|
||||
;;
|
||||
*)
|
||||
ucidef_set_interface_lan 'eth0'
|
||||
;;
|
||||
@@ -121,6 +126,7 @@ rockchip_setup_macs()
|
||||
friendlyarm,nanopi-r2c-plus|\
|
||||
friendlyarm,nanopi-r2s|\
|
||||
friendlyarm,nanopi-r2s-plus|\
|
||||
friendlyarm,nanopi-r76s|\
|
||||
hinlink,opc-h28k|\
|
||||
hinlink,opc-h66k|\
|
||||
hinlink,opc-h68k|\
|
||||
@@ -151,10 +157,6 @@ rockchip_setup_macs()
|
||||
wan_mac=$(macaddr_generate_from_mmc_cid mmcblk1)
|
||||
lan_mac=$(macaddr_add "$wan_mac" +1)
|
||||
;;
|
||||
friendlyarm,nanopi-r76s)
|
||||
wan_mac=$(macaddr_generate_from_mmc_cid mmcblk2)
|
||||
lan_mac=$(macaddr_add "$wan_mac" +1)
|
||||
;;
|
||||
xunlong,orangepi-r1-plus|\
|
||||
xunlong,orangepi-r1-plus-lts)
|
||||
lan_mac=$(cat /sys/class/net/eth1/address)
|
||||
|
||||
@@ -34,7 +34,6 @@ armsom,sige3|\
|
||||
armsom,sige5|\
|
||||
armsom,sige7|\
|
||||
hinlink,opc-h28k|\
|
||||
radxa,e20c|\
|
||||
widora,mangopi-m28k|\
|
||||
widora,mangopi-m28k-pro)
|
||||
set_interface_core 4 "eth0"
|
||||
@@ -73,6 +72,13 @@ friendlyarm,nanopi-r6s)
|
||||
set_interface_core 20 "eth1"
|
||||
set_interface_core 40 "eth2"
|
||||
;;
|
||||
radxa,e20c|\
|
||||
radxa,e24c)
|
||||
set_interface_core 2 "eth0"
|
||||
;;
|
||||
radxa,e54c)
|
||||
set_interface_core 20 "eth0"
|
||||
;;
|
||||
widora,mangopi-m28c)
|
||||
set_interface_core 4 "eth0"
|
||||
set_interface_core 8 "xhci-hcd:usb1"
|
||||
|
||||
+100
-77
@@ -2,10 +2,10 @@
|
||||
// Copyright (c) 2024 AY <amadeus@jmu.edu.cn>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/pinctrl/rockchip.h>
|
||||
|
||||
#include "rk3528.dtsi"
|
||||
|
||||
/ {
|
||||
@@ -31,7 +31,7 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&user_key>;
|
||||
|
||||
key-user {
|
||||
button-user {
|
||||
label = "user";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
|
||||
@@ -42,7 +42,7 @@
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&lan_led_en>, <&wan_led_en>, <&sys_led_en>;
|
||||
pinctrl-0 = <&lan_led_g>, <&wan_led_g>, <&sys_led_g>;
|
||||
|
||||
lan {
|
||||
label = "green:lan";
|
||||
@@ -60,70 +60,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v8: vcc-1v8 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_1v8";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
vin-supply = <&vcc_3v3>;
|
||||
};
|
||||
|
||||
vcc_3v3: vcc-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_3v3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vcc5v0_sys: vcc5v0-sys {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc5v0_sys";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
};
|
||||
|
||||
vcc5v0_usb_host: vcc5v0-usb-host {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&vcc5v0_usb_host_en>;
|
||||
regulator-name = "vcc5v0_usb_host";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vccio_sd: vccio-sd {
|
||||
compatible = "regulator-gpio";
|
||||
gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
|
||||
regulator-name = "vccio_sd";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
states = <1800000 0x0>, <3300000 0x1>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vcc_ddr: vcc-ddr {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_ddr";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vdd_0v9: vdd-0v9 {
|
||||
vdd_0v9: regulator-0v9-vdd {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vdd_0v9";
|
||||
regulator-always-on;
|
||||
@@ -133,7 +70,70 @@
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vdd_arm: vdd-arm {
|
||||
vcc_ddr: regulator-1v1-vcc-ddr {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_ddr";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1100000>;
|
||||
regulator-max-microvolt = <1100000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vcc_1v8: regulator-1v8-vcc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_1v8";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
vin-supply = <&vcc_3v3>;
|
||||
};
|
||||
|
||||
vcc_3v3: regulator-3v3-vcc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_3v3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vcc5v0_sys: regulator-5v0-vcc-sys {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc5v0_sys";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
};
|
||||
|
||||
vcc5v0_usb20: regulator-5v0-vcc-usb20 {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&usb_host_en>;
|
||||
regulator-name = "vcc5v0_usb20";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vccio_sd: regulator-vccio-sd {
|
||||
compatible = "regulator-gpio";
|
||||
gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdmmc_vol_ctrl_h>;
|
||||
regulator-name = "vccio_sd";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
states = <1800000 0x0>, <3300000 0x1>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vdd_arm: regulator-vdd-arm {
|
||||
compatible = "pwm-regulator";
|
||||
pwms = <&pwm1 0 5000 1>;
|
||||
pwm-supply = <&vcc5v0_sys>;
|
||||
@@ -145,7 +145,7 @@
|
||||
regulator-settling-time-up-us = <250>;
|
||||
};
|
||||
|
||||
vdd_logic: vdd-logic {
|
||||
vdd_logic: regulator-vdd-logic {
|
||||
compatible = "pwm-regulator";
|
||||
pwms = <&pwm2 0 5000 1>;
|
||||
pwm-supply = <&vcc5v0_sys>;
|
||||
@@ -205,19 +205,24 @@
|
||||
&i2c1 {
|
||||
status = "okay";
|
||||
|
||||
eeprom: eeprom@50 {
|
||||
compatible = "atmel,24c16";
|
||||
eeprom@50 {
|
||||
compatible = "belling,bl24c16a", "atmel,24c16";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x50>;
|
||||
pagesize = <16>;
|
||||
read-only;
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
eth_mac0: macaddr@9e {
|
||||
reg = <0x9e 0x06>;
|
||||
};
|
||||
|
||||
eth_mac1: macaddr@a4 {
|
||||
reg = <0xa4 0x06>;
|
||||
};
|
||||
@@ -226,7 +231,7 @@
|
||||
};
|
||||
|
||||
&mdio1 {
|
||||
rgmii_phy: phy@1 {
|
||||
rgmii_phy: ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-ieee802.3-c22";
|
||||
reg = <0x1>;
|
||||
};
|
||||
@@ -259,21 +264,27 @@
|
||||
};
|
||||
|
||||
leds {
|
||||
lan_led_en: lan-led-en {
|
||||
lan_led_g: lan-led-g {
|
||||
rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
wan_led_en: wan-led-en {
|
||||
wan_led_g: wan-led-g {
|
||||
rockchip,pins = <4 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
sys_led_en: sys-led-en {
|
||||
sys_led_g: sys-led-g {
|
||||
rockchip,pins = <4 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc {
|
||||
sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h {
|
||||
rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
usb {
|
||||
vcc5v0_usb_host_en: vcc5v0-usb-host-en {
|
||||
usb_host_en: usb-host-en {
|
||||
rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
@@ -332,7 +343,11 @@
|
||||
};
|
||||
|
||||
&usb2phy0_host {
|
||||
phy-supply = <&vcc5v0_usb_host>;
|
||||
phy-supply = <&vcc5v0_usb20>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy0_otg {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -343,3 +358,11 @@
|
||||
&usb_host0_ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_xhci {
|
||||
dr_mode = "host";
|
||||
maximum-speed = "high-speed";
|
||||
phys = <&usb2phy0_otg>;
|
||||
phy-names = "usb2-phy";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,626 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include "rk3528.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Radxa E24C";
|
||||
compatible = "radxa,e24c", "rockchip,rk3528";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &gmac1;
|
||||
mmc0 = &sdhci;
|
||||
mmc1 = &sdmmc;
|
||||
rtc0 = &hym8563;
|
||||
|
||||
led-boot = &status_led;
|
||||
led-failsafe = &status_led;
|
||||
led-running = &status_led;
|
||||
led-upgrade = &status_led;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:1500000n8";
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio0_a0_user>;
|
||||
|
||||
button-user {
|
||||
label = "USER";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
status_led: led-0 {
|
||||
label = "green:sys";
|
||||
gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sys_led_g>;
|
||||
};
|
||||
|
||||
led-1 {
|
||||
label = "green:wan";
|
||||
linux,default-trigger = "netdev";
|
||||
gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&wan_led_g>;
|
||||
};
|
||||
|
||||
led-2 {
|
||||
label = "green:lan1";
|
||||
linux,default-trigger = "netdev";
|
||||
gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&lan1_led_g>;
|
||||
};
|
||||
|
||||
led-3 {
|
||||
label = "green:lan2";
|
||||
linux,default-trigger = "netdev";
|
||||
gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&lan2_led_g>;
|
||||
};
|
||||
|
||||
led-4 {
|
||||
label = "green:lan3";
|
||||
linux,default-trigger = "netdev";
|
||||
gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&lan3_led_g>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_12v: regulator-12v0-vcc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_12v";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <12000000>;
|
||||
regulator-max-microvolt = <12000000>;
|
||||
};
|
||||
|
||||
vcc3v3_mkey: regulator-3v3-vcc-mkey {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mkey_pwr_en>;
|
||||
regulator-name = "vcc3v3_mkey";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vcc5v0_sys: regulator-5v0-vcc-sys {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc5v0_sys";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc_12v>;
|
||||
};
|
||||
|
||||
vcc5v0_usb20: regulator-5v0-vcc-usb20 {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&usb_host_en>;
|
||||
regulator-name = "vcc5v0_usb20";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
avddh_3v3: regulator-avdd-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio_8367_en>;
|
||||
regulator-name = "avddh_3v3";
|
||||
startup-delay-us = <10000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
|
||||
vccio_sd: regulator-vccio-sd {
|
||||
compatible = "regulator-gpio";
|
||||
gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdmmc_vol_ctrl_h>;
|
||||
regulator-name = "vccio_sd";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
states = <1800000 0x0>, <3300000 0x1>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
};
|
||||
|
||||
&combphy {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
cpu-supply = <&vdd_arm>;
|
||||
};
|
||||
|
||||
&cpu1 {
|
||||
cpu-supply = <&vdd_arm>;
|
||||
};
|
||||
|
||||
&cpu2 {
|
||||
cpu-supply = <&vdd_arm>;
|
||||
};
|
||||
|
||||
&cpu3 {
|
||||
cpu-supply = <&vdd_arm>;
|
||||
};
|
||||
|
||||
&gmac1 {
|
||||
/delete-property/ snps,tso;
|
||||
clock_in_out = "output";
|
||||
phy-mode = "rgmii-id";
|
||||
phy-supply = <&avddh_3v3>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&rgmii_miim
|
||||
&rgmii_tx_bus2
|
||||
&rgmii_rx_bus2
|
||||
&rgmii_rgmii_clk
|
||||
&rgmii_rgmii_bus>;
|
||||
status = "okay";
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
&gpu {
|
||||
mali-supply = <&vdd_logic>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c0m0_xfer>;
|
||||
status = "okay";
|
||||
|
||||
rk805: pmic@18 {
|
||||
compatible = "rockchip,rk805";
|
||||
reg = <0x18>;
|
||||
interrupt-parent = <&gpio4>;
|
||||
interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
|
||||
#clock-cells = <1>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pmic_int>;
|
||||
system-power-controller;
|
||||
wakeup-source;
|
||||
|
||||
vcc1-supply = <&vcc5v0_sys>;
|
||||
vcc2-supply = <&vcc5v0_sys>;
|
||||
vcc3-supply = <&vcc5v0_sys>;
|
||||
vcc4-supply = <&vcc5v0_sys>;
|
||||
vcc5-supply = <&vcc5v0_sys>;
|
||||
vcc6-supply = <&vcc5v0_sys>;
|
||||
|
||||
regulators {
|
||||
vdd_arm: DCDC_REG1 {
|
||||
regulator-name = "vdd_arm";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <712500>;
|
||||
regulator-max-microvolt = <1450000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_logic: DCDC_REG2 {
|
||||
regulator-name = "vdd_logic";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <712500>;
|
||||
regulator-max-microvolt = <1450000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_ddr: DCDC_REG3 {
|
||||
regulator-name = "vcc_ddr";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_3v3: DCDC_REG4 {
|
||||
regulator-name = "vcc_3v3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v8: LDO_REG1 {
|
||||
regulator-name = "vcc_1v8";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc1v8_emmc: LDO_REG2 {
|
||||
regulator-name = "vcc1v8_emmc";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_0v9_p: LDO_REG3 {
|
||||
regulator-name = "vdd_0v9_p";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <900000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c1m0_xfer>;
|
||||
status = "okay";
|
||||
|
||||
eeprom@50 {
|
||||
compatible = "belling,bl24c16a", "atmel,24c16";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x50>;
|
||||
pagesize = <16>;
|
||||
read-only;
|
||||
vcc-supply = <&vcc_3v3>;
|
||||
|
||||
nvmem-layout {
|
||||
compatible = "fixed-layout";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
eth_mac0: macaddr@9e {
|
||||
reg = <0x9e 0x06>;
|
||||
};
|
||||
|
||||
eth_mac1: macaddr@a4 {
|
||||
reg = <0xa4 0x06>;
|
||||
};
|
||||
|
||||
eth_mac2: macaddr@aa {
|
||||
reg = <0xaa 0x06>;
|
||||
};
|
||||
|
||||
eth_mac3: macaddr@b0 {
|
||||
reg = <0xb0 0x06>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c5 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c5m0_xfer>;
|
||||
status = "okay";
|
||||
|
||||
hym8563: rtc@51 {
|
||||
compatible = "haoyu,hym8563";
|
||||
reg = <0x51>;
|
||||
#clock-cells = <0>;
|
||||
interrupt-parent = <&gpio4>;
|
||||
interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&rtc_int_l>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
&mdio1 {
|
||||
ethernet-switch@29 {
|
||||
compatible = "realtek,rtl8365mb";
|
||||
reg = <29>;
|
||||
reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gmac1_rstn_l>;
|
||||
|
||||
switch_intc: interrupt-controller {
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <RK_PC2 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <0>;
|
||||
};
|
||||
|
||||
phy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <1>;
|
||||
};
|
||||
|
||||
phy2: ethernet-phy@2 {
|
||||
reg = <2>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <2>;
|
||||
};
|
||||
|
||||
phy3: ethernet-phy@3 {
|
||||
reg = <3>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
|
||||
phy4: ethernet-phy@4 {
|
||||
reg = <4>;
|
||||
interrupt-parent = <&switch_intc>;
|
||||
interrupts = <4>;
|
||||
};
|
||||
};
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet-port@0 {
|
||||
reg = <0>;
|
||||
label = "wan";
|
||||
phy-handle = <&phy0>;
|
||||
nvmem-cells = <ð_mac0>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
ethernet-port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
phy-handle = <&phy1>;
|
||||
nvmem-cells = <ð_mac1>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
ethernet-port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
phy-handle = <&phy2>;
|
||||
nvmem-cells = <ð_mac2>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
ethernet-port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
phy-handle = <&phy3>;
|
||||
nvmem-cells = <ð_mac3>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
ethernet-port@6 {
|
||||
reg = <6>;
|
||||
ethernet = <&gmac1>;
|
||||
phy-mode = "rgmii-id";
|
||||
rx-internal-delay-ps = <2000>;
|
||||
tx-internal-delay-ps = <2000>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pcie2x1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pciem1_pins>;
|
||||
reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc3v3_mkey>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
ethernet {
|
||||
gmac1_rstn_l: gmac1-rstn-l {
|
||||
rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
gpio_8367_en: gpio-8367-en {
|
||||
rockchip,pins = <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
rtl8367rb_eint: rtl8367rb-eint {
|
||||
rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
gpio0_a0_user: gpio0-a0-user {
|
||||
rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
lan1_led_g: lan1-led-g {
|
||||
rockchip,pins = <1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
lan2_led_g: lan2-led-g {
|
||||
rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
lan3_led_g: lan3-led-g {
|
||||
rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
sys_led_g: sys-led-g {
|
||||
rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
wan_led_g: wan-led-g {
|
||||
rockchip,pins = <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie {
|
||||
mkey_pwr_en: mkey-pwr-en {
|
||||
rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
pmic {
|
||||
pmic_int: pmic-int {
|
||||
rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc {
|
||||
rtc_int_l: rtc-int-l {
|
||||
rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc {
|
||||
sdmmc_vol_ctrl_h: sdmmc-vol-ctrl-h {
|
||||
rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
usb {
|
||||
usb_host_en: usb-host-en {
|
||||
rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&rng {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
bus-width = <8>;
|
||||
cap-mmc-highspeed;
|
||||
mmc-hs200-1_8v;
|
||||
non-removable;
|
||||
vmmc-supply = <&vcc_3v3>;
|
||||
vqmmc-supply = <&vcc1v8_emmc>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdmmc {
|
||||
bus-width = <4>;
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
sd-uhs-sdr104;
|
||||
vmmc-supply = <&vcc_3v3>;
|
||||
vqmmc-supply = <&vccio_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sfc {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&fspi_csn0>, <&fspi_pins>;
|
||||
status = "okay";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-tx-bus-width = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&tsadc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart0m0_xfer>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy0_host {
|
||||
phy-supply = <&vcc5v0_usb20>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy0_otg {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_ehci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_xhci {
|
||||
dr_mode = "host";
|
||||
maximum-speed = "high-speed";
|
||||
phys = <&usb2phy0_otg>;
|
||||
phy-names = "usb2-phy";
|
||||
status = "okay";
|
||||
};
|
||||
@@ -0,0 +1,737 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2024 Radxa Computer (Shenzhen) Co., Ltd.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/pinctrl/rockchip.h>
|
||||
#include <dt-bindings/pwm/pwm.h>
|
||||
#include "rk3588s.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Radxa E52C";
|
||||
compatible = "radxa,e52c", "rockchip,rk3582", "rockchip,rk3588s";
|
||||
|
||||
aliases {
|
||||
mmc0 = &sdhci;
|
||||
mmc1 = &sdmmc;
|
||||
|
||||
led-boot = &status_led;
|
||||
led-failsafe = &status_led;
|
||||
led-running = &status_led;
|
||||
led-upgrade = &status_led;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial2:1500000n8";
|
||||
};
|
||||
|
||||
keys-0 {
|
||||
compatible = "adc-keys";
|
||||
io-channels = <&saradc 0>;
|
||||
io-channel-names = "buttons";
|
||||
keyup-threshold-microvolt = <18000>;
|
||||
poll-interval = <100>;
|
||||
|
||||
button-0 {
|
||||
label = "Maskrom";
|
||||
linux,code = <KEY_VENDOR>;
|
||||
press-threshold-microvolt = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
keys-1 {
|
||||
compatible = "gpio-keys";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm15_ir_m1>;
|
||||
|
||||
button-1 {
|
||||
label = "User";
|
||||
linux,code = <KEY_RESTART>;
|
||||
gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
leds-0 {
|
||||
compatible = "gpio-leds";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&power_led>;
|
||||
|
||||
status_led: led-0 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
default-state = "on";
|
||||
function = LED_FUNCTION_STATUS;
|
||||
gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
leds-1 {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
led-1 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_LAN;
|
||||
linux,default-trigger = "netdev";
|
||||
pwms = <&pwm14 0 1000000 PWM_POLARITY_INVERTED>;
|
||||
max-brightness = <255>;
|
||||
};
|
||||
|
||||
led-2 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_WAN;
|
||||
linux,default-trigger = "netdev";
|
||||
pwms = <&pwm11 0 1000000 PWM_POLARITY_INVERTED>;
|
||||
max-brightness = <255>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v1_nldo_s3: regulator-1v1-vcc-nldo-s3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_1v1_nldo_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1100000>;
|
||||
regulator-max-microvolt = <1100000>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
};
|
||||
|
||||
vcc_3v3_s0: regulator-3v3-vcc-s0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_3v3_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
vin-supply = <&vcc_3v3_s3>;
|
||||
};
|
||||
|
||||
vcca: regulator-4v0-vcca {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcca";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <4000000>;
|
||||
regulator-max-microvolt = <4000000>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
};
|
||||
|
||||
vcc5v0_usb_otg0: regulator-5v0-vcc-usb-otg0 {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpio = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&usb_otg_pwren_h>;
|
||||
regulator-name = "vcc5v0_usb_otg0";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
};
|
||||
|
||||
vcc_5v0: regulator-5v0-vcc {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&vcc_5v0_pwren_h>;
|
||||
regulator-name = "vcc_5v0";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
};
|
||||
|
||||
vcc_sysin: regulator-5v0-vcc-sysin {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcc_sysin";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&combphy0_ps {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&combphy2_psu {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/*
|
||||
* In the Rockchip RK3582 SoC, some CPU cores end up disabled
|
||||
* and unused because they're marked in the efuses as defective.
|
||||
* The disabling in the DT is performed by the boot loader.
|
||||
*/
|
||||
&cpu_b0 {
|
||||
cpu-supply = <&vdd_cpu_big0_s0>;
|
||||
};
|
||||
|
||||
&cpu_b1 {
|
||||
cpu-supply = <&vdd_cpu_big0_s0>;
|
||||
};
|
||||
|
||||
&cpu_b2 {
|
||||
cpu-supply = <&vdd_cpu_big1_s0>;
|
||||
};
|
||||
|
||||
&cpu_b3 {
|
||||
cpu-supply = <&vdd_cpu_big1_s0>;
|
||||
};
|
||||
|
||||
&cpu_l0 {
|
||||
cpu-supply = <&vdd_cpu_lit_s0>;
|
||||
};
|
||||
|
||||
&cpu_l1 {
|
||||
cpu-supply = <&vdd_cpu_lit_s0>;
|
||||
};
|
||||
|
||||
&cpu_l2 {
|
||||
cpu-supply = <&vdd_cpu_lit_s0>;
|
||||
};
|
||||
|
||||
&cpu_l3 {
|
||||
cpu-supply = <&vdd_cpu_lit_s0>;
|
||||
};
|
||||
|
||||
&display_subsystem {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c0m2_xfer>;
|
||||
status = "okay";
|
||||
|
||||
vdd_cpu_big0_s0: regulator@42 {
|
||||
compatible = "rockchip,rk8602";
|
||||
reg = <0x42>;
|
||||
fcs,suspend-voltage-selector = <1>;
|
||||
regulator-name = "vdd_cpu_big0_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-ramp-delay = <2300>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_cpu_big1_s0: regulator@43 {
|
||||
compatible = "rockchip,rk8603", "rockchip,rk8602";
|
||||
reg = <0x43>;
|
||||
fcs,suspend-voltage-selector = <1>;
|
||||
regulator-name = "vdd_cpu_big1_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
regulator-ramp-delay = <2300>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
eeprom@50 {
|
||||
compatible = "belling,bl24c16a", "atmel,24c16";
|
||||
reg = <0x50>;
|
||||
pagesize = <16>;
|
||||
read-only;
|
||||
vcc-supply = <&vcc_3v3_s3>;
|
||||
};
|
||||
};
|
||||
|
||||
&i2c2 {
|
||||
status = "okay";
|
||||
|
||||
vdd_npu_s0: regulator@42 {
|
||||
compatible = "rockchip,rk8602";
|
||||
reg = <0x42>;
|
||||
fcs,suspend-voltage-selector = <1>;
|
||||
regulator-name = "vdd_npu_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <950000>;
|
||||
regulator-ramp-delay = <2300>;
|
||||
vin-supply = <&vcc_sysin>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c5 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2c5m2_xfer>;
|
||||
status = "okay";
|
||||
|
||||
rtc@51 {
|
||||
compatible = "haoyu,hym8563";
|
||||
reg = <0x51>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "rtcic_32kout";
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&rtc_int_l>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
&pcie2x1l1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie20x1_1_perstn_m1>;
|
||||
reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc_3v3_s3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie2x1l2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie20x1_2_perstn_m0>;
|
||||
reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc_3v3_s3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
keys {
|
||||
pwm15_ir_m1: pwm15-ir-m1 {
|
||||
rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
power_led: power-led {
|
||||
rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie {
|
||||
pcie20x1_1_perstn_m1: pcie-1 {
|
||||
rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
pcie20x1_2_perstn_m0: pcie-2 {
|
||||
rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
regulators {
|
||||
vcc_5v0_pwren_h: vcc-5v0-pwren-h {
|
||||
rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
rtc {
|
||||
rtc_int_l: rtc-int-l {
|
||||
rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
usb {
|
||||
usb_otg_pwren_h: usb-otg-pwren-h {
|
||||
rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pwm11 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm11m1_pins>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm14 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm14m1_pins>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&saradc {
|
||||
vref-supply = <&vcca_1v8_s0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
bus-width = <8>;
|
||||
cap-mmc-highspeed;
|
||||
mmc-hs400-1_8v;
|
||||
mmc-hs400-enhanced-strobe;
|
||||
non-removable;
|
||||
vmmc-supply = <&vcc_3v3_s0>;
|
||||
vqmmc-supply = <&vcc_1v8_s3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdmmc {
|
||||
bus-width = <4>;
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
|
||||
disable-wp;
|
||||
sd-uhs-sdr104;
|
||||
vmmc-supply = <&vcc_3v3_s3>;
|
||||
vqmmc-supply = <&vccio_sd_s0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
status = "okay";
|
||||
assigned-clocks = <&cru CLK_SPI2>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
num-cs = <1>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
|
||||
|
||||
pmic@0 {
|
||||
compatible = "rockchip,rk806";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
|
||||
<&rk806_dvs2_null>, <&rk806_dvs3_null>;
|
||||
spi-max-frequency = <1000000>;
|
||||
system-power-controller;
|
||||
|
||||
vcc1-supply = <&vcc_sysin>;
|
||||
vcc2-supply = <&vcc_sysin>;
|
||||
vcc3-supply = <&vcc_sysin>;
|
||||
vcc4-supply = <&vcc_sysin>;
|
||||
vcc5-supply = <&vcc_sysin>;
|
||||
vcc6-supply = <&vcc_sysin>;
|
||||
vcc7-supply = <&vcc_sysin>;
|
||||
vcc8-supply = <&vcc_sysin>;
|
||||
vcc9-supply = <&vcc_sysin>;
|
||||
vcc10-supply = <&vcc_sysin>;
|
||||
vcc11-supply = <&vcc_2v0_pldo_s3>;
|
||||
vcc12-supply = <&vcc_sysin>;
|
||||
vcc13-supply = <&vcc_1v1_nldo_s3>;
|
||||
vcc14-supply = <&vcc_1v1_nldo_s3>;
|
||||
vcca-supply = <&vcca>;
|
||||
|
||||
rk806_dvs1_null: dvs1-null-pins {
|
||||
pins = "gpio_pwrctrl1";
|
||||
function = "pin_fun0";
|
||||
};
|
||||
|
||||
rk806_dvs2_null: dvs2-null-pins {
|
||||
pins = "gpio_pwrctrl2";
|
||||
function = "pin_fun0";
|
||||
};
|
||||
|
||||
rk806_dvs3_null: dvs3-null-pins {
|
||||
pins = "gpio_pwrctrl3";
|
||||
function = "pin_fun0";
|
||||
};
|
||||
|
||||
regulators {
|
||||
vdd_gpu_s0: dcdc-reg1 {
|
||||
regulator-name = "vdd_gpu_s0";
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <950000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
regulator-enable-ramp-delay = <400>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_cpu_lit_s0: dcdc-reg2 {
|
||||
regulator-name = "vdd_cpu_lit_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <950000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_logic_s0: dcdc-reg3 {
|
||||
regulator-name = "vdd_logic_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <675000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <750000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_vdenc_s0: dcdc-reg4 {
|
||||
regulator-name = "vdd_vdenc_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <550000>;
|
||||
regulator-max-microvolt = <950000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_ddr_s0: dcdc-reg5 {
|
||||
regulator-name = "vdd_ddr_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <675000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
regulator-ramp-delay = <12500>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
regulator-suspend-microvolt = <850000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdd2_ddr_s3: dcdc-reg6 {
|
||||
regulator-name = "vdd2_ddr_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_2v0_pldo_s3: dcdc-reg7 {
|
||||
regulator-name = "vcc_2v0_pldo_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <2000000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_3v3_s3: dcdc-reg8 {
|
||||
regulator-name = "vcc_3v3_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
|
||||
vddq_ddr_s0: dcdc-reg9 {
|
||||
regulator-name = "vddq_ddr_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v8_s3: dcdc-reg10 {
|
||||
regulator-name = "vcc_1v8_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v8_s0: pldo-reg1 {
|
||||
regulator-name = "vcc_1v8_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcca_1v8_s0: pldo-reg2 {
|
||||
regulator-name = "vcca_1v8_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdda_1v2_s0: pldo-reg3 {
|
||||
regulator-name = "vdda_1v2_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcca_3v3_s0: pldo-reg4 {
|
||||
regulator-name = "vcca_3v3_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
|
||||
vccio_sd_s0: pldo-reg5 {
|
||||
regulator-name = "vccio_sd_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
pldo6_s3: pldo-reg6 {
|
||||
regulator-name = "pldo6_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_0v75_s3: nldo-reg1 {
|
||||
regulator-name = "vdd_0v75_s3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <750000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdda_ddr_pll_s0: nldo-reg2 {
|
||||
regulator-name = "vdda_ddr_pll_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <850000>;
|
||||
regulator-max-microvolt = <850000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <850000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdda_0v75_s0: nldo-reg3 {
|
||||
regulator-name = "vdda_0v75_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <750000>;
|
||||
};
|
||||
};
|
||||
|
||||
vdda_0v85_s0: nldo-reg4 {
|
||||
regulator-name = "vdda_0v85_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <850000>;
|
||||
regulator-max-microvolt = <850000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_0v75_s0: nldo-reg5 {
|
||||
regulator-name = "vdd_0v75_s0";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&tsadc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&u2phy0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&u2phy0_otg {
|
||||
phy-supply = <&vcc5v0_usb_otg0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
pinctrl-0 = <&uart2m0_xfer>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbdp_phy0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_xhci {
|
||||
dr_mode = "host";
|
||||
status = "okay";
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -425,6 +425,16 @@ define Device/radxa_e20c
|
||||
endef
|
||||
TARGET_DEVICES += radxa_e20c
|
||||
|
||||
define Device/radxa_e24c
|
||||
DEVICE_VENDOR := Radxa
|
||||
DEVICE_MODEL := E24C
|
||||
DEVICE_DTS := rockchip/rk3528-radxa-e24c
|
||||
UBOOT_DEVICE_NAME := radxa-e20c-rk3528
|
||||
IMAGE/sysupgrade.img.gz := boot-common | boot-script rk3528 | pine64-img | gzip | append-metadata
|
||||
DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-dsa-rtl8365mb -urngd
|
||||
endef
|
||||
TARGET_DEVICES += radxa_e24c
|
||||
|
||||
define Device/radxa_e25
|
||||
DEVICE_VENDOR := Radxa
|
||||
DEVICE_MODEL := E25
|
||||
@@ -435,6 +445,26 @@ define Device/radxa_e25
|
||||
endef
|
||||
TARGET_DEVICES += radxa_e25
|
||||
|
||||
define Device/radxa_e52c
|
||||
DEVICE_VENDOR := Radxa
|
||||
DEVICE_MODEL := E52C
|
||||
DEVICE_DTS := rockchip/rk3582-radxa-e52c
|
||||
UBOOT_DEVICE_NAME := generic-rk3588
|
||||
IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata
|
||||
DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-r8125-rss
|
||||
endef
|
||||
TARGET_DEVICES += radxa_e52c
|
||||
|
||||
define Device/radxa_e54c
|
||||
DEVICE_VENDOR := Radxa
|
||||
DEVICE_MODEL := E54C
|
||||
DEVICE_DTS := rockchip/rk3582-radxa-e54c
|
||||
UBOOT_DEVICE_NAME := generic-rk3588
|
||||
IMAGE/sysupgrade.img.gz := boot-common | boot-script | pine64-img | gzip | append-metadata
|
||||
DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-dsa-rtl8365mb
|
||||
endef
|
||||
TARGET_DEVICES += radxa_e54c
|
||||
|
||||
define Device/radxa_rock-3a
|
||||
DEVICE_VENDOR := Radxa
|
||||
DEVICE_MODEL := ROCK 3A
|
||||
|
||||
@@ -28,15 +28,16 @@ type Mieru struct {
|
||||
|
||||
type MieruOption struct {
|
||||
BasicOption
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port,omitempty"`
|
||||
PortRange string `proxy:"port-range,omitempty"`
|
||||
Transport string `proxy:"transport"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
UserName string `proxy:"username"`
|
||||
Password string `proxy:"password"`
|
||||
Multiplexing string `proxy:"multiplexing,omitempty"`
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port,omitempty"`
|
||||
PortRange string `proxy:"port-range,omitempty"`
|
||||
Transport string `proxy:"transport"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
UserName string `proxy:"username"`
|
||||
Password string `proxy:"password"`
|
||||
Multiplexing string `proxy:"multiplexing,omitempty"`
|
||||
HandshakeMode string `proxy:"handshake-mode,omitempty"`
|
||||
}
|
||||
|
||||
// DialContext implements C.ProxyAdapter
|
||||
@@ -245,6 +246,9 @@ func buildMieruClientConfig(option MieruOption) (*mieruclient.ClientConfig, erro
|
||||
Level: mierupb.MultiplexingLevel(multiplexing).Enum(),
|
||||
}
|
||||
}
|
||||
if handshakeMode, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; ok {
|
||||
config.Profile.HandshakeMode = (*mierupb.HandshakeMode)(&handshakeMode)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -294,6 +298,11 @@ func validateMieruOption(option MieruOption) error {
|
||||
return fmt.Errorf("invalid multiplexing level: %s", option.Multiplexing)
|
||||
}
|
||||
}
|
||||
if option.HandshakeMode != "" {
|
||||
if _, ok := mierupb.HandshakeMode_value[option.HandshakeMode]; !ok {
|
||||
return fmt.Errorf("invalid handshake mode: %s", option.HandshakeMode)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -933,6 +933,8 @@ proxies: # socks5
|
||||
password: password
|
||||
# 可以使用的值包括 MULTIPLEXING_OFF, MULTIPLEXING_LOW, MULTIPLEXING_MIDDLE, MULTIPLEXING_HIGH。其中 MULTIPLEXING_OFF 会关闭多路复用功能。默认值为 MULTIPLEXING_LOW。
|
||||
# multiplexing: MULTIPLEXING_LOW
|
||||
# 如果想开启 0-RTT 握手,请设置为 HANDSHAKE_NO_WAIT,否则请设置为 HANDSHAKE_STANDARD。默认值为 HANDSHAKE_STANDARD
|
||||
# handshake-mode: HANDSHAKE_STANDARD
|
||||
|
||||
# anytls
|
||||
- name: anytls
|
||||
@@ -1475,6 +1477,7 @@ listeners:
|
||||
# masquerade: http://127.0.0.1:8080 #作为反向代理
|
||||
# masquerade: https://127.0.0.1:8080 #作为反向代理
|
||||
|
||||
# 注意,listeners中的tun仅提供给高级用户使用,普通用户应使用顶层配置中的tun
|
||||
- name: tun-in-1
|
||||
type: tun
|
||||
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ require (
|
||||
github.com/bahlo/generic-list-go v0.2.0
|
||||
github.com/coreos/go-iptables v0.8.0
|
||||
github.com/dlclark/regexp2 v1.11.5
|
||||
github.com/enfein/mieru/v3 v3.16.1
|
||||
github.com/enfein/mieru/v3 v3.19.0
|
||||
github.com/go-chi/chi/v5 v5.2.2
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gobwas/ws v1.4.0
|
||||
@@ -31,7 +31,7 @@ require (
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
|
||||
github.com/metacubex/sing-tun v0.4.7
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
|
||||
+4
-4
@@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
|
||||
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/enfein/mieru/v3 v3.19.0 h1:GXUTWoWmr8pTqGSTbh82VXfnCENJm6m5UN76c3Ynzfw=
|
||||
github.com/enfein/mieru/v3 v3.19.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
|
||||
@@ -131,8 +131,8 @@ github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MY
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
|
||||
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd h1:VfD6UxKPAg7u9rPyxl18lQkpE9s8dZq0u2cPAgQShWs=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250817075824-5e05f123ccdd/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db h1:W7VKxR0r5IR+56Lblx2iyrEaykx0esdQwTQbkSrSaek=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250819151326-51d195aac5db/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
|
||||
@@ -113,3 +113,11 @@ func (c realityConnWrapper) Upstream() any {
|
||||
func (c realityConnWrapper) CloseWrite() error {
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
func (c realityConnWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c realityConnWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -25,11 +25,12 @@ import (
|
||||
"github.com/metacubex/sing-vmess/vless"
|
||||
"github.com/metacubex/sing/common"
|
||||
"github.com/metacubex/sing/common/metadata"
|
||||
"github.com/metacubex/sing/common/network"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*reality.Conn](conn) // *utls.Conn
|
||||
tlsConn, loaded := network.CastReader[*reality.Conn](conn) // *utls.Conn
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -37,7 +38,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*tlsC.UConn](conn) // *utls.UConn
|
||||
tlsConn, loaded := network.CastReader[*tlsC.UConn](conn) // *utls.UConn
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*encryption.ClientConn](conn)
|
||||
tlsConn, loaded := network.CastReader[*encryption.ClientConn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
@@ -53,7 +54,7 @@ func init() {
|
||||
})
|
||||
|
||||
vless.RegisterTLS(func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer unsafe.Pointer) {
|
||||
tlsConn, loaded := common.Cast[*encryption.ServerConn](conn)
|
||||
tlsConn, loaded := network.CastReader[*encryption.ServerConn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hash256 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash256[:])
|
||||
hash32 := sha3.Sum256(nfsEKeyBytes)
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(nfsEKeyBytes)
|
||||
i.xorKey = xorKey[:]
|
||||
@@ -79,7 +79,7 @@ func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Dura
|
||||
return
|
||||
}
|
||||
|
||||
func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
func (i *ClientInstance) Handshake(conn net.Conn) (*ClientConn, error) {
|
||||
if i.nfsEKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/bfe4820f2f086daf639b1957eb23dc13c843cad1
|
||||
// https://github.com/XTLS/Xray-core/commit/d1fb48521271251a8c74bd64fcc2fc8700717a3b
|
||||
// https://github.com/XTLS/Xray-core/commit/49580705f6029648399304b816a2737f991582a8
|
||||
// https://github.com/XTLS/Xray-core/commit/84835bec7d0d8555d0dd30953ed26a272de814c4
|
||||
package encryption
|
||||
|
||||
@@ -54,8 +54,8 @@ func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Durat
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hash256 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash256[:])
|
||||
hash32 := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
copy(i.hash11[:], hash32[:])
|
||||
if xor > 0 {
|
||||
xorKey := sha3.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||
i.xorKey = xorKey[:]
|
||||
@@ -91,7 +91,7 @@ func (i *ServerInstance) Close() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
||||
func (i *ServerInstance) Handshake(conn net.Conn) (*ServerConn, error) {
|
||||
if i.nfsDKey == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
l += 10
|
||||
if t == 0 {
|
||||
c.out_after0 = true
|
||||
c.out_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
c.ctr.XORKeyStream(b[:l], b[:l]) // caller MUST discard b
|
||||
@@ -77,7 +78,7 @@ func (c *XorConn) Write(b []byte) (int, error) { // whole one/two records
|
||||
break
|
||||
}
|
||||
_, c.out_skip, _ = DecodeHeader(append(c.out_header, p[:need]...))
|
||||
c.out_header = make([]byte, 0, 5) // DO NOT CHANGE
|
||||
c.out_header = c.out_header[:0]
|
||||
c.ctr.XORKeyStream(p[:need], p[:need])
|
||||
p = p[need:]
|
||||
}
|
||||
@@ -116,6 +117,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
c.isHeader = false
|
||||
if t == 0 {
|
||||
c.in_after0 = true
|
||||
c.in_header = make([]byte, 0, 5) // important
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -139,7 +141,7 @@ func (c *XorConn) Read(b []byte) (int, error) { // 5-bytes, data, 5-bytes...
|
||||
}
|
||||
c.peerCtr.XORKeyStream(p[:need], p[:need])
|
||||
_, c.in_skip, _ = DecodeHeader(append(c.in_header, p[:need]...))
|
||||
c.in_header = make([]byte, 0, 5) // DO NOT CHANGE
|
||||
c.in_header = c.in_header[:0]
|
||||
p = p[need:]
|
||||
}
|
||||
return n, err
|
||||
|
||||
Generated
+7
-5
@@ -1510,13 +1510,14 @@ checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"futures-core",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
@@ -1524,6 +1525,7 @@ dependencies = [
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
@@ -3231,9 +3233,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.142"
|
||||
version = "1.0.143"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
|
||||
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
||||
Vendored
+1
-18
@@ -149,7 +149,7 @@ jobs:
|
||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale'
|
||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
||||
- name: Build
|
||||
if: matrix.os != 'darwin' && matrix.os != 'android'
|
||||
if: matrix.os != 'android'
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
mkdir -p dist
|
||||
@@ -165,23 +165,6 @@ jobs:
|
||||
GOMIPS: ${{ matrix.gomips }}
|
||||
GOMIPS64: ${{ matrix.gomips }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build darwin
|
||||
if: matrix.os == 'darwin'
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
mkdir -p dist
|
||||
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0' \
|
||||
./cmd/sing-box
|
||||
env:
|
||||
CGO_ENABLED: "0"
|
||||
GOOS: ${{ matrix.os }}
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
GO386: ${{ matrix.go386 }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
GOMIPS: ${{ matrix.gomips }}
|
||||
GOMIPS64: ${{ matrix.gomips }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Android
|
||||
if: matrix.os == 'android'
|
||||
run: |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
VERSION_CODE=552
|
||||
VERSION_CODE=554
|
||||
VERSION_NAME=1.12.2
|
||||
GO_VERSION=go1.25.0
|
||||
|
||||
@@ -46,7 +46,7 @@ var (
|
||||
sharedFlags []string
|
||||
debugFlags []string
|
||||
sharedTags []string
|
||||
darwinTags []string
|
||||
macOSTags []string
|
||||
memcTags []string
|
||||
notMemcTags []string
|
||||
debugTags []string
|
||||
@@ -59,11 +59,11 @@ func init() {
|
||||
if err != nil {
|
||||
currentTag = "unknown"
|
||||
}
|
||||
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid= -checklinkname=0")
|
||||
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+"-s -w -buildid= -checklinkname=0")
|
||||
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=")
|
||||
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
|
||||
|
||||
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api", "with_conntrack")
|
||||
darwinTags = append(darwinTags, "with_dhcp")
|
||||
macOSTags = append(macOSTags, "with_dhcp")
|
||||
memcTags = append(memcTags, "with_tailscale")
|
||||
notMemcTags = append(notMemcTags, "with_low_memory")
|
||||
debugTags = append(debugTags, "debug")
|
||||
@@ -106,17 +106,19 @@ func buildAndroid() {
|
||||
"-libname=box",
|
||||
}
|
||||
|
||||
if !debugEnabled {
|
||||
sharedFlags[3] = sharedFlags[3] + " -checklinkname=0"
|
||||
args = append(args, sharedFlags...)
|
||||
} else {
|
||||
debugFlags[1] = debugFlags[1] + " -checklinkname=0"
|
||||
args = append(args, debugFlags...)
|
||||
}
|
||||
|
||||
tags := append(sharedTags, memcTags...)
|
||||
if debugEnabled {
|
||||
tags = append(tags, debugTags...)
|
||||
}
|
||||
|
||||
if !debugEnabled {
|
||||
args = append(args, sharedFlags...)
|
||||
} else {
|
||||
args = append(args, debugFlags...)
|
||||
}
|
||||
|
||||
args = append(args, "-tags", strings.Join(tags, ","))
|
||||
args = append(args, "./experimental/libbox")
|
||||
|
||||
@@ -158,7 +160,9 @@ func buildApple() {
|
||||
"-tags-not-macos=with_low_memory",
|
||||
}
|
||||
if !withTailscale {
|
||||
args = append(args, "-tags-macos="+strings.Join(memcTags, ","))
|
||||
args = append(args, "-tags-macos="+strings.Join(append(macOSTags, memcTags...), ","))
|
||||
} else {
|
||||
args = append(args, "-tags-macos="+strings.Join(macOSTags, ","))
|
||||
}
|
||||
|
||||
if !debugEnabled {
|
||||
@@ -167,7 +171,7 @@ func buildApple() {
|
||||
args = append(args, debugFlags...)
|
||||
}
|
||||
|
||||
tags := append(sharedTags, darwinTags...)
|
||||
tags := sharedTags
|
||||
if withTailscale {
|
||||
tags = append(tags, memcTags...)
|
||||
}
|
||||
|
||||
@@ -206,3 +206,11 @@ func (c *realityConnWrapper) Upstream() any {
|
||||
func (c *realityConnWrapper) CloseWrite() error {
|
||||
return c.Close()
|
||||
}
|
||||
|
||||
func (c *realityConnWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *realityConnWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -106,6 +106,14 @@ func (c *utlsConnWrapper) Upstream() any {
|
||||
return c.UConn
|
||||
}
|
||||
|
||||
func (c *utlsConnWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *utlsConnWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type utlsALPNWrapper struct {
|
||||
utlsConnWrapper
|
||||
nextProtocols []string
|
||||
|
||||
@@ -293,12 +293,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
|
||||
} else if errors.Is(err, ErrResponseRejected) {
|
||||
rejected = true
|
||||
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
|
||||
/*} else if responseCheck!= nil && errors.Is(err, RcodeError(mDNS.RcodeNameError)) {
|
||||
rejected = true
|
||||
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
|
||||
*/
|
||||
} else if len(message.Question) > 0 {
|
||||
rejected = true
|
||||
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String())))
|
||||
} else {
|
||||
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for <empty query>"))
|
||||
|
||||
@@ -9,10 +9,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/dns/transport"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
@@ -29,6 +27,7 @@ import (
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
mDNS "github.com/miekg/dns"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func RegisterTransport(registry *dns.TransportRegistry) {
|
||||
@@ -45,9 +44,12 @@ type Transport struct {
|
||||
networkManager adapter.NetworkManager
|
||||
interfaceName string
|
||||
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
transports []adapter.DNSTransport
|
||||
updateAccess sync.Mutex
|
||||
transportLock sync.RWMutex
|
||||
updatedAt time.Time
|
||||
servers []M.Socksaddr
|
||||
search []string
|
||||
ndots int
|
||||
attempts int
|
||||
}
|
||||
|
||||
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.DHCPDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
@@ -62,16 +64,28 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
logger: logger,
|
||||
networkManager: service.FromContext[adapter.NetworkManager](ctx),
|
||||
interfaceName: options.Interface,
|
||||
ndots: 1,
|
||||
attempts: 2,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewRawTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) *Transport {
|
||||
return &Transport{
|
||||
TransportAdapter: transportAdapter,
|
||||
ctx: ctx,
|
||||
dialer: dialer,
|
||||
logger: logger,
|
||||
networkManager: service.FromContext[adapter.NetworkManager](ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
err := t.fetchServers()
|
||||
_, err := t.Fetch()
|
||||
if err != nil {
|
||||
return err
|
||||
t.logger.Error(E.Cause(err, "fetch DNS servers"))
|
||||
}
|
||||
if t.interfaceName == "" {
|
||||
t.interfaceCallback = t.networkManager.InterfaceMonitor().RegisterCallback(t.interfaceUpdated)
|
||||
@@ -80,9 +94,6 @@ func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
for _, transport := range t.transports {
|
||||
transport.Close()
|
||||
}
|
||||
if t.interfaceCallback != nil {
|
||||
t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
@@ -90,23 +101,44 @@ func (t *Transport) Close() error {
|
||||
}
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
err := t.fetchServers()
|
||||
servers, err := t.Fetch()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(t.transports) == 0 {
|
||||
if len(servers) == 0 {
|
||||
return nil, E.New("dhcp: empty DNS servers from response")
|
||||
}
|
||||
return t.Exchange0(ctx, message, servers)
|
||||
}
|
||||
|
||||
var response *mDNS.Msg
|
||||
for _, transport := range t.transports {
|
||||
response, err = transport.Exchange(ctx, message)
|
||||
if err == nil {
|
||||
return response, nil
|
||||
}
|
||||
func (t *Transport) Exchange0(ctx context.Context, message *mDNS.Msg, servers []M.Socksaddr) (*mDNS.Msg, error) {
|
||||
question := message.Question[0]
|
||||
domain := dns.FqdnToDomain(question.Name)
|
||||
if len(servers) == 1 || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) {
|
||||
return t.exchangeSingleRequest(ctx, servers, message, domain)
|
||||
} else {
|
||||
return t.exchangeParallel(ctx, servers, message, domain)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (t *Transport) Fetch() ([]M.Socksaddr, error) {
|
||||
t.transportLock.RLock()
|
||||
updatedAt := t.updatedAt
|
||||
servers := t.servers
|
||||
t.transportLock.RUnlock()
|
||||
if time.Since(updatedAt) < C.DHCPTTL {
|
||||
return servers, nil
|
||||
}
|
||||
t.transportLock.Lock()
|
||||
defer t.transportLock.Unlock()
|
||||
if time.Since(t.updatedAt) < C.DHCPTTL {
|
||||
return t.servers, nil
|
||||
}
|
||||
err := t.updateServers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.servers, nil
|
||||
}
|
||||
|
||||
func (t *Transport) fetchInterface() (*control.Interface, error) {
|
||||
@@ -124,18 +156,6 @@ func (t *Transport) fetchInterface() (*control.Interface, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) fetchServers() error {
|
||||
if time.Since(t.updatedAt) < C.DHCPTTL {
|
||||
return nil
|
||||
}
|
||||
t.updateAccess.Lock()
|
||||
defer t.updateAccess.Unlock()
|
||||
if time.Since(t.updatedAt) < C.DHCPTTL {
|
||||
return nil
|
||||
}
|
||||
return t.updateServers()
|
||||
}
|
||||
|
||||
func (t *Transport) updateServers() error {
|
||||
iface, err := t.fetchInterface()
|
||||
if err != nil {
|
||||
@@ -148,7 +168,7 @@ func (t *Transport) updateServers() error {
|
||||
cancel()
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(t.transports) == 0 {
|
||||
} else if len(t.servers) == 0 {
|
||||
return E.New("dhcp: empty DNS servers response")
|
||||
} else {
|
||||
t.updatedAt = time.Now()
|
||||
@@ -177,7 +197,11 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface)
|
||||
}
|
||||
defer packetConn.Close()
|
||||
|
||||
discovery, err := dhcpv4.NewDiscovery(iface.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(dhcpv4.OptionDomainNameServer))
|
||||
discovery, err := dhcpv4.NewDiscovery(iface.HardwareAddr, dhcpv4.WithBroadcast(true), dhcpv4.WithRequestedOptions(
|
||||
dhcpv4.OptionDomainName,
|
||||
dhcpv4.OptionDomainNameServer,
|
||||
dhcpv4.OptionDNSDomainSearchList,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -223,31 +247,23 @@ func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn ne
|
||||
continue
|
||||
}
|
||||
|
||||
dns := dhcpPacket.DNS()
|
||||
if len(dns) == 0 {
|
||||
return nil
|
||||
}
|
||||
return t.recreateServers(iface, common.Map(dns, func(it net.IP) M.Socksaddr {
|
||||
return M.SocksaddrFrom(M.AddrFromIP(it), 53)
|
||||
}))
|
||||
return t.recreateServers(iface, dhcpPacket)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []M.Socksaddr) error {
|
||||
if len(serverAddrs) > 0 {
|
||||
t.logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, M.Socksaddr.String), ","), "]")
|
||||
func (t *Transport) recreateServers(iface *control.Interface, dhcpPacket *dhcpv4.DHCPv4) error {
|
||||
searchList := dhcpPacket.DomainSearch()
|
||||
if searchList != nil && len(searchList.Labels) > 0 {
|
||||
t.search = searchList.Labels
|
||||
} else if dhcpPacket.DomainName() != "" {
|
||||
t.search = []string{dhcpPacket.DomainName()}
|
||||
}
|
||||
serverDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{
|
||||
BindInterface: iface.Name,
|
||||
UDPFragmentDefault: true,
|
||||
}))
|
||||
var transports []adapter.DNSTransport
|
||||
for _, serverAddr := range serverAddrs {
|
||||
transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, serverAddr))
|
||||
serverAddrs := common.Map(dhcpPacket.DNS(), func(it net.IP) M.Socksaddr {
|
||||
return M.SocksaddrFrom(M.AddrFromIP(it), 53)
|
||||
})
|
||||
if len(serverAddrs) > 0 && !slices.Equal(t.servers, serverAddrs) {
|
||||
t.logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, M.Socksaddr.String), ","), "], search: [", strings.Join(t.search, ","), "]")
|
||||
}
|
||||
for _, transport := range t.transports {
|
||||
transport.Close()
|
||||
}
|
||||
t.transports = transports
|
||||
t.servers = serverAddrs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const (
|
||||
// net.maxDNSPacketSize
|
||||
maxDNSPacketSize = 1232
|
||||
)
|
||||
|
||||
func (t *Transport) exchangeSingleRequest(ctx context.Context, servers []M.Socksaddr, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
var lastErr error
|
||||
for _, fqdn := range t.nameList(domain) {
|
||||
response, err := t.tryOneName(ctx, servers, fqdn, message)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeParallel(ctx context.Context, servers []M.Socksaddr, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
returned := make(chan struct{})
|
||||
defer close(returned)
|
||||
type queryResult struct {
|
||||
response *mDNS.Msg
|
||||
err error
|
||||
}
|
||||
results := make(chan queryResult)
|
||||
startRacer := func(ctx context.Context, fqdn string) {
|
||||
response, err := t.tryOneName(ctx, servers, fqdn, message)
|
||||
if err == nil {
|
||||
if response.Rcode != mDNS.RcodeSuccess {
|
||||
err = dns.RcodeError(response.Rcode)
|
||||
} else if len(dns.MessageToAddresses(response)) == 0 {
|
||||
err = E.New(fqdn, ": empty result")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case results <- queryResult{response, err}:
|
||||
case <-returned:
|
||||
}
|
||||
}
|
||||
queryCtx, queryCancel := context.WithCancel(ctx)
|
||||
defer queryCancel()
|
||||
var nameCount int
|
||||
for _, fqdn := range t.nameList(domain) {
|
||||
nameCount++
|
||||
go startRacer(queryCtx, fqdn)
|
||||
}
|
||||
var errors []error
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case result := <-results:
|
||||
if result.err == nil {
|
||||
return result.response, nil
|
||||
}
|
||||
errors = append(errors, result.err)
|
||||
if len(errors) == nameCount {
|
||||
return nil, E.Errors(errors...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) tryOneName(ctx context.Context, servers []M.Socksaddr, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
sLen := len(servers)
|
||||
var lastErr error
|
||||
for i := 0; i < t.attempts; i++ {
|
||||
for j := 0; j < sLen; j++ {
|
||||
server := servers[j%sLen]
|
||||
question := message.Question[0]
|
||||
question.Name = fqdn
|
||||
response, err := t.exchangeOne(ctx, server, question, C.DNSTimeout, false, true)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
return nil, E.Cause(lastErr, fqdn)
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) {
|
||||
if server.Port == 0 {
|
||||
server.Port = 53
|
||||
}
|
||||
var networks []string
|
||||
if useTCP {
|
||||
networks = []string{N.NetworkTCP}
|
||||
} else {
|
||||
networks = []string{N.NetworkUDP, N.NetworkTCP}
|
||||
}
|
||||
request := &mDNS.Msg{
|
||||
MsgHdr: mDNS.MsgHdr{
|
||||
Id: uint16(rand.Uint32()),
|
||||
RecursionDesired: true,
|
||||
AuthenticatedData: ad,
|
||||
},
|
||||
Question: []mDNS.Question{question},
|
||||
Compress: true,
|
||||
}
|
||||
request.SetEdns0(maxDNSPacketSize, false)
|
||||
buffer := buf.Get(buf.UDPBufferSize)
|
||||
defer buf.Put(buffer)
|
||||
for _, network := range networks {
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
defer cancel()
|
||||
conn, err := t.dialer.DialContext(ctx, network, server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() {
|
||||
conn.SetDeadline(deadline)
|
||||
}
|
||||
rawMessage, err := request.PackBuffer(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "pack request")
|
||||
}
|
||||
_, err = conn.Write(rawMessage)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "write request")
|
||||
}
|
||||
n, err := conn.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read response")
|
||||
}
|
||||
var response mDNS.Msg
|
||||
err = response.Unpack(buffer[:n])
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "unpack response")
|
||||
}
|
||||
if response.Truncated && network == N.NetworkUDP {
|
||||
continue
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
panic("unexpected")
|
||||
}
|
||||
|
||||
func (t *Transport) nameList(name string) []string {
|
||||
l := len(name)
|
||||
rooted := l > 0 && name[l-1] == '.'
|
||||
if l > 254 || l == 254 && !rooted {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rooted {
|
||||
if avoidDNS(name) {
|
||||
return nil
|
||||
}
|
||||
return []string{name}
|
||||
}
|
||||
|
||||
hasNdots := strings.Count(name, ".") >= t.ndots
|
||||
name += "."
|
||||
// l++
|
||||
|
||||
names := make([]string, 0, 1+len(t.search))
|
||||
if hasNdots && !avoidDNS(name) {
|
||||
names = append(names, name)
|
||||
}
|
||||
for _, suffix := range t.search {
|
||||
fqdn := name + suffix
|
||||
if !avoidDNS(fqdn) && len(fqdn) <= 254 {
|
||||
names = append(names, fqdn)
|
||||
}
|
||||
}
|
||||
if !hasNdots && !avoidDNS(name) {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func avoidDNS(name string) bool {
|
||||
if name == "" {
|
||||
return true
|
||||
}
|
||||
if name[len(name)-1] == '.' {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
return strings.HasSuffix(name, ".onion")
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
//go:build !darwin
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
@@ -11,10 +11,8 @@ import (
|
||||
"github.com/sagernet/sing-box/dns/transport/hosts"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
@@ -37,9 +35,6 @@ type Transport struct {
|
||||
}
|
||||
|
||||
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
if C.IsDarwin && !options.PreferGo {
|
||||
return NewResolvTransport(ctx, logger, tag)
|
||||
}
|
||||
transportDialer, err := dns.NewLocalDialer(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -94,147 +89,5 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
}
|
||||
}
|
||||
systemConfig := getSystemDNSConfig(t.ctx)
|
||||
if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) {
|
||||
return t.exchangeSingleRequest(ctx, systemConfig, message, domain)
|
||||
} else {
|
||||
return t.exchangeParallel(ctx, systemConfig, message, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
var lastErr error
|
||||
for _, fqdn := range systemConfig.nameList(domain) {
|
||||
response, err := t.tryOneName(ctx, systemConfig, fqdn, message)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
returned := make(chan struct{})
|
||||
defer close(returned)
|
||||
type queryResult struct {
|
||||
response *mDNS.Msg
|
||||
err error
|
||||
}
|
||||
results := make(chan queryResult)
|
||||
startRacer := func(ctx context.Context, fqdn string) {
|
||||
response, err := t.tryOneName(ctx, systemConfig, fqdn, message)
|
||||
if err == nil {
|
||||
if response.Rcode != mDNS.RcodeSuccess {
|
||||
err = dns.RcodeError(response.Rcode)
|
||||
} else if len(dns.MessageToAddresses(response)) == 0 {
|
||||
err = E.New(fqdn, ": empty result")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case results <- queryResult{response, err}:
|
||||
case <-returned:
|
||||
}
|
||||
}
|
||||
queryCtx, queryCancel := context.WithCancel(ctx)
|
||||
defer queryCancel()
|
||||
var nameCount int
|
||||
for _, fqdn := range systemConfig.nameList(domain) {
|
||||
nameCount++
|
||||
go startRacer(queryCtx, fqdn)
|
||||
}
|
||||
var errors []error
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case result := <-results:
|
||||
if result.err == nil {
|
||||
return result.response, nil
|
||||
}
|
||||
errors = append(errors, result.err)
|
||||
if len(errors) == nameCount {
|
||||
return nil, E.Errors(errors...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
serverOffset := config.serverOffset()
|
||||
sLen := uint32(len(config.servers))
|
||||
var lastErr error
|
||||
for i := 0; i < config.attempts; i++ {
|
||||
for j := uint32(0); j < sLen; j++ {
|
||||
server := config.servers[(serverOffset+j)%sLen]
|
||||
question := message.Question[0]
|
||||
question.Name = fqdn
|
||||
response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
return nil, E.Cause(lastErr, fqdn)
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) {
|
||||
if server.Port == 0 {
|
||||
server.Port = 53
|
||||
}
|
||||
var networks []string
|
||||
if useTCP {
|
||||
networks = []string{N.NetworkTCP}
|
||||
} else {
|
||||
networks = []string{N.NetworkUDP, N.NetworkTCP}
|
||||
}
|
||||
request := &mDNS.Msg{
|
||||
MsgHdr: mDNS.MsgHdr{
|
||||
Id: uint16(rand.Uint32()),
|
||||
RecursionDesired: true,
|
||||
AuthenticatedData: ad,
|
||||
},
|
||||
Question: []mDNS.Question{question},
|
||||
Compress: true,
|
||||
}
|
||||
request.SetEdns0(maxDNSPacketSize, false)
|
||||
buffer := buf.Get(buf.UDPBufferSize)
|
||||
defer buf.Put(buffer)
|
||||
for _, network := range networks {
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
defer cancel()
|
||||
conn, err := t.dialer.DialContext(ctx, network, server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() {
|
||||
conn.SetDeadline(deadline)
|
||||
}
|
||||
rawMessage, err := request.PackBuffer(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "pack request")
|
||||
}
|
||||
_, err = conn.Write(rawMessage)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "write request")
|
||||
}
|
||||
n, err := conn.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read response")
|
||||
}
|
||||
var response mDNS.Msg
|
||||
err = response.Unpack(buffer[:n])
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "unpack response")
|
||||
}
|
||||
if response.Truncated && network == N.NetworkUDP {
|
||||
continue
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
panic("unexpected")
|
||||
return t.exchange(ctx, message, domain)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
//go:build darwin
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/dns/transport/hosts"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func RegisterTransport(registry *dns.TransportRegistry) {
|
||||
dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport)
|
||||
}
|
||||
|
||||
var _ adapter.DNSTransport = (*Transport)(nil)
|
||||
|
||||
type Transport struct {
|
||||
dns.TransportAdapter
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
hosts *hosts.File
|
||||
dialer N.Dialer
|
||||
preferGo bool
|
||||
fallback bool
|
||||
dhcpTransport dhcpTransport
|
||||
resolver net.Resolver
|
||||
}
|
||||
|
||||
type dhcpTransport interface {
|
||||
adapter.DNSTransport
|
||||
Fetch() ([]M.Socksaddr, error)
|
||||
Exchange0(ctx context.Context, message *mDNS.Msg, servers []M.Socksaddr) (*mDNS.Msg, error)
|
||||
}
|
||||
|
||||
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
transportDialer, err := dns.NewLocalDialer(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transportAdapter := dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options)
|
||||
return &Transport{
|
||||
TransportAdapter: transportAdapter,
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
hosts: hosts.NewFile(hosts.DefaultPath),
|
||||
dialer: transportDialer,
|
||||
preferGo: options.PreferGo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
inboundManager := service.FromContext[adapter.InboundManager](t.ctx)
|
||||
for _, inbound := range inboundManager.Inbounds() {
|
||||
if inbound.Type() == C.TypeTun {
|
||||
t.fallback = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !C.IsIos {
|
||||
if t.fallback {
|
||||
t.dhcpTransport = newDHCPTransport(t.TransportAdapter, log.ContextWithOverrideLevel(t.ctx, log.LevelDebug), t.dialer, t.logger)
|
||||
if t.dhcpTransport != nil {
|
||||
err := t.dhcpTransport.Start(stage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
return common.Close(
|
||||
t.dhcpTransport,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
question := message.Question[0]
|
||||
domain := dns.FqdnToDomain(question.Name)
|
||||
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
|
||||
addresses := t.hosts.Lookup(domain)
|
||||
if len(addresses) > 0 {
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
}
|
||||
}
|
||||
if !t.fallback {
|
||||
return t.exchange(ctx, message, domain)
|
||||
}
|
||||
if !C.IsIos {
|
||||
if t.dhcpTransport != nil {
|
||||
dhcpTransports, _ := t.dhcpTransport.Fetch()
|
||||
if len(dhcpTransports) > 0 {
|
||||
return t.dhcpTransport.Exchange0(ctx, message, dhcpTransports)
|
||||
}
|
||||
}
|
||||
}
|
||||
if t.preferGo {
|
||||
// Assuming the user knows what they are doing, we still execute the query which will fail.
|
||||
return t.exchange(ctx, message, domain)
|
||||
}
|
||||
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
|
||||
var network string
|
||||
if question.Qtype == mDNS.TypeA {
|
||||
network = "ip4"
|
||||
} else {
|
||||
network = "ip6"
|
||||
}
|
||||
addresses, err := t.resolver.LookupNetIP(ctx, network, domain)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
return nil, dns.RcodeRefused
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
}
|
||||
if C.IsIos {
|
||||
return nil, E.New("only A and AAAA queries are supported on iOS and tvOS when using NetworkExtension.")
|
||||
} else {
|
||||
return nil, E.New("only A and AAAA queries are supported on macOS when using NetworkExtension and DHCP unavailable.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build darwin && with_dhcp
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/dns/transport/dhcp"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func newDHCPTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) dhcpTransport {
|
||||
return dhcp.NewRawTransport(transportAdapter, ctx, dialer, logger)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//go:build darwin && !with_dhcp
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func newDHCPTransport(transportAdapter dns.TransportAdapter, ctx context.Context, dialer N.Dialer, logger log.ContextLogger) dhcpTransport {
|
||||
return nil
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
//go:build darwin
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var _ adapter.DNSTransport = (*ResolvTransport)(nil)
|
||||
|
||||
type ResolvTransport struct {
|
||||
dns.TransportAdapter
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
}
|
||||
|
||||
func NewResolvTransport(ctx context.Context, logger log.ContextLogger, tag string) (adapter.DNSTransport, error) {
|
||||
return &ResolvTransport{
|
||||
TransportAdapter: dns.NewTransportAdapter(C.DNSTypeLocal, tag, nil),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *ResolvTransport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ResolvTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ResolvTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
question := message.Question[0]
|
||||
return doBlockingWithCtx(ctx, func() (*mDNS.Msg, error) {
|
||||
return cgoResSearch(question.Name, int(question.Qtype), int(question.Qclass))
|
||||
})
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
_ "unsafe"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type (
|
||||
_C_char = byte
|
||||
_C_int = int32
|
||||
_C_uchar = byte
|
||||
_C_ushort = uint16
|
||||
_C_uint = uint32
|
||||
_C_ulong = uint64
|
||||
_C_struct___res_state = ResState
|
||||
_C_struct_sockaddr = syscall.RawSockaddr
|
||||
)
|
||||
|
||||
func _C_free(p unsafe.Pointer) { runtime.KeepAlive(p) }
|
||||
|
||||
func _C_malloc(n uintptr) unsafe.Pointer {
|
||||
if n <= 0 {
|
||||
n = 1
|
||||
}
|
||||
return unsafe.Pointer(&make([]byte, n)[0])
|
||||
}
|
||||
|
||||
const (
|
||||
MAXNS = 3
|
||||
MAXDNSRCH = 6
|
||||
)
|
||||
|
||||
type ResState struct {
|
||||
Retrans _C_int
|
||||
Retry _C_int
|
||||
Options _C_ulong
|
||||
Nscount _C_int
|
||||
Nsaddrlist [MAXNS]_C_struct_sockaddr
|
||||
Id _C_ushort
|
||||
Dnsrch [MAXDNSRCH + 1]*_C_char
|
||||
Defname [256]_C_char
|
||||
Pfcode _C_ulong
|
||||
Ndots _C_uint
|
||||
Nsort _C_uint
|
||||
stub [128]byte
|
||||
}
|
||||
|
||||
//go:linkname ResNinit internal/syscall/unix.ResNinit
|
||||
func ResNinit(state *_C_struct___res_state) error
|
||||
|
||||
//go:linkname ResNsearch internal/syscall/unix.ResNsearch
|
||||
func ResNsearch(state *_C_struct___res_state, dname *byte, class, typ int, ans *byte, anslen int) (int, error)
|
||||
|
||||
//go:linkname ResNclose internal/syscall/unix.ResNclose
|
||||
func ResNclose(state *_C_struct___res_state)
|
||||
|
||||
//go:linkname GoString internal/syscall/unix.GoString
|
||||
func GoString(p *byte) string
|
||||
|
||||
// doBlockingWithCtx executes a blocking function in a separate goroutine when the provided
|
||||
// context is cancellable. It is intended for use with calls that don't support context
|
||||
// cancellation (cgo, syscalls). blocking func may still be running after this function finishes.
|
||||
// For the duration of the execution of the blocking function, the thread is 'acquired' using [acquireThread],
|
||||
// blocking might not be executed when the context gets canceled early.
|
||||
func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) (T, error) {
|
||||
if err := acquireThread(ctx); err != nil {
|
||||
var zero T
|
||||
return zero, err
|
||||
}
|
||||
|
||||
if ctx.Done() == nil {
|
||||
defer releaseThread()
|
||||
return blocking()
|
||||
}
|
||||
|
||||
type result struct {
|
||||
res T
|
||||
err error
|
||||
}
|
||||
|
||||
res := make(chan result, 1)
|
||||
go func() {
|
||||
defer releaseThread()
|
||||
var r result
|
||||
r.res, r.err = blocking()
|
||||
res <- r
|
||||
}()
|
||||
|
||||
select {
|
||||
case r := <-res:
|
||||
return r.res, r.err
|
||||
case <-ctx.Done():
|
||||
var zero T
|
||||
return zero, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname acquireThread net.acquireThread
|
||||
func acquireThread(ctx context.Context) error
|
||||
|
||||
//go:linkname releaseThread net.releaseThread
|
||||
func releaseThread()
|
||||
|
||||
func cgoResSearch(hostname string, rtype, class int) (*mDNS.Msg, error) {
|
||||
resStateSize := unsafe.Sizeof(_C_struct___res_state{})
|
||||
var state *_C_struct___res_state
|
||||
if resStateSize > 0 {
|
||||
mem := _C_malloc(resStateSize)
|
||||
defer _C_free(mem)
|
||||
memSlice := unsafe.Slice((*byte)(mem), resStateSize)
|
||||
clear(memSlice)
|
||||
state = (*_C_struct___res_state)(unsafe.Pointer(&memSlice[0]))
|
||||
}
|
||||
if err := ResNinit(state); err != nil {
|
||||
return nil, errors.New("res_ninit failure: " + err.Error())
|
||||
}
|
||||
defer ResNclose(state)
|
||||
|
||||
bufSize := maxDNSPacketSize
|
||||
buf := (*_C_uchar)(_C_malloc(uintptr(bufSize)))
|
||||
defer _C_free(unsafe.Pointer(buf))
|
||||
|
||||
s, err := syscall.BytePtrFromString(hostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var size int
|
||||
for {
|
||||
size, _ = ResNsearch(state, s, class, rtype, buf, bufSize)
|
||||
if size <= bufSize || size > 0xffff {
|
||||
break
|
||||
}
|
||||
|
||||
// Allocate a bigger buffer to fit the entire msg.
|
||||
_C_free(unsafe.Pointer(buf))
|
||||
bufSize = size
|
||||
buf = (*_C_uchar)(_C_malloc(uintptr(bufSize)))
|
||||
}
|
||||
|
||||
var msg mDNS.Msg
|
||||
if size == -1 {
|
||||
// macOS's libresolv seems to directly return -1 for responses that are not success responses but are exchanged.
|
||||
// However, we still need the response, so we fall back to parsing the entire buffer.
|
||||
err = msg.Unpack(unsafe.Slice(buf, bufSize))
|
||||
if err != nil {
|
||||
return nil, E.New("res_nsearch failure")
|
||||
}
|
||||
} else {
|
||||
err = msg.Unpack(unsafe.Slice(buf, size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &msg, nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
//go:build !darwin
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
func NewResolvTransport(ctx context.Context, logger log.ContextLogger, tag string) (adapter.DNSTransport, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func (t *Transport) exchange(ctx context.Context, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
systemConfig := getSystemDNSConfig(t.ctx)
|
||||
if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) {
|
||||
return t.exchangeSingleRequest(ctx, systemConfig, message, domain)
|
||||
} else {
|
||||
return t.exchangeParallel(ctx, systemConfig, message, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeSingleRequest(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
var lastErr error
|
||||
for _, fqdn := range systemConfig.nameList(domain) {
|
||||
response, err := t.tryOneName(ctx, systemConfig, fqdn, message)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfig, message *mDNS.Msg, domain string) (*mDNS.Msg, error) {
|
||||
returned := make(chan struct{})
|
||||
defer close(returned)
|
||||
type queryResult struct {
|
||||
response *mDNS.Msg
|
||||
err error
|
||||
}
|
||||
results := make(chan queryResult)
|
||||
startRacer := func(ctx context.Context, fqdn string) {
|
||||
response, err := t.tryOneName(ctx, systemConfig, fqdn, message)
|
||||
if err == nil {
|
||||
if response.Rcode != mDNS.RcodeSuccess {
|
||||
err = dns.RcodeError(response.Rcode)
|
||||
} else if len(dns.MessageToAddresses(response)) == 0 {
|
||||
err = E.New(fqdn, ": empty result")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case results <- queryResult{response, err}:
|
||||
case <-returned:
|
||||
}
|
||||
}
|
||||
queryCtx, queryCancel := context.WithCancel(ctx)
|
||||
defer queryCancel()
|
||||
var nameCount int
|
||||
for _, fqdn := range systemConfig.nameList(domain) {
|
||||
nameCount++
|
||||
go startRacer(queryCtx, fqdn)
|
||||
}
|
||||
var errors []error
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case result := <-results:
|
||||
if result.err == nil {
|
||||
return result.response, nil
|
||||
}
|
||||
errors = append(errors, result.err)
|
||||
if len(errors) == nameCount {
|
||||
return nil, E.Errors(errors...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn string, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
serverOffset := config.serverOffset()
|
||||
sLen := uint32(len(config.servers))
|
||||
var lastErr error
|
||||
for i := 0; i < config.attempts; i++ {
|
||||
for j := uint32(0); j < sLen; j++ {
|
||||
server := config.servers[(serverOffset+j)%sLen]
|
||||
question := message.Question[0]
|
||||
question.Name = fqdn
|
||||
response, err := t.exchangeOne(ctx, M.ParseSocksaddr(server), question, config.timeout, config.useTCP, config.trustAD)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
return nil, E.Cause(lastErr, fqdn)
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeOne(ctx context.Context, server M.Socksaddr, question mDNS.Question, timeout time.Duration, useTCP, ad bool) (*mDNS.Msg, error) {
|
||||
if server.Port == 0 {
|
||||
server.Port = 53
|
||||
}
|
||||
var networks []string
|
||||
if useTCP {
|
||||
networks = []string{N.NetworkTCP}
|
||||
} else {
|
||||
networks = []string{N.NetworkUDP, N.NetworkTCP}
|
||||
}
|
||||
request := &mDNS.Msg{
|
||||
MsgHdr: mDNS.MsgHdr{
|
||||
Id: uint16(rand.Uint32()),
|
||||
RecursionDesired: true,
|
||||
AuthenticatedData: ad,
|
||||
},
|
||||
Question: []mDNS.Question{question},
|
||||
Compress: true,
|
||||
}
|
||||
request.SetEdns0(maxDNSPacketSize, false)
|
||||
buffer := buf.Get(buf.UDPBufferSize)
|
||||
defer buf.Put(buffer)
|
||||
for _, network := range networks {
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
defer cancel()
|
||||
conn, err := t.dialer.DialContext(ctx, network, server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
if deadline, loaded := ctx.Deadline(); loaded && !deadline.IsZero() {
|
||||
conn.SetDeadline(deadline)
|
||||
}
|
||||
rawMessage, err := request.PackBuffer(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "pack request")
|
||||
}
|
||||
_, err = conn.Write(rawMessage)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "write request")
|
||||
}
|
||||
n, err := conn.Read(buffer)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read response")
|
||||
}
|
||||
var response mDNS.Msg
|
||||
err = response.Unpack(buffer[:n])
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "unpack response")
|
||||
}
|
||||
if response.Truncated && network == N.NetworkUDP {
|
||||
continue
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
panic("unexpected")
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func dnsReadConfig(_ context.Context, _ string) *dnsConfig {
|
||||
resStateSize := unsafe.Sizeof(_C_struct___res_state{})
|
||||
var state *_C_struct___res_state
|
||||
if resStateSize > 0 {
|
||||
mem := _C_malloc(resStateSize)
|
||||
defer _C_free(mem)
|
||||
memSlice := unsafe.Slice((*byte)(mem), resStateSize)
|
||||
clear(memSlice)
|
||||
state = (*_C_struct___res_state)(unsafe.Pointer(&memSlice[0]))
|
||||
}
|
||||
if err := ResNinit(state); err != nil {
|
||||
return &dnsConfig{
|
||||
servers: defaultNS,
|
||||
search: dnsDefaultSearch(),
|
||||
ndots: 1,
|
||||
timeout: 5 * time.Second,
|
||||
attempts: 2,
|
||||
err: E.Cause(err, "libresolv initialization failed"),
|
||||
}
|
||||
}
|
||||
defer ResNclose(state)
|
||||
conf := &dnsConfig{
|
||||
ndots: 1,
|
||||
timeout: 5 * time.Second,
|
||||
attempts: int(state.Retry),
|
||||
}
|
||||
for i := 0; i < int(state.Nscount); i++ {
|
||||
addr := parseRawSockaddr(&state.Nsaddrlist[i])
|
||||
if addr.IsValid() {
|
||||
conf.servers = append(conf.servers, addr.String())
|
||||
}
|
||||
}
|
||||
for i := 0; ; i++ {
|
||||
search := state.Dnsrch[i]
|
||||
if search == nil {
|
||||
break
|
||||
}
|
||||
name := dns.Fqdn(GoString(search))
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
conf.search = append(conf.search, name)
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
func parseRawSockaddr(rawSockaddr *syscall.RawSockaddr) netip.Addr {
|
||||
switch rawSockaddr.Family {
|
||||
case syscall.AF_INET:
|
||||
sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rawSockaddr))
|
||||
return netip.AddrFrom4(sa.Addr)
|
||||
case syscall.AF_INET6:
|
||||
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rawSockaddr))
|
||||
return netip.AddrFrom16(sa.Addr)
|
||||
default:
|
||||
return netip.Addr{}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !windows && !darwin
|
||||
//go:build !windows
|
||||
|
||||
package local
|
||||
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.13.0-alpha.4
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.0-alpha.3
|
||||
|
||||
* Improve `local` DNS server **1**
|
||||
|
||||
@@ -43,16 +43,18 @@ When enabled, `local` DNS server will resolve DNS by dialing itself whenever pos
|
||||
|
||||
Specifically, it disables following behaviors which was added as features in sing-box 1.13.0:
|
||||
|
||||
* On Apple platforms: Use `libresolv` for resolution, as it is the only one that works properly with NetworkExtension
|
||||
that overrides DNS servers (DHCP is also possible but is not considered).
|
||||
* On Linux: Resolve through `systemd-resolvd`'s DBus interface when available.
|
||||
1. On Apple platforms: Attempt to resolve A/AAAA requests using `getaddrinfo` in NetworkExtension.
|
||||
2. On Linux: Resolve through `systemd-resolvd`'s DBus interface when available.
|
||||
|
||||
As a sole exception, it cannot disable the following behavior:
|
||||
|
||||
In the Android graphical client, the `local` DNS server will always resolve DNS through the platform interface,
|
||||
as there is no other way to obtain upstream DNS servers.
|
||||
1. In the Android graphical client,
|
||||
`local` will always resolve DNS through the platform interface,
|
||||
as there is no other way to obtain upstream DNS servers;
|
||||
On devices running Android versions lower than 10, this interface can only resolve A/AAAA requests.
|
||||
|
||||
On devices running Android versions lower than 10, this interface can only resolve IP queries.
|
||||
2. On macOS, `local` will try DHCP first in Network Extension, since DHCP respects DIal Fields,
|
||||
it will not be disabled by `prefer_go`.
|
||||
|
||||
### Dial Fields
|
||||
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ require (
|
||||
github.com/libdns/alidns v1.0.5-libdns.v1.beta1
|
||||
github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
github.com/metacubex/utls v1.8.0
|
||||
github.com/mholt/acmez/v3 v3.1.2
|
||||
github.com/miekg/dns v1.1.67
|
||||
@@ -34,7 +34,7 @@ require (
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1
|
||||
github.com/sagernet/sing-vmess v0.2.6
|
||||
github.com/sagernet/sing-vmess v0.2.7
|
||||
github.com/sagernet/smux v1.5.34-mod.2
|
||||
github.com/sagernet/tailscale v1.80.3-mod.5
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
||||
|
||||
+4
-4
@@ -122,8 +122,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ
|
||||
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
|
||||
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
|
||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||
@@ -181,8 +181,8 @@ github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ=
|
||||
github.com/sagernet/sing-vmess v0.2.6 h1:1c4dGzeGy0kpBXXrT1sgiMZtHhdJylIT8eWrGhJYZec=
|
||||
github.com/sagernet/sing-vmess v0.2.6/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
|
||||
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=
|
||||
|
||||
@@ -223,6 +223,9 @@ func (e *Endpoint) Close() error {
|
||||
}
|
||||
|
||||
func (e *Endpoint) Lookup(address netip.Addr) *device.Peer {
|
||||
if e.allowedIPs == nil {
|
||||
return nil
|
||||
}
|
||||
return e.allowedIPs.Lookup(address.AsSlice())
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -29,7 +29,7 @@ jobs:
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}-${{ matrix.sdk }}
|
||||
FEEDNAME: packages_ci
|
||||
PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box
|
||||
PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-momo luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box
|
||||
NO_REFRESH_CHECK: true
|
||||
IGNORE_ERRORS: true
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -68,7 +68,7 @@ jobs:
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}-${{ matrix.sdk }}
|
||||
FEEDNAME: packages_ci
|
||||
PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box
|
||||
PACKAGES: luci-app-fchomo luci-app-homeproxy luci-app-momo luci-app-nikki luci-app-openclash luci-app-passwall luci-app-passwall2 luci-app-ssr-plus luci-app-bypass brook hysteria ipt2socks pdnsd-alt redsocks2 shadow-tls trojan tuic-client xray-plugin v2ray-core v2ray-geodata naiveproxy sing-box
|
||||
NO_REFRESH_CHECK: true
|
||||
IGNORE_ERRORS: true
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_VERSION:=1.23.3
|
||||
PKG_VERSION:=1.24.0
|
||||
|
||||
LUCI_TITLE:=LuCI Support for nikki
|
||||
LUCI_DEPENDS:=+luci-base +nikki
|
||||
|
||||
@@ -65,8 +65,6 @@ const appLogPath = `${logDir}/app.log`;
|
||||
const coreLogPath = `${logDir}/core.log`;
|
||||
const debugLogPath = `${logDir}/debug.log`;
|
||||
const nftDir = `${homeDir}/nftables`;
|
||||
const reservedIPNFT = `${nftDir}/reserved_ip.nft`;
|
||||
const reservedIP6NFT = `${nftDir}/reserved_ip6.nft`;
|
||||
|
||||
return baseclass.extend({
|
||||
homeDir: homeDir,
|
||||
@@ -80,8 +78,6 @@ return baseclass.extend({
|
||||
appLogPath: appLogPath,
|
||||
coreLogPath: coreLogPath,
|
||||
debugLogPath: debugLogPath,
|
||||
reservedIPNFT: reservedIPNFT,
|
||||
reservedIP6NFT: reservedIP6NFT,
|
||||
|
||||
status: async function () {
|
||||
return (await callRCList('nikki'))?.nikki?.running;
|
||||
|
||||
@@ -47,8 +47,6 @@ return view.extend({
|
||||
|
||||
o.value(nikki.mixinFilePath, _('File for Mixin'));
|
||||
o.value(nikki.runProfilePath, _('Profile for Startup'));
|
||||
o.value(nikki.reservedIPNFT, _('File for Reserved IP'));
|
||||
o.value(nikki.reservedIP6NFT, _('File for Reserved IP6'));
|
||||
|
||||
o.write = function (section_id, formvalue) {
|
||||
return true;
|
||||
|
||||
@@ -117,10 +117,9 @@ return view.extend({
|
||||
o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD');
|
||||
o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord');
|
||||
|
||||
o = s.taboption('external_control', form.Value, 'api_listen', '*' + ' ' + _('API Listen'));
|
||||
o = s.taboption('external_control', form.Value, 'api_listen', _('API Listen'));
|
||||
o.datatype = 'ipaddrport(1)';
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('external_control', form.Value, 'api_secret', _('API Secret'));
|
||||
o.password = true;
|
||||
@@ -152,15 +151,13 @@ return view.extend({
|
||||
o.datatype = 'port';
|
||||
o.placeholder = _('Unmodified');
|
||||
|
||||
o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port'));
|
||||
o = s.taboption('inbound', form.Value, 'redir_port', _('Redirect Port'));
|
||||
o.datatype = 'port';
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port'));
|
||||
o = s.taboption('inbound', form.Value, 'tproxy_port', _('TPROXY Port'));
|
||||
o.datatype = 'port';
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('inbound', form.Flag, 'authentication', _('Overwrite Authentication'));
|
||||
o.rmempty = false;
|
||||
@@ -185,9 +182,14 @@ return view.extend({
|
||||
|
||||
s.tab('tun', _('TUN Config'));
|
||||
|
||||
o = s.taboption('tun', form.Value, 'tun_device', '*' + ' ' + _('Device Name'));
|
||||
o = s.taboption('tun', form.ListValue, 'tun_enabled', _('Enable'));
|
||||
o.optional = true;
|
||||
o.placeholder = _('Unmodified');
|
||||
o.value('0', _('Disable'));
|
||||
o.value('1', _('Enable'));
|
||||
|
||||
o = s.taboption('tun', form.Value, 'tun_device', _('Device Name'));
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('tun', form.ListValue, 'tun_stack', _('Stack'));
|
||||
o.optional = true;
|
||||
@@ -227,10 +229,15 @@ return view.extend({
|
||||
|
||||
s.tab('dns', _('DNS Config'));
|
||||
|
||||
o = s.taboption('dns', form.Value, 'dns_listen', '*' + ' ' + _('DNS Listen'));
|
||||
o = s.taboption('dns', form.ListValue, 'dns_enabled', _('Enable'));
|
||||
o.optional = true;
|
||||
o.placeholder = _('Unmodified');
|
||||
o.value('0', _('Disable'));
|
||||
o.value('1', _('Enable'));
|
||||
|
||||
o = s.taboption('dns', form.Value, 'dns_listen', _('DNS Listen'));
|
||||
o.datatype = 'ipaddrport(1)';
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('dns', form.ListValue, 'dns_ipv6', 'IPv6');
|
||||
o.optional = true;
|
||||
@@ -238,15 +245,15 @@ return view.extend({
|
||||
o.value('0', _('Disable'));
|
||||
o.value('1', _('Enable'));
|
||||
|
||||
o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode'));
|
||||
o = s.taboption('dns', form.ListValue, 'dns_mode', _('DNS Mode'));
|
||||
o.optional = true;
|
||||
o.placeholder = _('Unmodified');
|
||||
o.value('redir-host', 'Redir-Host');
|
||||
o.value('fake-ip', 'Fake-IP');
|
||||
|
||||
o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range'));
|
||||
o = s.taboption('dns', form.Value, 'fake_ip_range', _('Fake-IP Range'));
|
||||
o.datatype = 'cidr4';
|
||||
o.placeholder = _('Unmodified');
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter'));
|
||||
o.rmempty = false;
|
||||
|
||||
@@ -132,6 +132,7 @@ return view.extend({
|
||||
so.rmempty = false;
|
||||
|
||||
so = o.subsection.option(form.DynamicList, 'ip', 'IP');
|
||||
so.datatype = 'ip4addr';
|
||||
|
||||
for (const mac in hosts) {
|
||||
const host = hosts[mac];
|
||||
@@ -142,6 +143,7 @@ return view.extend({
|
||||
};
|
||||
|
||||
so = o.subsection.option(form.DynamicList, 'ip6', 'IP6');
|
||||
so.datatype = 'ip6addr';
|
||||
|
||||
for (const mac in hosts) {
|
||||
const host = hosts[mac];
|
||||
@@ -152,6 +154,7 @@ return view.extend({
|
||||
};
|
||||
|
||||
so = o.subsection.option(form.DynamicList, 'mac', 'MAC');
|
||||
so.datatype = 'macaddr';
|
||||
|
||||
for (const mac in hosts) {
|
||||
const host = hosts[mac];
|
||||
|
||||
@@ -60,9 +60,10 @@ start_service() {
|
||||
config_get dns_inbound_tag "core" "dns_inbound_tag"
|
||||
config_get fake_ip_dns_server_tag "core" "fake_ip_dns_server_tag"
|
||||
## proxy config
|
||||
local ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode
|
||||
config_get ipv4_dns_hijack "proxy" "ipv4_dns_hijack"
|
||||
config_get ipv6_dns_hijack "proxy" "ipv6_dns_hijack"
|
||||
local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0
|
||||
config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
# get profile
|
||||
@@ -100,11 +101,12 @@ start_service() {
|
||||
return
|
||||
fi
|
||||
# check profile
|
||||
if [ "$core_only" = 0 ]; then
|
||||
if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
|
||||
log "Profile" "Checking..."
|
||||
if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then
|
||||
local dns_port; dns_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$dns_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='direct']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$dns_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "DNS inbound not found, should be tagged with $dns_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
@@ -113,6 +115,7 @@ start_service() {
|
||||
if [ "$tcp_mode" = "redirect" ]; then
|
||||
local redirect_port; redirect_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$redirect_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='redirect']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$redirect_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "Redirect inbound not found, should be tagged with $redirect_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
@@ -121,6 +124,7 @@ start_service() {
|
||||
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
|
||||
local tproxy_port; tproxy_port=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tproxy_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tproxy']" | jsonfilter -q -e "@['listen_port']")
|
||||
if [ -z "$tproxy_port" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TPROXY inbound not found, should be tagged with $tproxy_inbound_tag and define listen_port."
|
||||
log "App" "Exit."
|
||||
return
|
||||
@@ -129,6 +133,7 @@ start_service() {
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
local tun_device; tun_device=$(jsonfilter -q -i "$RUN_PROFILE_PATH" -e "@['inbounds'][*]" | jsonfilter -q -a -e "@[@['tag']='$tun_inbound_tag']" | jsonfilter -q -a -e "@[@['type']='tun']" | jsonfilter -q -e "@['interface_name']")
|
||||
if [ -z "$tun_device" ]; then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TUN inbound not found, should be tagged with $tun_inbound_tag and define interface_name."
|
||||
log "App" "Exit."
|
||||
return
|
||||
|
||||
@@ -27,8 +27,6 @@ DEBUG_SH="$SH_DIR/debug.sh"
|
||||
|
||||
## firewall
|
||||
NFT_DIR="$HOME_DIR/firewall"
|
||||
RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft"
|
||||
RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft"
|
||||
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"
|
||||
GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft"
|
||||
|
||||
@@ -66,8 +64,6 @@ get_paths() {
|
||||
json_add_string debug_sh "$DEBUG_SH"
|
||||
|
||||
json_add_string nft_dir "$NFT_DIR"
|
||||
json_add_string reserved_ip_nft "$RESERVED_IP_NFT"
|
||||
json_add_string reserved_ip6_nft "$RESERVED_IP6_NFT"
|
||||
json_add_string geoip_cn_nft "$GEOIP_CN_NFT"
|
||||
json_add_string geoip6_cn_nft "$GEOIP6_CN_NFT"
|
||||
|
||||
|
||||
@@ -462,19 +462,17 @@ table inet momo {
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta nfproto @proxy_nfproto jump router_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
{% if (fake_ip_range ): %}
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
|
||||
{% endif %}
|
||||
{% if (fake_ip6_range ): %}
|
||||
{% if (fake_ip6_range): %}
|
||||
icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
@@ -493,9 +491,9 @@ table inet momo {
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% endif %}
|
||||
@@ -536,19 +534,17 @@ table inet momo {
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
{% if (fake_ip_range ): %}
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
|
||||
{% endif %}
|
||||
{% if (fake_ip6_range ): %}
|
||||
{% if (fake_ip6_range): %}
|
||||
icmpv6 type echo-request ip6 daddr {{ fake_ip6_range }} counter redirect
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
@@ -562,9 +558,9 @@ table inet momo {
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range ): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp {% if (fake_ip6_range): %} ip6 daddr != {{ fake_ip6_range }} {% endif %} counter return
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% endif %}
|
||||
|
||||
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=nikki
|
||||
PKG_VERSION:=2025.07.27
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
@@ -43,8 +43,6 @@ endef
|
||||
define Package/nikki/conffiles
|
||||
/etc/config/nikki
|
||||
/etc/nikki/mixin.yaml
|
||||
/etc/nikki/nftables/reserved_ip.nft
|
||||
/etc/nikki/nftables/reserved_ip6.nft
|
||||
endef
|
||||
|
||||
define Package/nikki/install
|
||||
@@ -71,8 +69,6 @@ define Package/nikki/install
|
||||
$(INSTALL_BIN) $(CURDIR)/files/scripts/firewall_include.sh $(1)/etc/nikki/scripts/firewall_include.sh
|
||||
$(INSTALL_BIN) $(CURDIR)/files/scripts/debug.sh $(1)/etc/nikki/scripts/debug.sh
|
||||
|
||||
$(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip.nft $(1)/etc/nikki/nftables/reserved_ip.nft
|
||||
$(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip6.nft $(1)/etc/nikki/nftables/reserved_ip6.nft
|
||||
$(INSTALL_BIN) $(CURDIR)/files/nftables/geoip_cn.nft $(1)/etc/nikki/nftables/geoip_cn.nft
|
||||
$(INSTALL_BIN) $(CURDIR)/files/nftables/geoip6_cn.nft $(1)/etc/nikki/nftables/geoip6_cn.nft
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/sbin/nft -f
|
||||
|
||||
table inet nikki {
|
||||
set reserved_ip {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
elements = {
|
||||
0.0.0.0/8,
|
||||
10.0.0.0/8,
|
||||
127.0.0.0/8,
|
||||
100.64.0.0/10,
|
||||
169.254.0.0/16,
|
||||
172.16.0.0/12,
|
||||
192.168.0.0/16,
|
||||
224.0.0.0/4,
|
||||
240.0.0.0/4
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/sbin/nft -f
|
||||
|
||||
table inet nikki {
|
||||
set reserved_ip6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
elements = {
|
||||
::/128,
|
||||
::1/128,
|
||||
::ffff:0:0/96,
|
||||
100::/64,
|
||||
64:ff9b::/96,
|
||||
2001::/32,
|
||||
2001:10::/28,
|
||||
2001:20::/28,
|
||||
2001:db8::/32,
|
||||
2002::/16,
|
||||
fc00::/7,
|
||||
fe80::/10,
|
||||
ff00::/8
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,24 +11,11 @@ config config 'config'
|
||||
option 'fast_reload' '0'
|
||||
option 'core_only' '0'
|
||||
|
||||
config proxy 'proxy'
|
||||
option 'enabled' '1'
|
||||
option 'tcp_mode' 'redirect'
|
||||
option 'udp_mode' 'tun'
|
||||
option 'ipv4_dns_hijack' '1'
|
||||
option 'ipv6_dns_hijack' '1'
|
||||
option 'ipv4_proxy' '1'
|
||||
option 'ipv6_proxy' '1'
|
||||
option 'fake_ip_ping_hijack' '1'
|
||||
option 'router_proxy' '1'
|
||||
option 'lan_proxy' '1'
|
||||
list 'lan_inbound_interface' 'lan'
|
||||
list 'bypass_dscp' '4'
|
||||
option 'bypass_china_mainland_ip' '0'
|
||||
option 'proxy_tcp_dport' '0-65535'
|
||||
option 'proxy_udp_dport' '0-65535'
|
||||
option 'tun_timeout' '30'
|
||||
option 'tun_interval' '1'
|
||||
config env 'env'
|
||||
option 'disable_loopback_detector' '0'
|
||||
option 'disable_quic_go_gso' '0'
|
||||
option 'disable_quic_go_ecn' '0'
|
||||
option 'skip_system_ipv6_check' '0'
|
||||
|
||||
config subscription 'subscription'
|
||||
option 'name' 'default'
|
||||
@@ -74,56 +61,6 @@ config mixin 'mixin'
|
||||
option 'rule_provider' '0'
|
||||
option 'mixin_file_content' '0'
|
||||
|
||||
config env 'env'
|
||||
option 'disable_loopback_detector' '0'
|
||||
option 'disable_quic_go_gso' '0'
|
||||
option 'disable_quic_go_ecn' '0'
|
||||
option 'skip_system_ipv6_check' '0'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
list 'user' 'dnsmasq'
|
||||
list 'user' 'ftp'
|
||||
list 'user' 'logd'
|
||||
list 'user' 'nobody'
|
||||
list 'user' 'ntp'
|
||||
list 'user' 'ubus'
|
||||
list 'group' 'dnsmasq'
|
||||
list 'group' 'ftp'
|
||||
list 'group' 'logd'
|
||||
list 'group' 'nogroup'
|
||||
list 'group' 'ntp'
|
||||
list 'group' 'ubus'
|
||||
list 'cgroup' 'services/adguardhome'
|
||||
list 'cgroup' 'services/aria2'
|
||||
list 'cgroup' 'services/dnsmasq'
|
||||
list 'cgroup' 'services/netbird'
|
||||
list 'cgroup' 'services/qbittorrent'
|
||||
list 'cgroup' 'services/sysntpd'
|
||||
list 'cgroup' 'services/tailscale'
|
||||
list 'cgroup' 'services/zerotier'
|
||||
option 'proxy' '0'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config lan_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config routing 'routing'
|
||||
option 'tproxy_fw_mark' '0x80'
|
||||
option 'tun_fw_mark' '0x81'
|
||||
option 'tproxy_rule_pref' '1024'
|
||||
option 'tun_rule_pref' '1025'
|
||||
option 'tproxy_route_table' '80'
|
||||
option 'tun_route_table' '81'
|
||||
option 'cgroup_id' '0x12061206'
|
||||
option 'cgroup_name' 'nikki'
|
||||
|
||||
config authentication
|
||||
option 'enabled' '1'
|
||||
option 'username' 'nikki'
|
||||
@@ -192,6 +129,91 @@ config sniff
|
||||
list 'port' '8443'
|
||||
option 'overwrite_destination' '1'
|
||||
|
||||
config proxy 'proxy'
|
||||
option 'enabled' '1'
|
||||
option 'tcp_mode' 'redirect'
|
||||
option 'udp_mode' 'tun'
|
||||
option 'ipv4_dns_hijack' '1'
|
||||
option 'ipv6_dns_hijack' '1'
|
||||
option 'ipv4_proxy' '1'
|
||||
option 'ipv6_proxy' '1'
|
||||
option 'fake_ip_ping_hijack' '1'
|
||||
option 'router_proxy' '1'
|
||||
option 'lan_proxy' '1'
|
||||
list 'lan_inbound_interface' 'lan'
|
||||
list 'reserved_ip' '0.0.0.0/8'
|
||||
list 'reserved_ip' '10.0.0.0/8'
|
||||
list 'reserved_ip' '127.0.0.0/8'
|
||||
list 'reserved_ip' '100.64.0.0/10'
|
||||
list 'reserved_ip' '169.254.0.0/16'
|
||||
list 'reserved_ip' '172.16.0.0/12'
|
||||
list 'reserved_ip' '192.168.0.0/16'
|
||||
list 'reserved_ip' '224.0.0.0/4'
|
||||
list 'reserved_ip' '240.0.0.0/4'
|
||||
list 'reserved_ip6' '::/128'
|
||||
list 'reserved_ip6' '::1/128'
|
||||
list 'reserved_ip6' '::ffff:0:0/96'
|
||||
list 'reserved_ip6' '100::/64'
|
||||
list 'reserved_ip6' '64:ff9b::/96'
|
||||
list 'reserved_ip6' '2001::/32'
|
||||
list 'reserved_ip6' '2001:10::/28'
|
||||
list 'reserved_ip6' '2001:20::/28'
|
||||
list 'reserved_ip6' '2001:db8::/32'
|
||||
list 'reserved_ip6' '2002::/16'
|
||||
list 'reserved_ip6' 'fc00::/7'
|
||||
list 'reserved_ip6' 'fe80::/10'
|
||||
list 'reserved_ip6' 'ff00::/8'
|
||||
list 'bypass_dscp' '4'
|
||||
option 'bypass_china_mainland_ip' '0'
|
||||
option 'proxy_tcp_dport' '0-65535'
|
||||
option 'proxy_udp_dport' '0-65535'
|
||||
option 'tun_timeout' '30'
|
||||
option 'tun_interval' '1'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
list 'user' 'dnsmasq'
|
||||
list 'user' 'ftp'
|
||||
list 'user' 'logd'
|
||||
list 'user' 'nobody'
|
||||
list 'user' 'ntp'
|
||||
list 'user' 'ubus'
|
||||
list 'group' 'dnsmasq'
|
||||
list 'group' 'ftp'
|
||||
list 'group' 'logd'
|
||||
list 'group' 'nogroup'
|
||||
list 'group' 'ntp'
|
||||
list 'group' 'ubus'
|
||||
list 'cgroup' 'services/adguardhome'
|
||||
list 'cgroup' 'services/aria2'
|
||||
list 'cgroup' 'services/dnsmasq'
|
||||
list 'cgroup' 'services/netbird'
|
||||
list 'cgroup' 'services/qbittorrent'
|
||||
list 'cgroup' 'services/sysntpd'
|
||||
list 'cgroup' 'services/tailscale'
|
||||
list 'cgroup' 'services/zerotier'
|
||||
option 'proxy' '0'
|
||||
|
||||
config router_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config lan_access_control
|
||||
option 'enabled' '1'
|
||||
option 'dns' '1'
|
||||
option 'proxy' '1'
|
||||
|
||||
config routing 'routing'
|
||||
option 'tproxy_fw_mark' '0x80'
|
||||
option 'tun_fw_mark' '0x81'
|
||||
option 'tproxy_rule_pref' '1024'
|
||||
option 'tun_rule_pref' '1025'
|
||||
option 'tproxy_route_table' '80'
|
||||
option 'tun_route_table' '81'
|
||||
option 'cgroup_id' '0x12061206'
|
||||
option 'cgroup_name' 'nikki'
|
||||
|
||||
config editor 'editor'
|
||||
|
||||
config log 'log'
|
||||
|
||||
@@ -52,6 +52,13 @@ start_service() {
|
||||
config_get_bool test_profile "config" "test_profile" 0
|
||||
config_get_bool fast_reload "config" "fast_reload" 0
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## environment variable
|
||||
local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check
|
||||
config_get safe_paths "env" "safe_paths"
|
||||
config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0
|
||||
config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0
|
||||
config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0
|
||||
config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0
|
||||
## mixin config
|
||||
### overwrite
|
||||
local overwrite_authentication overwrite_tun_dns_hijack overwrite_fake_ip_filter overwrite_hosts overwrite_dns_nameserver overwrite_dns_nameserver_policy overwrite_sniffer_sniff overwrite_sniffer_force_domain_name overwrite_sniffer_ignore_domain_name
|
||||
@@ -67,13 +74,13 @@ start_service() {
|
||||
### mixin file content
|
||||
local mixin_file_content
|
||||
config_get_bool mixin_file_content "mixin" "mixin_file_content" 0
|
||||
## environment variable
|
||||
local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check
|
||||
config_get safe_paths "env" "safe_paths"
|
||||
config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0
|
||||
config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0
|
||||
config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0
|
||||
config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0
|
||||
## proxy config
|
||||
local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0
|
||||
config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
# get profile
|
||||
local profile_type; profile_type=$(echo "$profile" | cut -d ':' -f 1)
|
||||
local profile_id; profile_id=$(echo "$profile" | cut -d ':' -f 2)
|
||||
@@ -144,6 +151,43 @@ start_service() {
|
||||
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" -
|
||||
fi
|
||||
fi
|
||||
# check profile
|
||||
if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
|
||||
log "Profile" "Checking..."
|
||||
if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then
|
||||
if (! yq -M -e 'has("dns") and (.dns | .enable) and (.dns | has("listen"))' "$RUN_PROFILE_PATH"); then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "DNS should be enabled and listen should be defined."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "redirect" ]; then
|
||||
if (! yq -M -e 'has("redir-port")' "$RUN_PROFILE_PATH"); then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "Redirect Port should be defined."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
|
||||
if (! yq -M -e 'has("tproxy-port")' "$RUN_PROFILE_PATH"); then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TPROXY Port should be defined."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
if (! yq -M -e 'has("tun") and (.tun | .enable) and (.tun | has("device"))' "$RUN_PROFILE_PATH"); then
|
||||
log "Profile" "Check failed."
|
||||
log "Profile" "TUN should be enabled and device should be defined."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
log "Profile" "Check passed."
|
||||
fi
|
||||
# test profile
|
||||
if [ "$test_profile" = 1 ]; then
|
||||
log "Profile" "Testing..."
|
||||
@@ -204,10 +248,6 @@ service_started() {
|
||||
## app config
|
||||
local core_only
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## mixin
|
||||
### tun
|
||||
local tun_device
|
||||
config_get tun_device "mixin" "tun_device" "nikki"
|
||||
## proxy config
|
||||
### general
|
||||
local tcp_mode udp_mode ipv4_proxy ipv6_proxy tun_timeout tun_interval
|
||||
@@ -236,6 +276,7 @@ service_started() {
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
tun_enable=1
|
||||
fi
|
||||
local tun_device; tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH")
|
||||
if [ "$core_only" = 0 ]; then
|
||||
# proxy
|
||||
log "Proxy" "Enabled."
|
||||
@@ -243,11 +284,9 @@ service_started() {
|
||||
if [ "$tun_enable" = 1 ]; then
|
||||
log "Proxy" "Waiting for tun device online within $tun_timeout seconds..."
|
||||
while [ "$tun_timeout" -gt 0 ]; do
|
||||
if (ip link show dev "$tun_device" > /dev/null 2>&1); then
|
||||
if [ "$(ip -json addr show dev "$tun_device" | tun_device="$tun_device" yq -M '.[] | select(.ifname = strenv(tun_device)) | .addr_info | length')" -gt 0 ]; then
|
||||
log "Proxy" "TUN device is online."
|
||||
break
|
||||
fi
|
||||
if (ip -j link show dev "$tun_device" | jsonfilter -q -e "@[@['flags'][@='UP']]" > /dev/null 2>&1); then
|
||||
log "Proxy" "TUN device is online."
|
||||
break
|
||||
fi
|
||||
tun_timeout=$((tun_timeout - tun_interval))
|
||||
sleep "$tun_interval"
|
||||
@@ -354,11 +393,11 @@ cleanup() {
|
||||
# delete hijack
|
||||
nft delete table inet nikki > /dev/null 2>&1
|
||||
local handles handle
|
||||
handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "input" and .comment == "nikki") | .handle')
|
||||
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='input']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']")
|
||||
for handle in $handles; do
|
||||
nft delete rule inet fw4 input handle "$handle"
|
||||
done
|
||||
handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "forward" and .comment == "nikki") | .handle')
|
||||
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='forward']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']")
|
||||
for handle in $handles; do
|
||||
nft delete rule inet fw4 forward handle "$handle"
|
||||
done
|
||||
|
||||
@@ -49,8 +49,8 @@ const config = uci.get_all("nikki");
|
||||
const result = {};
|
||||
|
||||
for (let section_id in config) {
|
||||
const section = config[section_id];
|
||||
const section_type = section[".type"];
|
||||
const section = config[section_id];
|
||||
const section_type = section[".type"];
|
||||
if (result[section_type] == null) {
|
||||
result[section_type] = [];
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ config_get_bool core_only "config" "core_only" 0
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
config_get tun_device "mixin" "tun_device"
|
||||
|
||||
if [ "$enabled" = 1 ] && [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
|
||||
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
|
||||
tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH")
|
||||
nft insert rule inet fw4 input iifname "$tun_device" counter accept comment "nikki"
|
||||
nft insert rule inet fw4 forward oifname "$tun_device" counter accept comment "nikki"
|
||||
nft insert rule inet fw4 forward iifname "$tun_device" counter accept comment "nikki"
|
||||
|
||||
@@ -36,8 +36,6 @@ FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh"
|
||||
|
||||
# nftables
|
||||
NFT_DIR="$HOME_DIR/nftables"
|
||||
RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft"
|
||||
RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft"
|
||||
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"
|
||||
GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft"
|
||||
|
||||
|
||||
@@ -156,6 +156,35 @@ uci show nikki | grep -o -E 'nikki.@lan_access_control\[[[:digit:]]+\]=lan_acces
|
||||
[ -z "$lan_access_control_dns" ] && uci set "$lan_access_control.dns=$lan_access_control_proxy"
|
||||
done
|
||||
|
||||
# since v1.24.0
|
||||
proxy_reserved_ip=$(uci -q get nikki.proxy.reserved_ip); [ -z "$proxy_reserved_ip" ] && {
|
||||
uci add_list nikki.proxy.reserved_ip=0.0.0.0/8
|
||||
uci add_list nikki.proxy.reserved_ip=10.0.0.0/8
|
||||
uci add_list nikki.proxy.reserved_ip=127.0.0.0/8
|
||||
uci add_list nikki.proxy.reserved_ip=100.64.0.0/10
|
||||
uci add_list nikki.proxy.reserved_ip=169.254.0.0/16
|
||||
uci add_list nikki.proxy.reserved_ip=172.16.0.0/12
|
||||
uci add_list nikki.proxy.reserved_ip=192.168.0.0/16
|
||||
uci add_list nikki.proxy.reserved_ip=224.0.0.0/4
|
||||
uci add_list nikki.proxy.reserved_ip=240.0.0.0/4
|
||||
}
|
||||
|
||||
proxy_reserved_ip6=$(uci -q get nikki.proxy.reserved_ip6); [ -z "$proxy_reserved_ip6" ] && {
|
||||
uci add_list nikki.proxy.reserved_ip6=::/128
|
||||
uci add_list nikki.proxy.reserved_ip6=::1/128
|
||||
uci add_list nikki.proxy.reserved_ip6=::ffff:0:0/96
|
||||
uci add_list nikki.proxy.reserved_ip6=100::/64
|
||||
uci add_list nikki.proxy.reserved_ip6=64:ff9b::/96
|
||||
uci add_list nikki.proxy.reserved_ip6=2001::/32
|
||||
uci add_list nikki.proxy.reserved_ip6=2001:10::/28
|
||||
uci add_list nikki.proxy.reserved_ip6=2001:20::/28
|
||||
uci add_list nikki.proxy.reserved_ip6=2001:db8::/32
|
||||
uci add_list nikki.proxy.reserved_ip6=2002::/16
|
||||
uci add_list nikki.proxy.reserved_ip6=fc00::/7
|
||||
uci add_list nikki.proxy.reserved_ip6=fe80::/10
|
||||
uci add_list nikki.proxy.reserved_ip6=ff00::/8
|
||||
}
|
||||
|
||||
# commit
|
||||
uci commit nikki
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups } from '/etc/nikki/ucode/include.uc';
|
||||
import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups, load_profile } from '/etc/nikki/ucode/include.uc';
|
||||
|
||||
const cgroups_version = get_cgroups_version();
|
||||
|
||||
@@ -16,16 +16,18 @@
|
||||
const uci = cursor();
|
||||
const ubus = connect();
|
||||
|
||||
uci.load('nikki');
|
||||
const profile = load_profile();
|
||||
|
||||
const redir_port = uci.get('nikki', 'mixin', 'redir_port');
|
||||
const tproxy_port = uci.get('nikki', 'mixin', 'tproxy_port');
|
||||
const redir_port = profile['redir-port'];
|
||||
const tproxy_port = profile['tproxy-port'];
|
||||
|
||||
const dns_listen = uci.get('nikki', 'mixin', 'dns_listen');
|
||||
const dns_listen = profile['dns']['listen'];
|
||||
const dns_port = substr(dns_listen, rindex(dns_listen, ':') + 1);
|
||||
const fake_ip_range = uci.get('nikki', 'mixin', 'fake_ip_range');
|
||||
const fake_ip_range = profile['dns']['fake-ip-range'];
|
||||
|
||||
const tun_device = uci.get('nikki', 'mixin', 'tun_device');
|
||||
const tun_device = profile['tun']['device'];
|
||||
|
||||
uci.load('nikki');
|
||||
|
||||
const tcp_mode = uci.get('nikki', 'proxy', 'tcp_mode');
|
||||
const udp_mode = uci.get('nikki', 'proxy', 'udp_mode');
|
||||
@@ -68,6 +70,8 @@
|
||||
push(lan_access_control, access_control);
|
||||
});
|
||||
|
||||
const reserved_ip = uci_array(uci.get('momo', 'proxy', 'reserved_ip'));
|
||||
const reserved_ip6 = uci_array(uci.get('momo', 'proxy', 'reserved_ip6'));
|
||||
const bypass_dscp = uci_array(uci.get('nikki', 'proxy', 'bypass_dscp'));
|
||||
const bypass_china_mainland_ip = uci_bool(uci.get('nikki', 'proxy', 'bypass_china_mainland_ip'));
|
||||
const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' ');
|
||||
@@ -128,12 +132,22 @@ table inet nikki {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(reserved_ip) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', reserved_ip) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set reserved_ip6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(reserved_ip6) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', reserved_ip6) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set lan_inbound_device {
|
||||
@@ -180,6 +194,7 @@ table inet nikki {
|
||||
}
|
||||
|
||||
{% if (router_proxy): %}
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
chain router_dns_hijack {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -205,7 +220,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain router_redirect {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -231,7 +248,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
chain router_tproxy {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -257,7 +276,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
chain router_tun {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -284,8 +305,10 @@ table inet nikki {
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if (lan_proxy): %}
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
chain lan_dns_hijack {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -309,7 +332,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain lan_redirect {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -333,7 +358,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
chain lan_tproxy {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -357,7 +384,9 @@ table inet nikki {
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
chain lan_tun {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
@@ -382,6 +411,7 @@ table inet nikki {
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if (router_proxy): %}
|
||||
chain nat_output {
|
||||
@@ -399,14 +429,16 @@ table inet nikki {
|
||||
ip6 daddr @reserved_ip6 counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
meta nfproto @proxy_nfproto jump router_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% if (fake_ip_range ): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
@@ -423,9 +455,9 @@ table inet nikki {
|
||||
ip6 daddr @reserved_ip6 counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% if (tcp_mode == 'tproxy'): %}
|
||||
@@ -462,14 +494,16 @@ table inet nikki {
|
||||
ip6 daddr @reserved_ip6 counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect
|
||||
{% endif %}
|
||||
{% if (fake_ip_ping_hijack): %}
|
||||
ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
@@ -481,9 +515,9 @@ table inet nikki {
|
||||
ip6 daddr @reserved_ip6 counter return
|
||||
ip daddr @china_ip counter return
|
||||
ip6 daddr @china_ip6 counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
|
||||
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
|
||||
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% if (tcp_mode == 'tproxy'): %}
|
||||
@@ -500,9 +534,6 @@ table inet nikki {
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
include "/etc/nikki/nftables/reserved_ip.nft"
|
||||
include "/etc/nikki/nftables/reserved_ip6.nft"
|
||||
|
||||
{% if (bypass_china_mainland_ip): %}
|
||||
include "/etc/nikki/nftables/geoip_cn.nft"
|
||||
include "/etc/nikki/nftables/geoip6_cn.nft"
|
||||
|
||||
@@ -74,4 +74,14 @@ export function get_cgroups() {
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export function load_profile() {
|
||||
let result = {};
|
||||
const process = popen('yq -M -p yaml -o json /etc/nikki/run/config.yaml');
|
||||
if (process) {
|
||||
result = json(process);
|
||||
process.close();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -51,26 +51,24 @@ if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) {
|
||||
}
|
||||
|
||||
config['tun'] = {};
|
||||
if (uci.get('nikki', 'proxy', 'tcp_mode') == 'tun' || uci.get('nikki', 'proxy', 'udp_mode') == 'tun') {
|
||||
config['tun']['enable'] = true;
|
||||
config['tun']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'tun_enabled'));
|
||||
config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device');
|
||||
config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack');
|
||||
config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu'));
|
||||
config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso'));
|
||||
config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size'));
|
||||
config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat'));
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) {
|
||||
config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks'));
|
||||
}
|
||||
if (uci_bool(uci.get('nikki', 'proxy', 'enabled'))) {
|
||||
config['tun']['auto-route'] = false;
|
||||
config['tun']['auto-redirect'] = false;
|
||||
config['tun']['auto-detect-interface'] = false;
|
||||
config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device');
|
||||
config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack');
|
||||
config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu'));
|
||||
config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso'));
|
||||
config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size'));
|
||||
config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat'));
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) {
|
||||
config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks'));
|
||||
}
|
||||
} else {
|
||||
config['tun']['enable'] = false;
|
||||
}
|
||||
|
||||
config['dns'] = {};
|
||||
config['dns']['enable'] = true;
|
||||
config['dns']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'dns_enabled'));
|
||||
config['dns']['listen'] = uci.get('nikki', 'mixin', 'dns_listen');
|
||||
config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6'));
|
||||
config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode');
|
||||
@@ -182,7 +180,7 @@ if (uci_bool(uci.get('nikki', 'mixin', 'rule'))) {
|
||||
}
|
||||
|
||||
const geoip_format = uci.get('nikki', 'mixin', 'geoip_format');
|
||||
config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat';
|
||||
config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat';
|
||||
config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader');
|
||||
config['geox-url'] = {};
|
||||
config['geox-url']['geosite'] = uci.get('nikki', 'mixin', 'geosite_url');
|
||||
|
||||
@@ -21,13 +21,13 @@ define Download/geoip
|
||||
HASH:=54761d8691a5756fdb08d2cd4d0a9c889dbaab786e1cf758592e09fb00377f53
|
||||
endef
|
||||
|
||||
GEOSITE_VER:=20250814002625
|
||||
GEOSITE_VER:=20250819114505
|
||||
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
|
||||
define Download/geosite
|
||||
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
|
||||
URL_FILE:=dlc.dat
|
||||
FILE:=$(GEOSITE_FILE)
|
||||
HASH:=01dae2a9c31b5c74ba7e54d8d51e0060688ed22da493eaf09f6eeeec89db395e
|
||||
HASH:=0388dba07e0567e5f35e728f595be0e6ee8b98dcddacd15745499ddcf58cbfa8
|
||||
endef
|
||||
|
||||
GEOSITE_IRAN_VER:=202508180044
|
||||
|
||||
+432
-151
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ===== Require Red Hat Enterprise Linux / Rocky Linux / AlmaLinux / CentOS Stream =======
|
||||
# ===== Require Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS OR Ubuntu/Debian ====
|
||||
if [[ -r /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
case "$ID" in
|
||||
rhel|rocky|almalinux|centos)
|
||||
rhel|rocky|almalinux|centos|ubuntu|debian)
|
||||
echo "[OK] Detected supported system: $NAME $VERSION_ID"
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unsupported system: $NAME ($ID)."
|
||||
echo "This script only supports Red Hat Enterprise Linux / Rocky Linux / AlmaLinux / CentOS Stream."
|
||||
echo "This script only supports Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS or Ubuntu/Debian."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -24,8 +24,10 @@ VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
||||
WITH_CORE="both" # Default: bundle both xray+sing-box
|
||||
AUTOSTART=0 # 1 = enable system-wide autostart (/etc/xdg/autostart)
|
||||
FORCE_NETCORE=0 # --netcore => skip archive bundle, use separate downloads
|
||||
ARCH_OVERRIDE="" # --arch x64|arm64|all (optional compile target)
|
||||
BUILD_FROM="" # --buildfrom 1|2|3 to select channel non-interactively
|
||||
|
||||
# If the first argument starts with --, don’t treat it as version number
|
||||
# If the first argument starts with --, do not treat it as a version number
|
||||
if [[ "${VERSION_ARG:-}" == --* ]]; then
|
||||
VERSION_ARG=""
|
||||
fi
|
||||
@@ -37,28 +39,109 @@ while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--with-core) WITH_CORE="${2:-both}"; shift 2;;
|
||||
--autostart) AUTOSTART=1; shift;;
|
||||
--xray-ver) XRAY_VER="${2:-}"; shift 2;; # Specify xray version (optional)
|
||||
--singbox-ver) SING_VER="${2:-}"; shift 2;; # Specify sing-box version (optional)
|
||||
--netcore) FORCE_NETCORE=1; shift;; # NEW: force old mode (no bundle zip)
|
||||
--xray-ver) XRAY_VER="${2:-}"; shift 2;;
|
||||
--singbox-ver) SING_VER="${2:-}"; shift 2;;
|
||||
--netcore) FORCE_NETCORE=1; shift;;
|
||||
--arch) ARCH_OVERRIDE="${2:-}"; shift 2;;
|
||||
--buildfrom) BUILD_FROM="${2:-}"; shift 2;;
|
||||
*)
|
||||
if [[ -z "${VERSION_ARG:-}" ]]; then VERSION_ARG="$1"; fi
|
||||
shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ===== Environment check ===============================================================
|
||||
arch="$(uname -m)"
|
||||
[[ "$arch" == "aarch64" || "$arch" == "x86_64" ]] || { echo "Only supports aarch64 / x86_64"; exit 1; }
|
||||
# Conflict: version number AND --buildfrom cannot be used together
|
||||
if [[ -n "${VERSION_ARG:-}" && -n "${BUILD_FROM:-}" ]]; then
|
||||
echo "[ERROR] You cannot specify both an explicit version and --buildfrom at the same time."
|
||||
echo " Provide either a version (e.g. 7.14.0) OR --buildfrom 1|2|3."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ===== Environment check + Dependencies ========================================
|
||||
host_arch="$(uname -m)"
|
||||
[[ "$host_arch" == "aarch64" || "$host_arch" == "x86_64" ]] || { echo "Only supports aarch64 / x86_64"; exit 1; }
|
||||
|
||||
install_ok=0
|
||||
case "$ID" in
|
||||
# ------------------------------ RHEL family (UNCHANGED) ------------------------------
|
||||
rhel|rocky|almalinux|centos)
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \
|
||||
sudo dnf -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
||||
install_ok=1
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
sudo yum -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \
|
||||
sudo yum -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
||||
install_ok=1
|
||||
fi
|
||||
;;
|
||||
# ------------------------------ Ubuntu ----------------------------------------------
|
||||
ubuntu)
|
||||
sudo apt-get update
|
||||
# Ensure 'universe' (Ubuntu) to get 'rpm'
|
||||
if ! apt-cache policy | grep -q '^500 .*ubuntu.com/ubuntu.* universe'; then
|
||||
sudo apt-get -y install software-properties-common || true
|
||||
sudo add-apt-repository -y universe || true
|
||||
sudo apt-get update
|
||||
fi
|
||||
# Base tools + rpm (provides rpmbuild)
|
||||
sudo apt-get -y install curl unzip tar rsync rpm || true
|
||||
# Cross-arch binutils so strip matches target arch + objdump for brp scripts
|
||||
sudo apt-get -y install binutils binutils-x86-64-linux-gnu binutils-aarch64-linux-gnu || true
|
||||
# rpmbuild presence check
|
||||
if ! command -v rpmbuild >/dev/null 2>&1; then
|
||||
echo "[ERROR] 'rpmbuild' not found after installing 'rpm'."
|
||||
echo " Please ensure the 'rpm' package is available from your repos (universe on Ubuntu)."
|
||||
exit 1
|
||||
fi
|
||||
# .NET SDK 8 (best effort via apt)
|
||||
if ! command -v dotnet >/dev/null 2>&1; then
|
||||
sudo apt-get -y install dotnet-sdk-8.0 || true
|
||||
sudo apt-get -y install dotnet-sdk-8 || true
|
||||
sudo apt-get -y install dotnet-sdk || true
|
||||
fi
|
||||
install_ok=1
|
||||
;;
|
||||
# ------------------------------ Debian (KEEP, with local dotnet install) ------------
|
||||
debian)
|
||||
sudo apt-get update
|
||||
# Base tools + rpm (provides rpmbuild on Debian) + objdump/strip
|
||||
sudo apt-get -y install curl unzip tar rsync rpm binutils || true
|
||||
# rpmbuild presence check
|
||||
if ! command -v rpmbuild >/dev/null 2>&1; then
|
||||
echo "[ERROR] 'rpmbuild' not found after installing 'rpm'."
|
||||
echo " Please ensure 'rpm' is available from Debian repos."
|
||||
exit 1
|
||||
fi
|
||||
# Try apt for dotnet; fallback to official installer into $HOME/.dotnet
|
||||
if ! command -v dotnet >/dev/null 2>&1; then
|
||||
echo "[INFO] 'dotnet' not found. Installing .NET 8 SDK locally to \$HOME/.dotnet ..."
|
||||
tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN
|
||||
curl -fsSL https://dot.net/v1/dotnet-install.sh -o "$tmp/dotnet-install.sh"
|
||||
bash "$tmp/dotnet-install.sh" --channel 8.0 --install-dir "$HOME/.dotnet"
|
||||
export PATH="$HOME/.dotnet:$HOME/.dotnet/tools:$PATH"
|
||||
export DOTNET_ROOT="$HOME/.dotnet"
|
||||
if ! command -v dotnet >/dev/null 2>&1; then
|
||||
echo "[ERROR] dotnet installation failed."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
install_ok=1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$install_ok" -ne 1 ]]; then
|
||||
echo "[WARN] Could not auto-install dependencies for '$ID'. Make sure these are available:"
|
||||
echo " dotnet-sdk 8.x, curl, unzip, tar, rsync, rpm, rpmdevtools, rpm-build (on RPM-based distros)"
|
||||
fi
|
||||
|
||||
# Dependencies (packaging shouldn’t be run as root, but this line needs sudo)
|
||||
sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar || sudo dnf -y install dotnet-sdk
|
||||
command -v curl >/dev/null
|
||||
|
||||
# Root directory = the script's location
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Git submodules (tolerant)
|
||||
# Git submodules (best effort)
|
||||
if [[ -f .gitmodules ]]; then
|
||||
git submodule sync --recursive || true
|
||||
git submodule update --init --recursive || true
|
||||
@@ -72,25 +155,36 @@ fi
|
||||
[[ -f "$PROJECT" ]] || { echo "v2rayN.Desktop.csproj not found"; exit 1; }
|
||||
|
||||
# ===== Resolve GUI version & auto checkout ============================================
|
||||
# Rules:
|
||||
# - If VERSION_ARG provided: try to checkout that tag (vX.Y.Z or X.Y.Z). If not found, ask which channel (Latest vs Pre-release),
|
||||
# default to Latest, then fetch the chosen channel's latest tag and checkout.
|
||||
# - If VERSION_ARG not provided: ask the channel first (default Latest), then checkout to that tag.
|
||||
# - If not a git repo, warn and continue without switching (keep current branch).
|
||||
VERSION="" # final GUI version string without 'v' prefix
|
||||
VERSION=""
|
||||
|
||||
choose_channel() {
|
||||
# Print menu to stderr first, then read from stdin; only echo the chosen token to stdout.
|
||||
# If --buildfrom provided, map it directly and skip interaction.
|
||||
if [[ -n "${BUILD_FROM:-}" ]]; then
|
||||
case "$BUILD_FROM" in
|
||||
1) echo "latest"; return 0;;
|
||||
2) echo "prerelease"; return 0;;
|
||||
3) echo "keep"; return 0;;
|
||||
*) echo "[ERROR] Invalid --buildfrom value: ${BUILD_FROM}. Use 1|2|3." >&2; exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Print menu to stderr and read from /dev/tty so stdout only carries the token.
|
||||
local ch="latest" sel=""
|
||||
if [[ -t 0 ]]; then
|
||||
>&2 echo "[?] Choose v2rayN release channel:"
|
||||
>&2 echo " 1) Latest (stable) [default]"
|
||||
>&2 echo " 2) Pre-release (preview)"
|
||||
read -r -p "Enter 1 or 2 (default 1): " sel
|
||||
case "${sel:-}" in
|
||||
2) ch="prerelease" ;;
|
||||
*) ch="latest" ;;
|
||||
esac
|
||||
echo "[?] Choose v2rayN release channel:" >&2
|
||||
echo " 1) Latest (stable) [default]" >&2
|
||||
echo " 2) Pre-release (preview)" >&2
|
||||
echo " 3) Keep current (do nothing)" >&2
|
||||
printf "Enter 1, 2 or 3 [default 1]: " >&2
|
||||
if read -r sel </dev/tty; then
|
||||
case "${sel:-}" in
|
||||
2) ch="prerelease" ;;
|
||||
3) ch="keep" ;;
|
||||
*) ch="latest" ;;
|
||||
esac
|
||||
else
|
||||
ch="latest"
|
||||
fi
|
||||
else
|
||||
ch="latest"
|
||||
fi
|
||||
@@ -98,7 +192,7 @@ choose_channel() {
|
||||
}
|
||||
|
||||
get_latest_tag_latest() {
|
||||
# Use GitHub API: /releases/latest → tag_name
|
||||
# Resolve /releases/latest → tag_name
|
||||
curl -fsSL "https://api.github.com/repos/2dust/v2rayN/releases/latest" \
|
||||
| grep -Eo '"tag_name":\s*"v?[^"]+"' \
|
||||
| head -n1 \
|
||||
@@ -106,16 +200,34 @@ get_latest_tag_latest() {
|
||||
}
|
||||
|
||||
get_latest_tag_prerelease() {
|
||||
# Use GitHub API: /releases?per_page=20 and pick the newest prerelease=true's tag_name
|
||||
local json
|
||||
# Resolve newest prerelease=true tag; prefer jq, fallback to sed/grep (no awk)
|
||||
local json tag
|
||||
json="$(curl -fsSL "https://api.github.com/repos/2dust/v2rayN/releases?per_page=20")" || return 1
|
||||
echo "$json" \
|
||||
| awk -v RS='},' '/"prerelease":[[:space:]]*true/ { if (match($0, /"tag_name":[[:space:]]*"v?[^"]+"/, m)) { t=m[0]; sub(/.*"tag_name":[[:space:]]*"?v?/, "", t); sub(/".*/, "", t); print t; exit } }'
|
||||
|
||||
# 1) Use jq if present
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
tag="$(printf '%s' "$json" \
|
||||
| jq -r '[.[] | select(.prerelease==true)][0].tag_name' 2>/dev/null \
|
||||
| sed 's/^v//')" || true
|
||||
fi
|
||||
|
||||
# 2) Fallback to sed/grep only
|
||||
if [[ -z "${tag:-}" || "${tag:-}" == "null" ]]; then
|
||||
tag="$(printf '%s' "$json" \
|
||||
| tr '\n' ' ' \
|
||||
| sed 's/},[[:space:]]*{/\n/g' \
|
||||
| grep -m1 -E '"prerelease"[[:space:]]*:[[:space:]]*true' \
|
||||
| grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"v?[^"]+"' \
|
||||
| head -n1 \
|
||||
| sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v?([^"]+)".*/\1/')" || true
|
||||
fi
|
||||
|
||||
[[ -n "${tag:-}" && "${tag:-}" != "null" ]] || return 1
|
||||
printf '%s\n' "$tag"
|
||||
}
|
||||
|
||||
git_try_checkout() {
|
||||
# Try a series of refs and checkout when found.
|
||||
# Args: version-like string (may contain leading 'v')
|
||||
local want="$1" ref=""
|
||||
if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
git fetch --tags --force --prune --depth=1 || true
|
||||
@@ -147,10 +259,51 @@ if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
else
|
||||
echo "[WARN] Tag '${VERSION_ARG}' not found."
|
||||
ch="$(choose_channel)"
|
||||
if [[ "$ch" == "keep" ]]; then
|
||||
echo "[*] Keep current repository state (no checkout)."
|
||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||
VERSION="$(git describe --tags --abbrev=0)"
|
||||
else
|
||||
VERSION="0.0.0+git"
|
||||
fi
|
||||
VERSION="${VERSION#v}"
|
||||
else
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
tag=""
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
if [[ -z "$tag" ]]; then
|
||||
echo "[WARN] Failed to resolve prerelease tag, falling back to latest."
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
[[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; }
|
||||
echo "[*] Latest tag for '${ch}': ${tag}"
|
||||
git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
ch="$(choose_channel)"
|
||||
if [[ "$ch" == "keep" ]]; then
|
||||
echo "[*] Keep current repository state (no checkout)."
|
||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||
VERSION="$(git describe --tags --abbrev=0)"
|
||||
else
|
||||
VERSION="0.0.0+git"
|
||||
fi
|
||||
VERSION="${VERSION#v}"
|
||||
else
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
tag=""
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
if [[ -z "$tag" ]]; then
|
||||
echo "[WARN] Failed to resolve prerelease tag, falling back to latest."
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
@@ -159,20 +312,6 @@ if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
fi
|
||||
else
|
||||
# No explicit GUI version passed: ask channel first
|
||||
ch="$(choose_channel)"
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
tag=""
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
[[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; }
|
||||
echo "[*] Latest tag for '${ch}': ${tag}"
|
||||
git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
fi
|
||||
else
|
||||
echo "[WARN] Current directory is not a git repo; cannot checkout version. Proceeding on current tree."
|
||||
@@ -188,45 +327,30 @@ else
|
||||
fi
|
||||
echo "[*] GUI version resolved as: ${VERSION}"
|
||||
|
||||
# ===== .NET publish (non-single file, self-contained) ===========================================
|
||||
dotnet clean "$PROJECT" -c Release
|
||||
rm -rf "$(dirname "$PROJECT")/bin/Release/net8.0" || true
|
||||
|
||||
dotnet restore "$PROJECT"
|
||||
dotnet publish "$PROJECT" \
|
||||
-c Release -r "$( [[ "$arch" == "aarch64" ]] && echo linux-arm64 || echo linux-x64 )" \
|
||||
-p:PublishSingleFile=false \
|
||||
-p:SelfContained=true \
|
||||
-p:IncludeNativeLibrariesForSelfExtract=true
|
||||
|
||||
RID_DIR="$( [[ "$arch" == "aarch64" ]] && echo linux-arm64 || echo linux-x64 )"
|
||||
PUBDIR="$(dirname "$PROJECT")/bin/Release/net8.0/${RID_DIR}/publish"
|
||||
[[ -d "$PUBDIR" ]]
|
||||
|
||||
# ===== Download Core(Optional) ========================================================
|
||||
# ===== Helpers for core/rules download (use RID_DIR for arch sync) =====================
|
||||
download_xray() {
|
||||
# Download Xray core and install to outdir/xray
|
||||
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
||||
mkdir -p "$outdir"
|
||||
if [[ -z "$ver" ]]; then
|
||||
# Latest version
|
||||
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
fi
|
||||
[[ -n "$ver" ]] || { echo "[xray] Failed to get version"; return 1; }
|
||||
|
||||
if [[ "$arch" == "aarch64" ]]; then
|
||||
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||
url="https://github.com/XTLS/Xray-core/releases/download/v${ver}/Xray-linux-arm64-v8a.zip"
|
||||
else
|
||||
url="https://github.com/XTLS/Xray-core/releases/download/v${ver}/Xray-linux-64.zip"
|
||||
fi
|
||||
echo "[+] Download xray: $url"
|
||||
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN
|
||||
tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN
|
||||
curl -fL "$url" -o "$tmp/$zipname"
|
||||
unzip -q "$tmp/$zipname" -d "$tmp"
|
||||
install -Dm755 "$tmp/xray" "$outdir/xray"
|
||||
}
|
||||
|
||||
download_singbox() {
|
||||
# Download sing-box core and install to outdir/sing-box
|
||||
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
||||
mkdir -p "$outdir"
|
||||
if [[ -z "$ver" ]]; then
|
||||
@@ -234,14 +358,13 @@ download_singbox() {
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
fi
|
||||
[[ -n "$ver" ]] || { echo "[sing-box] Failed to get version"; return 1; }
|
||||
|
||||
if [[ "$arch" == "aarch64" ]]; then
|
||||
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||
url="https://github.com/SagerNet/sing-box/releases/download/v${ver}/sing-box-${ver}-linux-arm64.tar.gz"
|
||||
else
|
||||
url="https://github.com/SagerNet/sing-box/releases/download/v${ver}/sing-box-${ver}-linux-amd64.tar.gz"
|
||||
fi
|
||||
echo "[+] Download sing-box: $url"
|
||||
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN
|
||||
tmp="$(mktemp -d)"; trap '[[ -n "${tmp:-}" ]] && rm -rf "$tmp"' RETURN
|
||||
curl -fL "$url" -o "$tmp/$tarname"
|
||||
tar -C "$tmp" -xzf "$tmp/$tarname"
|
||||
bin="$(find "$tmp" -type f -name 'sing-box' | head -n1 || true)"
|
||||
@@ -249,18 +372,32 @@ download_singbox() {
|
||||
install -Dm755 "$bin" "$outdir/sing-box"
|
||||
}
|
||||
|
||||
# === Geo rule download (ZIP-LIKE LAYOUT for netcore mode) =====================
|
||||
# Make netcore output match the ZIP bundle structure:
|
||||
# - All geo databases at outroot/bin/ (geosite.dat, geoip.dat, Country.mmdb, geoip-only-cn-private.dat, geoip.metadb)
|
||||
# - All *.srs rule-sets at outroot/bin/srss/
|
||||
# (Binaries stay under outroot/bin/xray and outroot/bin/sing_box as before.)
|
||||
# Move geo files to a unified path: outroot/bin/xray/
|
||||
unify_geo_layout() {
|
||||
local outroot="$1"
|
||||
mkdir -p "$outroot/bin/xray"
|
||||
local srcs=( \
|
||||
"$outroot/bin/geosite.dat" \
|
||||
"$outroot/bin/geoip.dat" \
|
||||
"$outroot/bin/geoip-only-cn-private.dat" \
|
||||
"$outroot/bin/Country.mmdb" \
|
||||
"$outroot/bin/geoip.metadb" \
|
||||
)
|
||||
for s in "${srcs[@]}"; do
|
||||
if [[ -f "$s" ]]; then
|
||||
mv -f "$s" "$outroot/bin/xray/$(basename "$s")"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Download geo/rule assets; then unify to bin/xray/
|
||||
download_geo_assets() {
|
||||
local outroot="$1"
|
||||
local bin_dir="$outroot/bin"
|
||||
local srss_dir="$bin_dir/srss"
|
||||
mkdir -p "$bin_dir" "$srss_dir"
|
||||
|
||||
echo "[+] Download Xray Geo (geosite/geoip/...) to ${bin_dir}"
|
||||
echo "[+] Download Xray Geo to ${bin_dir}"
|
||||
curl -fsSL -o "$bin_dir/geosite.dat" \
|
||||
"https://github.com/Loyalsoldier/V2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
curl -fsSL -o "$bin_dir/geoip.dat" \
|
||||
@@ -270,7 +407,7 @@ download_geo_assets() {
|
||||
curl -fsSL -o "$bin_dir/Country.mmdb" \
|
||||
"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb"
|
||||
|
||||
echo "[+] Download sing-box rule DB & rule-sets to ZIP-like paths"
|
||||
echo "[+] Download sing-box rule DB & rule-sets"
|
||||
curl -fsSL -o "$bin_dir/geoip.metadb" \
|
||||
"https://github.com/MetaCubeX/meta-rules-dat/releases/latest/download/geoip.metadb" || true
|
||||
|
||||
@@ -280,20 +417,22 @@ download_geo_assets() {
|
||||
curl -fsSL -o "$srss_dir/$f" \
|
||||
"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geoip/$f" || true
|
||||
done
|
||||
|
||||
for f in \
|
||||
geosite-cn.srs geosite-gfw.srs geosite-greatfire.srs \
|
||||
geosite-geolocation-cn.srs geosite-category-ads-all.srs geosite-private.srs; do
|
||||
curl -fsSL -o "$srss_dir/$f" \
|
||||
"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geosite/$f" || true
|
||||
done
|
||||
|
||||
# Unify to bin/xray/
|
||||
unify_geo_layout "$outroot"
|
||||
}
|
||||
|
||||
# === NEW: Prefer the all-in-one v2rayN bundle zip first =======================
|
||||
# Prefer the prebuilt v2rayN core bundle; then unify geo layout
|
||||
download_v2rayn_bundle() {
|
||||
local outroot="$1"
|
||||
local url=""
|
||||
if [[ "$arch" == "aarch64" ]]; then
|
||||
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64.zip"
|
||||
else
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64.zip"
|
||||
@@ -304,7 +443,6 @@ download_v2rayn_bundle() {
|
||||
curl -fL "$url" -o "$zipname" || { echo "[!] Bundle download failed"; return 1; }
|
||||
unzip -q "$zipname" -d "$tmp" || { echo "[!] Bundle unzip failed"; return 1; }
|
||||
|
||||
# Normalize layout: copy 'bin/' if present; otherwise copy all
|
||||
if [[ -d "$tmp/bin" ]]; then
|
||||
mkdir -p "$outroot/bin"
|
||||
rsync -a "$tmp/bin/" "$outroot/bin/"
|
||||
@@ -312,7 +450,6 @@ download_v2rayn_bundle() {
|
||||
rsync -a "$tmp/" "$outroot/"
|
||||
fi
|
||||
|
||||
# --- CLEANUPS (keep bundle-only adjustments) -------------------------------
|
||||
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
|
||||
find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
@@ -323,37 +460,100 @@ download_v2rayn_bundle() {
|
||||
rsync -a "$nested_dir/bin/" "$outroot/bin/"
|
||||
rm -rf "$nested_dir"
|
||||
fi
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Unify to bin/xray/
|
||||
unify_geo_layout "$outroot"
|
||||
|
||||
echo "[+] Bundle extracted to $outroot"
|
||||
}
|
||||
|
||||
# ===== Copy publish files to RPM build root ==================================================
|
||||
rpmdev-setuptree
|
||||
TOPDIR="${HOME}/rpmbuild"
|
||||
SPECDIR="${TOPDIR}/SPECS"
|
||||
SOURCEDIR="${TOPDIR}/SOURCES"
|
||||
# ===== Build results collection for --arch all ========================================
|
||||
BUILT_RPMS=() # Will collect absolute paths of built RPMs
|
||||
BUILT_ALL=0 # Flag to know if we should print the final summary
|
||||
|
||||
PKGROOT="v2rayN-publish"
|
||||
WORKDIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORKDIR"' EXIT
|
||||
# ===== Build (single-arch) function ====================================================
|
||||
build_for_arch() {
|
||||
# $1: target short arch: x64 | arm64
|
||||
local short="$1"
|
||||
local rid rpm_target archdir
|
||||
case "$short" in
|
||||
x64) rid="linux-x64"; rpm_target="x86_64"; archdir="x86_64" ;;
|
||||
arm64) rid="linux-arm64"; rpm_target="aarch64"; archdir="aarch64" ;;
|
||||
*) echo "[ERROR] Unknown arch '$short' (use x64|arm64)"; return 1;;
|
||||
esac
|
||||
|
||||
mkdir -p "$WORKDIR/$PKGROOT"
|
||||
cp -a "$PUBDIR/." "$WORKDIR/$PKGROOT/"
|
||||
echo "[*] Building for target: $short (RID=$rid, RPM --target $rpm_target)"
|
||||
|
||||
# icon(Optional)
|
||||
ICON_CANDIDATE="$(dirname "$PROJECT")/../v2rayN.Desktop/v2rayN.png"
|
||||
[[ -f "$ICON_CANDIDATE" ]] && cp "$ICON_CANDIDATE" "$WORKDIR/$PKGROOT/v2rayn.png" || true
|
||||
# .NET publish (self-contained) for this RID
|
||||
dotnet clean "$PROJECT" -c Release
|
||||
rm -rf "$(dirname "$PROJECT")/bin/Release/net8.0" || true
|
||||
|
||||
# bin directory structure
|
||||
mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box"
|
||||
dotnet restore "$PROJECT"
|
||||
dotnet publish "$PROJECT" \
|
||||
-c Release -r "$rid" \
|
||||
-p:PublishSingleFile=false \
|
||||
-p:SelfContained=true \
|
||||
-p:IncludeNativeLibrariesForSelfExtract=true
|
||||
|
||||
# ====== NEW decision: prefer bundle zip unless --netcore, else fall back ======
|
||||
if [[ "$FORCE_NETCORE" -eq 0 ]]; then
|
||||
if download_v2rayn_bundle "$WORKDIR/$PKGROOT"; then
|
||||
echo "[*] Using v2rayN bundle archive."
|
||||
# Per-arch variables (scoped)
|
||||
local RID_DIR="$rid"
|
||||
local PUBDIR
|
||||
PUBDIR="$(dirname "$PROJECT")/bin/Release/net8.0/${RID_DIR}/publish"
|
||||
[[ -d "$PUBDIR" ]]
|
||||
|
||||
# Make RID_DIR visible to download helpers (they read this var)
|
||||
export RID_DIR
|
||||
|
||||
# Per-arch working area
|
||||
local PKGROOT="v2rayN-publish"
|
||||
local WORKDIR
|
||||
WORKDIR="$(mktemp -d)"
|
||||
trap '[[ -n "${WORKDIR:-}" ]] && rm -rf "$WORKDIR"' RETURN
|
||||
|
||||
# rpmbuild topdir selection
|
||||
local TOPDIR SPECDIR SOURCEDIR USE_TOPDIR_DEFINE
|
||||
if [[ "$ID" =~ ^(rhel|rocky|almalinux|centos)$ ]]; then
|
||||
rpmdev-setuptree
|
||||
TOPDIR="${HOME}/rpmbuild"
|
||||
SPECDIR="${TOPDIR}/SPECS"
|
||||
SOURCEDIR="${TOPDIR}/SOURCES"
|
||||
USE_TOPDIR_DEFINE=0
|
||||
else
|
||||
echo "[*] Bundle failed, fallback to separate core + rules."
|
||||
TOPDIR="${WORKDIR}/rpmbuild"
|
||||
SPECDIR="${TOPDIR}/SPECS}"
|
||||
SOURCEDIR="${TOPDIR}/SOURCES"
|
||||
mkdir -p "${SPECDIR}" "${SOURCEDIR}" "${TOPDIR}/BUILD" "${TOPDIR}/RPMS" "${TOPDIR}/SRPMS"
|
||||
USE_TOPDIR_DEFINE=1
|
||||
fi
|
||||
|
||||
# Stage publish content
|
||||
mkdir -p "$WORKDIR/$PKGROOT"
|
||||
cp -a "$PUBDIR/." "$WORKDIR/$PKGROOT/"
|
||||
|
||||
# Optional icon
|
||||
local ICON_CANDIDATE
|
||||
ICON_CANDIDATE="$(dirname "$PROJECT")/../v2rayN.Desktop/v2rayN.png"
|
||||
[[ -f "$ICON_CANDIDATE" ]] && cp "$ICON_CANDIDATE" "$WORKDIR/$PKGROOT/v2rayn.png" || true
|
||||
|
||||
# Prepare bin structure
|
||||
mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box"
|
||||
|
||||
# Bundle / cores per-arch
|
||||
if [[ "$FORCE_NETCORE" -eq 0 ]]; then
|
||||
if download_v2rayn_bundle "$WORKDIR/$PKGROOT"; then
|
||||
echo "[*] Using v2rayN bundle archive."
|
||||
else
|
||||
echo "[*] Bundle failed, fallback to separate core + rules."
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
fi
|
||||
else
|
||||
echo "[*] --netcore specified: use separate core + rules."
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
@@ -362,22 +562,15 @@ if [[ "$FORCE_NETCORE" -eq 0 ]]; then
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
fi
|
||||
else
|
||||
echo "[*] --netcore specified: use separate core + rules."
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
fi
|
||||
|
||||
tar -C "$WORKDIR" -czf "$SOURCEDIR/$PKGROOT.tar.gz" "$PKGROOT"
|
||||
# Tarball
|
||||
mkdir -p "$SOURCEDIR"
|
||||
tar -C "$WORKDIR" -czf "$SOURCEDIR/$PKGROOT.tar.gz" "$PKGROOT"
|
||||
|
||||
# ===== Generate SPEC (heredoc with placeholders) ===================================
|
||||
SPECFILE="$SPECDIR/v2rayN.spec"
|
||||
cat > "$SPECFILE" <<'SPEC'
|
||||
# SPEC
|
||||
local SPECFILE="$SPECDIR/v2rayN.spec"
|
||||
mkdir -p "$SPECDIR"
|
||||
cat > "$SPECFILE" <<'SPEC'
|
||||
%global debug_package %{nil}
|
||||
%undefine _debuginfo_subpackages
|
||||
%undefine _debugsource_packages
|
||||
@@ -413,14 +606,14 @@ Geo files for Xray are placed at /opt/v2rayN/bin/xray; launcher will symlink the
|
||||
install -dm0755 %{buildroot}/opt/v2rayN
|
||||
cp -a * %{buildroot}/opt/v2rayN/
|
||||
|
||||
# Launcher (prioritize ELF first, then fall back to DLL; also create Geo symlinks for the user)
|
||||
# Launcher (prefer native ELF first, then DLL fallback; also create Geo symlinks for the user)
|
||||
install -dm0755 %{buildroot}%{_bindir}
|
||||
cat > %{buildroot}%{_bindir}/v2rayn << 'EOF'
|
||||
#!/usr/bin/bash
|
||||
set -euo pipefail
|
||||
DIR="/opt/v2rayN"
|
||||
|
||||
# --- SYMLINK GEO into user's XDG dir (new) ---
|
||||
# --- Symlink GEO files into user's XDG dir (first-run convenience) ---
|
||||
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
USR_GEO_DIR="$XDG_DATA_HOME/v2rayN/bin"
|
||||
SYS_XRAY_DIR="$DIR/bin/xray"
|
||||
@@ -432,10 +625,10 @@ for f in geosite.dat geoip.dat geoip-only-cn-private.dat Country.mmdb; do
|
||||
done
|
||||
# --- end GEO ---
|
||||
|
||||
# Prefer native ELF(apphost)
|
||||
# Prefer native apphost
|
||||
if [[ -x "$DIR/v2rayN" ]]; then exec "$DIR/v2rayN" "$@"; fi
|
||||
|
||||
# DLL fallback (for framework-dependent publish)
|
||||
# DLL fallback
|
||||
for dll in v2rayN.Desktop.dll v2rayN.dll; do
|
||||
if [[ -f "$DIR/$dll" ]]; then exec /usr/bin/dotnet "$DIR/$dll" "$@"; fi
|
||||
done
|
||||
@@ -446,7 +639,7 @@ exit 1
|
||||
EOF
|
||||
chmod 0755 %{buildroot}%{_bindir}/v2rayn
|
||||
|
||||
# Desktop File
|
||||
# Desktop file
|
||||
install -dm0755 %{buildroot}%{_datadir}/applications
|
||||
cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF'
|
||||
[Desktop Entry]
|
||||
@@ -459,7 +652,7 @@ Terminal=false
|
||||
Categories=Network;
|
||||
EOF
|
||||
|
||||
# icon
|
||||
# Icon
|
||||
if [ -f "%{_builddir}/__PKGROOT__/v2rayn.png" ]; then
|
||||
install -dm0755 %{buildroot}%{_datadir}/icons/hicolor/256x256/apps
|
||||
install -m0644 %{_builddir}/__PKGROOT__/v2rayn.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png
|
||||
@@ -480,32 +673,120 @@ fi
|
||||
%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png
|
||||
SPEC
|
||||
|
||||
# Optional: system-wide autostart (append block, keep original logic unchanged)
|
||||
if [[ "$AUTOSTART" -eq 1 ]]; then
|
||||
cat >> "$SPECFILE" <<'SPEC'
|
||||
# System-wide autostart entry
|
||||
%install
|
||||
install -dm0755 %{buildroot}/etc/xdg/autostart
|
||||
cat > %{buildroot}/etc/xdg/autostart/v2rayn.desktop << 'EOF'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=v2rayN (Autostart)
|
||||
Exec=v2rayn
|
||||
X-GNOME-Autostart-enabled=true
|
||||
NoDisplay=false
|
||||
EOF
|
||||
# Autostart injection (inside %install) and %files entry
|
||||
if [[ "$AUTOSTART" -eq 1 ]]; then
|
||||
awk '
|
||||
BEGIN{ins=0}
|
||||
/^%post$/ && !ins {
|
||||
print "# --- Autostart (.desktop) ---"
|
||||
print "install -dm0755 %{buildroot}/etc/xdg/autostart"
|
||||
print "cat > %{buildroot}/etc/xdg/autostart/v2rayn.desktop << '\''EOF'\''"
|
||||
print "[Desktop Entry]"
|
||||
print "Type=Application"
|
||||
print "Name=v2rayN (Autostart)"
|
||||
print "Exec=v2rayn"
|
||||
print "X-GNOME-Autostart-enabled=true"
|
||||
print "NoDisplay=false"
|
||||
print "EOF"
|
||||
ins=1
|
||||
}
|
||||
{print}
|
||||
' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE"
|
||||
|
||||
%files
|
||||
%config(noreplace) /etc/xdg/autostart/v2rayn.desktop
|
||||
SPEC
|
||||
awk '
|
||||
BEGIN{infiles=0; done=0}
|
||||
/^%files$/ {infiles=1}
|
||||
infiles && done==0 && $0 ~ /%{_datadir}\/icons\/hicolor\/256x256\/apps\/v2rayn\.png/ {
|
||||
print
|
||||
print "%config(noreplace) /etc/xdg/autostart/v2rayn.desktop"
|
||||
done=1
|
||||
next
|
||||
}
|
||||
{print}
|
||||
' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE"
|
||||
fi
|
||||
|
||||
# Replace placeholders
|
||||
sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE"
|
||||
sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE"
|
||||
|
||||
# ----- Select proper 'strip' per target arch on Ubuntu only (cross-binutils) -----
|
||||
# NOTE: We define only __strip to point to the target-arch strip.
|
||||
# DO NOT override __brp_strip (it must stay the brp script path).
|
||||
local STRIP_ARGS=()
|
||||
if [[ "$ID" == "ubuntu" ]]; then
|
||||
local STRIP_BIN=""
|
||||
if [[ "$short" == "x64" ]]; then
|
||||
STRIP_BIN="/usr/bin/x86_64-linux-gnu-strip"
|
||||
else
|
||||
STRIP_BIN="/usr/bin/aarch64-linux-gnu-strip"
|
||||
fi
|
||||
if [[ -x "$STRIP_BIN" ]]; then
|
||||
STRIP_ARGS=( --define "__strip $STRIP_BIN" )
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build RPM for this arch (force rpm --target to match compile arch)
|
||||
if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then
|
||||
rpmbuild -ba "$SPECFILE" --define "_topdir $TOPDIR" --target "$rpm_target" "${STRIP_ARGS[@]}"
|
||||
else
|
||||
rpmbuild -ba "$SPECFILE" --target "$rpm_target" "${STRIP_ARGS[@]}"
|
||||
fi
|
||||
|
||||
# Copy temporary rpmbuild to ~/rpmbuild on Debian/Ubuntu path
|
||||
if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then
|
||||
mkdir -p "$HOME/rpmbuild"
|
||||
rsync -a "$TOPDIR"/ "$HOME/rpmbuild"/
|
||||
TOPDIR="$HOME/rpmbuild"
|
||||
fi
|
||||
|
||||
echo "Build done for $short. RPM at:"
|
||||
local f
|
||||
for f in "${TOPDIR}/RPMS/${archdir}/v2rayN-${VERSION}-1"*.rpm; do
|
||||
[[ -e "$f" ]] || continue
|
||||
echo " $f"
|
||||
BUILT_RPMS+=("$f")
|
||||
done
|
||||
}
|
||||
|
||||
# ===== Arch selection and build orchestration =========================================
|
||||
case "${ARCH_OVERRIDE:-}" in
|
||||
"")
|
||||
# No --arch: use host architecture
|
||||
if [[ "$host_arch" == "aarch64" ]]; then
|
||||
build_for_arch arm64
|
||||
else
|
||||
build_for_arch x64
|
||||
fi
|
||||
;;
|
||||
x64|amd64)
|
||||
build_for_arch x64
|
||||
;;
|
||||
arm64|aarch64)
|
||||
build_for_arch arm64
|
||||
;;
|
||||
all)
|
||||
BUILT_ALL=1
|
||||
# Build x64 and arm64 separately; each package contains its own arch-only binaries.
|
||||
build_for_arch x64
|
||||
build_for_arch arm64
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unknown --arch '${ARCH_OVERRIDE}'. Use x64|arm64|all."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# ===== Final summary if building both arches ==========================================
|
||||
if [[ "$BUILT_ALL" -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "================ Build Summary (both architectures) ================"
|
||||
if [[ "${#BUILT_RPMS[@]}" -gt 0 ]]; then
|
||||
for rp in "${BUILT_RPMS[@]}"; do
|
||||
echo "$rp"
|
||||
done
|
||||
else
|
||||
echo "[WARN] No RPMs detected in summary (check build logs above)."
|
||||
fi
|
||||
echo "==================================================================="
|
||||
fi
|
||||
|
||||
# Injecting version/package root placeholders
|
||||
sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE"
|
||||
sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE"
|
||||
|
||||
# ===== Build RPM ================================================================
|
||||
rpmbuild -ba "$SPECFILE"
|
||||
|
||||
echo "Build done. RPM at:"
|
||||
ls -1 "${TOPDIR}/RPMS/$( [[ "$arch" == "aarch64" ]] && echo aarch64 || echo x86_64 )/v2rayN-${VERSION}-1"*.rpm
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.14.1</Version>
|
||||
<Version>7.14.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.3" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.3" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.3" />
|
||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.3" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.4" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.4" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.4" />
|
||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.4" />
|
||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||
@@ -20,7 +20,7 @@
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.9" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.9" />
|
||||
<PackageVersion Include="Splat.NLog" Version="15.4.1" />
|
||||
<PackageVersion Include="Splat.NLog" Version="15.5.3" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||
|
||||
@@ -64,7 +64,7 @@ public partial class CoreConfigSingboxService(Config config)
|
||||
|
||||
await GenRouting(singboxConfig);
|
||||
|
||||
await GenDns(singboxConfig);
|
||||
await GenDns(node, singboxConfig);
|
||||
|
||||
await GenExperimental(singboxConfig);
|
||||
|
||||
@@ -421,7 +421,7 @@ public partial class CoreConfigSingboxService(Config config)
|
||||
}
|
||||
await GenOutboundsList(proxyProfiles, singboxConfig);
|
||||
|
||||
await GenDns(singboxConfig);
|
||||
await GenDns(null, singboxConfig);
|
||||
await ConvertGeo2Ruleset(singboxConfig);
|
||||
|
||||
ret.Success = true;
|
||||
|
||||
@@ -2,14 +2,14 @@ namespace ServiceLib.Services.CoreConfig;
|
||||
|
||||
public partial class CoreConfigSingboxService
|
||||
{
|
||||
private async Task<int> GenDns(SingboxConfig singboxConfig)
|
||||
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
var item = await AppManager.Instance.GetDNSItem(ECoreType.sing_box);
|
||||
if (item != null && item.Enabled == true)
|
||||
{
|
||||
return await GenDnsCompatible(singboxConfig);
|
||||
return await GenDnsCompatible(node, singboxConfig);
|
||||
}
|
||||
|
||||
var simpleDNSItem = _config.SimpleDNSItem;
|
||||
@@ -19,6 +19,7 @@ public partial class CoreConfigSingboxService
|
||||
singboxConfig.dns ??= new Dns4Sbox();
|
||||
singboxConfig.dns.independent_cache = true;
|
||||
|
||||
// final dns
|
||||
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||
var useDirectDns = false;
|
||||
if (routing != null)
|
||||
@@ -32,6 +33,17 @@ public partial class CoreConfigSingboxService
|
||||
lastRule.Ip?.Contains("0.0.0.0/0") == true);
|
||||
}
|
||||
singboxConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag;
|
||||
|
||||
// Tun2SocksAddress
|
||||
if (node != null && Utils.IsDomain(node.Address))
|
||||
{
|
||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||
singboxConfig.dns.rules.Insert(0, new Rule4Sbox
|
||||
{
|
||||
server = Global.SingboxOutboundResolverTag,
|
||||
domain = [node.Address],
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -67,26 +79,27 @@ public partial class CoreConfigSingboxService
|
||||
{
|
||||
hostsDns.predefined = Global.PredefinedHosts;
|
||||
}
|
||||
var userHostsMap = simpleDNSItem.Hosts?
|
||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Where(line => line.Contains(' '))
|
||||
.ToDictionary(
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return parts[0];
|
||||
},
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var values = parts.Skip(1).ToList();
|
||||
return values;
|
||||
}
|
||||
);
|
||||
|
||||
if (userHostsMap != null)
|
||||
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||
{
|
||||
var userHostsMap = simpleDNSItem.Hosts?
|
||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Where(line => line.Contains(' '))
|
||||
.ToDictionary(
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return parts[0];
|
||||
},
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var values = parts.Skip(1).ToList();
|
||||
return values;
|
||||
}
|
||||
) ?? new Dictionary<string, List<string>>();
|
||||
|
||||
foreach (var kvp in userHostsMap)
|
||||
{
|
||||
hostsDns.predefined[kvp.Key] = kvp.Value;
|
||||
@@ -100,11 +113,11 @@ public partial class CoreConfigSingboxService
|
||||
{
|
||||
foreach (var host in systemHosts)
|
||||
{
|
||||
if (userHostsMap[host.Key] != null)
|
||||
if (hostsDns.predefined[host.Key] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
userHostsMap[host.Key] = new List<string> { host.Value };
|
||||
hostsDns.predefined[host.Key] = new List<string> { host.Value };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,7 +302,7 @@ public partial class CoreConfigSingboxService
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async Task<int> GenDnsCompatible(SingboxConfig singboxConfig)
|
||||
private async Task<int> GenDnsCompatible(ProfileItem? node, SingboxConfig singboxConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -319,6 +332,17 @@ public partial class CoreConfigSingboxService
|
||||
{
|
||||
await GenDnsDomainsLegacyCompatible(singboxConfig, item);
|
||||
}
|
||||
|
||||
// Tun2SocksAddress
|
||||
if (node != null && Utils.IsDomain(node.Address))
|
||||
{
|
||||
singboxConfig.dns.rules ??= new List<Rule4Sbox>();
|
||||
singboxConfig.dns.rules.Insert(0, new Rule4Sbox
|
||||
{
|
||||
server = Global.SingboxFinalResolverTag,
|
||||
domain = [node.Address],
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -434,7 +434,7 @@ public class UpdateService
|
||||
|
||||
var fileName = $"{type}-{srsName}.srs";
|
||||
var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName);
|
||||
var url = string.Format(srsUrl, type, $"{type}-{srsName}");
|
||||
var url = string.Format(srsUrl, type, $"{type}-{srsName}", srsName);
|
||||
|
||||
await DownloadGeoFile(url, fileName, targetPath, updateFunc);
|
||||
}
|
||||
|
||||
+10
-19
@@ -7,6 +7,8 @@ body:
|
||||
description: |-
|
||||
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
|
||||
options:
|
||||
- label: I have read all the comments in the issue template and ensured that this issue meet the requirements.
|
||||
required: true
|
||||
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
|
||||
required: true
|
||||
- label: I provided the complete config and logs, rather than just providing the truncated parts based on my own judgment.
|
||||
@@ -38,6 +40,8 @@ body:
|
||||
### For config
|
||||
Please provide the configuration files that can reproduce the problem, including the server and client.
|
||||
Don't just paste a big exported config file here. Eliminate useless inbound/outbound, rules, options, this can help determine the problem, if you really want to get help.
|
||||
After removing parts that do not affect reproduction, provide the actual running **complete** file.
|
||||
meaning of complete: This config can be directly used to start the core, **not a truncated part of the config**. For fields like keys, use newly generated valid parameters that have not been actually used to fill in.
|
||||
|
||||
### For logs
|
||||
Please set the log level to debug and dnsLog to true first.
|
||||
@@ -46,42 +50,29 @@ body:
|
||||
Provide the log of Xray-core, not the log output by the panel or other things.
|
||||
|
||||
### Finally
|
||||
After removing parts that do not affect reproduction, provide the actual running **complete** file, do not only provide inbound or outbound or a few lines of logs based on your own judgment.
|
||||
Put the content between the preset ```<details><pre><code>``` ```</code></pre></details>``` in the text box.
|
||||
If the problem is very clear that only related to one end (such as core startup failure/crash after correctly writing the config according to the documents), N/A can be filled in for unnecessary areas below.
|
||||
The specific content to be filled in each of the following text boxes needs to be placed between ```<details><pre><code>``` and ```</code></pre></details>```, like this
|
||||
```
|
||||
<details><pre><code>
|
||||
(config)
|
||||
</code></pre></details>
|
||||
```
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Client config
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Server config
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Client log
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Server log
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
+10
-19
@@ -7,6 +7,8 @@ body:
|
||||
description: |-
|
||||
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
|
||||
options:
|
||||
- label: 我读完了 issue 模板中的所有注释,确保填写符合要求。
|
||||
required: true
|
||||
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
|
||||
required: true
|
||||
- label: 我提供了完整的配置文件和日志,而不是出于自己的判断只给出截取的部分。
|
||||
@@ -38,6 +40,8 @@ body:
|
||||
### 对于配置文件
|
||||
请提供可以重现问题的配置文件,包括服务端和客户端。
|
||||
不要直接在这里黏贴一大段导出的 config 文件。去掉无用的出入站、规则、选项,这可以帮助确定问题,如果你真的想得到帮助。
|
||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件。
|
||||
完整的含义:可以直接使用这个配置启动核心,**不是截取的部分配置**。对于密钥等参数使用重新生成未实际使用的有效参数填充。
|
||||
|
||||
### 对于日志
|
||||
请先将日志等级设置为 debug, dnsLog 设置为true.
|
||||
@@ -46,42 +50,29 @@ body:
|
||||
提供 Xray-core 的日志,而不是面板或者别的东西输出的日志。
|
||||
|
||||
### 最后
|
||||
在去掉不影响复现的部分后,提供实际运行的**完整**文件,不要出于自己的判断只提供入站出站或者几行日志。
|
||||
把内容放在文本框预置的 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间。
|
||||
如果问题十分明确只出现在某一端(如按文档正确编写配置后核心启动失败/崩溃),可以在下面不需要的项目填入N/A.
|
||||
把下面的每格具体内容需要放在 ```<details><pre><code>``` 和 ```</code></pre></details>``` 中间,如
|
||||
```
|
||||
<details><pre><code>
|
||||
(config)
|
||||
</code></pre></details>
|
||||
```
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 客户端配置
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 服务端配置
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 客户端日志
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 服务端日志
|
||||
value: |-
|
||||
<details><pre><code>
|
||||
|
||||
</code></pre></details>
|
||||
validations:
|
||||
required: true
|
||||
|
||||
+31
-9
@@ -11,21 +11,23 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# macOS specific files
|
||||
*.DS_Store
|
||||
.DS_Store
|
||||
|
||||
# IDE specific files
|
||||
# IDE/editor specific files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Archive files
|
||||
# Archives and compressed files
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.tar
|
||||
*.gz
|
||||
*.bz2
|
||||
|
||||
# Binaries
|
||||
# Go build binaries
|
||||
xray
|
||||
xray_softfloat
|
||||
mockgen
|
||||
@@ -36,11 +38,31 @@ errorgen
|
||||
*.dat
|
||||
|
||||
# Build assets
|
||||
/build_assets
|
||||
/build_assets/
|
||||
|
||||
# Output from dlv test
|
||||
**/debug.*
|
||||
|
||||
# Certificates
|
||||
# Certificates and keys
|
||||
*.crt
|
||||
*.key
|
||||
|
||||
# Dependency directories (uncomment if needed)
|
||||
# vendor/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Coverage reports
|
||||
coverage.*
|
||||
|
||||
# Node modules (in case of frontend assets)
|
||||
node_modules/
|
||||
|
||||
# System files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Other common ignores
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
@@ -322,10 +322,18 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
outbounds[0].Target = originalDest
|
||||
}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
local := net.DestinationFromAddr(w.hub.Addr())
|
||||
if local.Address == net.AnyIP || local.Address == net.AnyIPv6 {
|
||||
if source.Address.Family().IsIPv4() {
|
||||
local.Address = net.AnyIP
|
||||
} else if source.Address.Family().IsIPv6() {
|
||||
local.Address = net.AnyIPv6
|
||||
}
|
||||
}
|
||||
|
||||
ctx = session.ContextWithInbound(ctx, &session.Inbound{
|
||||
Source: source,
|
||||
Local: net.DestinationFromAddr(w.hub.Addr()), // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
|
||||
Local: local, // Due to some limitations, in UDP connections, localIP is always equal to listen interface IP
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
})
|
||||
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
goerrors "errors"
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
"io"
|
||||
"math/big"
|
||||
gonet "net"
|
||||
"os"
|
||||
|
||||
"github.com/xtls/xray-core/common/dice"
|
||||
|
||||
"github.com/xtls/xray-core/app/proxyman"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
@@ -180,7 +181,11 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
content := session.ContentFromContext(ctx)
|
||||
if h.senderSettings != nil && h.senderSettings.TargetStrategy.HasStrategy() && ob.Target.Address.Family().IsDomain() && (content == nil || !content.SkipDNSResolve) {
|
||||
ips, err := internet.LookupForIP(ob.Target.Address.Domain(), h.senderSettings.TargetStrategy, nil)
|
||||
strategy := h.senderSettings.TargetStrategy
|
||||
if ob.Target.Network == net.Network_UDP && ob.OriginalTarget.Address != nil {
|
||||
strategy = strategy.GetDynamicStrategy(ob.OriginalTarget.Address.Family())
|
||||
}
|
||||
ips, err := internet.LookupForIP(ob.Target.Address.Domain(), strategy, nil)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to resolve ip for target ", ob.Target.Address.Domain())
|
||||
if h.senderSettings.TargetStrategy.ForceIP() {
|
||||
@@ -251,14 +256,6 @@ out:
|
||||
common.Interrupt(link.Reader)
|
||||
}
|
||||
|
||||
// Address implements internet.Dialer.
|
||||
func (h *Handler) Address() net.Address {
|
||||
if h.senderSettings == nil || h.senderSettings.Via == nil {
|
||||
return nil
|
||||
}
|
||||
return h.senderSettings.Via.AsAddress()
|
||||
}
|
||||
|
||||
func (h *Handler) DestIpAddress() net.IP {
|
||||
return internet.DestIpAddress()
|
||||
}
|
||||
@@ -293,41 +290,16 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return h.getStatCouterConnection(conn), nil
|
||||
}
|
||||
|
||||
errors.LogWarning(ctx, "failed to get outbound handler with tag: ", tag)
|
||||
errors.LogError(ctx, "failed to get outbound handler with tag: ", tag)
|
||||
return nil, errors.New("failed to get outbound handler with tag: " + tag)
|
||||
}
|
||||
|
||||
if h.senderSettings.Via != nil {
|
||||
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Local.Address
|
||||
errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
|
||||
}
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Source.Address
|
||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||
}
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
}
|
||||
|
||||
h.SetOutboundGateway(ctx, ob)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if conn, err := h.getUoTConnection(ctx, dest); err != os.ErrInvalid {
|
||||
@@ -342,6 +314,38 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connecti
|
||||
return conn, err
|
||||
}
|
||||
|
||||
func (h *Handler) SetOutboundGateway(ctx context.Context, ob *session.Outbound) {
|
||||
if ob.Gateway == nil && h.senderSettings != nil && h.senderSettings.Via != nil && !h.senderSettings.ProxySettings.HasTag() && (h.streamSettings.SocketSettings == nil || len(h.streamSettings.SocketSettings.DialerProxy) == 0) {
|
||||
var domain string
|
||||
addr := h.senderSettings.Via.AsAddress()
|
||||
domain = h.senderSettings.Via.GetDomain()
|
||||
switch {
|
||||
case h.senderSettings.ViaCidr != "":
|
||||
ob.Gateway = ParseRandomIP(addr, h.senderSettings.ViaCidr)
|
||||
|
||||
case domain == "origin":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Local.IsValid() && inbound.Local.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Local.Address
|
||||
errors.LogDebug(ctx, "use inbound local ip as sendthrough: ", inbound.Local.Address.String())
|
||||
}
|
||||
}
|
||||
case domain == "srcip":
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if inbound.Source.IsValid() && inbound.Source.Address.Family().IsIP() {
|
||||
ob.Gateway = inbound.Source.Address
|
||||
errors.LogDebug(ctx, "use inbound source ip as sendthrough: ", inbound.Source.Address.String())
|
||||
}
|
||||
}
|
||||
//case addr.Family().IsDomain():
|
||||
default:
|
||||
ob.Gateway = addr
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) getStatCouterConnection(conn stat.Connection) stat.Connection {
|
||||
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
||||
return &stat.CounterConnection{
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
type FreedomConfig struct {
|
||||
@@ -47,27 +48,27 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
||||
}
|
||||
switch strings.ToLower(targetStrategy) {
|
||||
case "asis", "":
|
||||
config.DomainStrategy = freedom.Config_AS_IS
|
||||
config.DomainStrategy = internet.DomainStrategy_AS_IS
|
||||
case "useip":
|
||||
config.DomainStrategy = freedom.Config_USE_IP
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP
|
||||
case "useipv4":
|
||||
config.DomainStrategy = freedom.Config_USE_IP4
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP4
|
||||
case "useipv6":
|
||||
config.DomainStrategy = freedom.Config_USE_IP6
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP6
|
||||
case "useipv4v6":
|
||||
config.DomainStrategy = freedom.Config_USE_IP46
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP46
|
||||
case "useipv6v4":
|
||||
config.DomainStrategy = freedom.Config_USE_IP64
|
||||
config.DomainStrategy = internet.DomainStrategy_USE_IP64
|
||||
case "forceip":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP
|
||||
case "forceipv4":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP4
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP4
|
||||
case "forceipv6":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP6
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP6
|
||||
case "forceipv4v6":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP46
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP46
|
||||
case "forceipv6v4":
|
||||
config.DomainStrategy = freedom.Config_FORCE_IP64
|
||||
config.DomainStrategy = internet.DomainStrategy_FORCE_IP64
|
||||
default:
|
||||
return nil, errors.New("unsupported domain strategy: ", targetStrategy)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
. "github.com/xtls/xray-core/infra/conf"
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
)
|
||||
|
||||
func TestFreedomConfig(t *testing.T) {
|
||||
@@ -23,7 +24,7 @@ func TestFreedomConfig(t *testing.T) {
|
||||
}`,
|
||||
Parser: loadJSON(creator),
|
||||
Output: &freedom.Config{
|
||||
DomainStrategy: freedom.Config_AS_IS,
|
||||
DomainStrategy: internet.DomainStrategy_AS_IS,
|
||||
DestinationOverride: &freedom.DestinationOverride{
|
||||
Server: &protocol.ServerEndpoint{
|
||||
Address: &net.IPOrDomain{
|
||||
|
||||
@@ -1,44 +1 @@
|
||||
package freedom
|
||||
|
||||
var strategy = [][]byte{
|
||||
// name strategy, prefer, fallback
|
||||
{0, 0, 0}, // AsIs none, /, /
|
||||
{1, 0, 0}, // UseIP use, both, none
|
||||
{1, 4, 0}, // UseIPv4 use, 4, none
|
||||
{1, 6, 0}, // UseIPv6 use, 6, none
|
||||
{1, 4, 6}, // UseIPv4v6 use, 4, 6
|
||||
{1, 6, 4}, // UseIPv6v4 use, 6, 4
|
||||
{2, 0, 0}, // ForceIP force, both, none
|
||||
{2, 4, 0}, // ForceIPv4 force, 4, none
|
||||
{2, 6, 0}, // ForceIPv6 force, 6, none
|
||||
{2, 4, 6}, // ForceIPv4v6 force, 4, 6
|
||||
{2, 6, 4}, // ForceIPv6v4 force, 6, 4
|
||||
}
|
||||
|
||||
func (c *Config) hasStrategy() bool {
|
||||
return strategy[c.DomainStrategy][0] != 0
|
||||
}
|
||||
|
||||
func (c *Config) forceIP() bool {
|
||||
return strategy[c.DomainStrategy][0] == 2
|
||||
}
|
||||
|
||||
func (c *Config) preferIP4() bool {
|
||||
return strategy[c.DomainStrategy][1] == 4 || strategy[c.DomainStrategy][1] == 0
|
||||
}
|
||||
|
||||
func (c *Config) preferIP6() bool {
|
||||
return strategy[c.DomainStrategy][1] == 6 || strategy[c.DomainStrategy][1] == 0
|
||||
}
|
||||
|
||||
func (c *Config) hasFallback() bool {
|
||||
return strategy[c.DomainStrategy][2] != 0
|
||||
}
|
||||
|
||||
func (c *Config) fallbackIP4() bool {
|
||||
return strategy[c.DomainStrategy][2] == 4
|
||||
}
|
||||
|
||||
func (c *Config) fallbackIP6() bool {
|
||||
return strategy[c.DomainStrategy][2] == 6
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package freedom
|
||||
|
||||
import (
|
||||
protocol "github.com/xtls/xray-core/common/protocol"
|
||||
internet "github.com/xtls/xray-core/transport/internet"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -21,79 +22,6 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Config_DomainStrategy int32
|
||||
|
||||
const (
|
||||
Config_AS_IS Config_DomainStrategy = 0
|
||||
Config_USE_IP Config_DomainStrategy = 1
|
||||
Config_USE_IP4 Config_DomainStrategy = 2
|
||||
Config_USE_IP6 Config_DomainStrategy = 3
|
||||
Config_USE_IP46 Config_DomainStrategy = 4
|
||||
Config_USE_IP64 Config_DomainStrategy = 5
|
||||
Config_FORCE_IP Config_DomainStrategy = 6
|
||||
Config_FORCE_IP4 Config_DomainStrategy = 7
|
||||
Config_FORCE_IP6 Config_DomainStrategy = 8
|
||||
Config_FORCE_IP46 Config_DomainStrategy = 9
|
||||
Config_FORCE_IP64 Config_DomainStrategy = 10
|
||||
)
|
||||
|
||||
// Enum value maps for Config_DomainStrategy.
|
||||
var (
|
||||
Config_DomainStrategy_name = map[int32]string{
|
||||
0: "AS_IS",
|
||||
1: "USE_IP",
|
||||
2: "USE_IP4",
|
||||
3: "USE_IP6",
|
||||
4: "USE_IP46",
|
||||
5: "USE_IP64",
|
||||
6: "FORCE_IP",
|
||||
7: "FORCE_IP4",
|
||||
8: "FORCE_IP6",
|
||||
9: "FORCE_IP46",
|
||||
10: "FORCE_IP64",
|
||||
}
|
||||
Config_DomainStrategy_value = map[string]int32{
|
||||
"AS_IS": 0,
|
||||
"USE_IP": 1,
|
||||
"USE_IP4": 2,
|
||||
"USE_IP6": 3,
|
||||
"USE_IP46": 4,
|
||||
"USE_IP64": 5,
|
||||
"FORCE_IP": 6,
|
||||
"FORCE_IP4": 7,
|
||||
"FORCE_IP6": 8,
|
||||
"FORCE_IP46": 9,
|
||||
"FORCE_IP64": 10,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Config_DomainStrategy) Enum() *Config_DomainStrategy {
|
||||
p := new(Config_DomainStrategy)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Config_DomainStrategy) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Config_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Config_DomainStrategy) Type() protoreflect.EnumType {
|
||||
return &file_proxy_freedom_config_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Config_DomainStrategy) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config_DomainStrategy.Descriptor instead.
|
||||
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3, 0}
|
||||
}
|
||||
|
||||
type DestinationOverride struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -330,12 +258,12 @@ type Config struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.freedom.Config_DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||
DomainStrategy internet.DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DestinationOverride *DestinationOverride `protobuf:"bytes,3,opt,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
UserLevel uint32 `protobuf:"varint,4,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
@@ -368,11 +296,11 @@ func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Config) GetDomainStrategy() Config_DomainStrategy {
|
||||
func (x *Config) GetDomainStrategy() internet.DomainStrategy {
|
||||
if x != nil {
|
||||
return x.DomainStrategy
|
||||
}
|
||||
return Config_AS_IS
|
||||
return internet.DomainStrategy(0)
|
||||
}
|
||||
|
||||
func (x *Config) GetDestinationOverride() *DestinationOverride {
|
||||
@@ -418,81 +346,72 @@ var file_proxy_freedom_config_proto_rawDesc = []byte{
|
||||
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d,
|
||||
0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||
0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72, 0x61,
|
||||
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73,
|
||||
0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63, 0x6b,
|
||||
0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61,
|
||||
0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d, 0x6d,
|
||||
0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e, 0x12,
|
||||
0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61, 0x78,
|
||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74,
|
||||
0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x64,
|
||||
0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08,
|
||||
0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x61,
|
||||
0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65, 0x6c,
|
||||
0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19, 0x0a,
|
||||
0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0x97, 0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x78,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f,
|
||||
0x6d, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69,
|
||||
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13,
|
||||
0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72,
|
||||
0x69, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65,
|
||||
0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76,
|
||||
0x65, 0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e,
|
||||
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x63, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06,
|
||||
0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x0e, 0x44, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x5f,
|
||||
0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x10, 0x01,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x10, 0x02, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x55, 0x53, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53,
|
||||
0x45, 0x5f, 0x49, 0x50, 0x34, 0x36, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x5f,
|
||||
0x49, 0x50, 0x36, 0x34, 0x10, 0x05, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f,
|
||||
0x49, 0x50, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50,
|
||||
0x34, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36,
|
||||
0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x34, 0x36,
|
||||
0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x36, 0x34,
|
||||
0x10, 0x0a, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50, 0x01, 0x5a, 0x27,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f,
|
||||
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x13, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3c, 0x0a, 0x06, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, 0x08, 0x46, 0x72,
|
||||
0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x61,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x70,
|
||||
0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x54, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65,
|
||||
0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
||||
0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e,
|
||||
0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||
0x61, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4d, 0x61, 0x78, 0x12, 0x22, 0x0a, 0x0d,
|
||||
0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x69, 0x6e,
|
||||
0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x6d, 0x61,
|
||||
0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x70, 0x6c, 0x69,
|
||||
0x74, 0x4d, 0x61, 0x78, 0x22, 0xb2, 0x01, 0x0a, 0x05, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x09, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x4d, 0x61, 0x78, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x08, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x6c,
|
||||
0x61, 0x79, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x65,
|
||||
0x6c, 0x61, 0x79, 0x4d, 0x61, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x19,
|
||||
0x0a, 0x08, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x22, 0xe9, 0x02, 0x0a, 0x06, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x50, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x73,
|
||||
0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e,
|
||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x74,
|
||||
0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x5a, 0x0a, 0x14, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x13, 0x64,
|
||||
0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x76, 0x65,
|
||||
0x6c, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x06, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||
0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x2e, 0x4e, 0x6f, 0x69, 0x73, 0x65, 0x52, 0x06, 0x6e,
|
||||
0x6f, 0x69, 0x73, 0x65, 0x73, 0x42, 0x58, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x50,
|
||||
0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74,
|
||||
0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x2f, 0x66, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x46, 0x72, 0x65, 0x65, 0x64, 0x6f, 0x6d, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -507,22 +426,21 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
|
||||
return file_proxy_freedom_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_proxy_freedom_config_proto_goTypes = []any{
|
||||
(Config_DomainStrategy)(0), // 0: xray.proxy.freedom.Config.DomainStrategy
|
||||
(*DestinationOverride)(nil), // 1: xray.proxy.freedom.DestinationOverride
|
||||
(*Fragment)(nil), // 2: xray.proxy.freedom.Fragment
|
||||
(*Noise)(nil), // 3: xray.proxy.freedom.Noise
|
||||
(*Config)(nil), // 4: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint
|
||||
(*DestinationOverride)(nil), // 0: xray.proxy.freedom.DestinationOverride
|
||||
(*Fragment)(nil), // 1: xray.proxy.freedom.Fragment
|
||||
(*Noise)(nil), // 2: xray.proxy.freedom.Noise
|
||||
(*Config)(nil), // 3: xray.proxy.freedom.Config
|
||||
(*protocol.ServerEndpoint)(nil), // 4: xray.common.protocol.ServerEndpoint
|
||||
(internet.DomainStrategy)(0), // 5: xray.transport.internet.DomainStrategy
|
||||
}
|
||||
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
||||
5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
0, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.proxy.freedom.Config.DomainStrategy
|
||||
1, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
2, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
3, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
4, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||
5, // 1: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||
0, // 2: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||
1, // 3: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||
2, // 4: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
@@ -540,14 +458,13 @@ func file_proxy_freedom_config_proto_init() {
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proxy_freedom_config_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_proxy_freedom_config_proto_goTypes,
|
||||
DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
|
||||
EnumInfos: file_proxy_freedom_config_proto_enumTypes,
|
||||
MessageInfos: file_proxy_freedom_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proxy_freedom_config_proto = out.File
|
||||
|
||||
@@ -7,6 +7,7 @@ option java_package = "com.xray.proxy.freedom";
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "common/protocol/server_spec.proto";
|
||||
import "transport/internet/config.proto";
|
||||
|
||||
message DestinationOverride {
|
||||
xray.common.protocol.ServerEndpoint server = 1;
|
||||
@@ -32,20 +33,7 @@ message Noise {
|
||||
}
|
||||
|
||||
message Config {
|
||||
enum DomainStrategy {
|
||||
AS_IS = 0;
|
||||
USE_IP = 1;
|
||||
USE_IP4 = 2;
|
||||
USE_IP6 = 3;
|
||||
USE_IP46 = 4;
|
||||
USE_IP64 = 5;
|
||||
FORCE_IP = 6;
|
||||
FORCE_IP4 = 7;
|
||||
FORCE_IP6 = 8;
|
||||
FORCE_IP46 = 9;
|
||||
FORCE_IP64 = 10;
|
||||
}
|
||||
DomainStrategy domain_strategy = 1;
|
||||
xray.transport.internet.DomainStrategy domain_strategy = 1;
|
||||
DestinationOverride destination_override = 3;
|
||||
uint32 user_level = 4;
|
||||
Fragment fragment = 5;
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
"github.com/xtls/xray-core/common/utils"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/stats"
|
||||
"github.com/xtls/xray-core/proxy"
|
||||
@@ -35,8 +34,8 @@ var useSplice bool
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
h := new(Handler)
|
||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {
|
||||
return h.Init(config.(*Config), pm, d)
|
||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
|
||||
return h.Init(config.(*Config), pm)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -53,16 +52,13 @@ func init() {
|
||||
// Handler handles Freedom connections.
|
||||
type Handler struct {
|
||||
policyManager policy.Manager
|
||||
dns dns.Client
|
||||
config *Config
|
||||
}
|
||||
|
||||
// Init initializes the Handler with necessary parameters.
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||
h.config = config
|
||||
h.policyManager = pm
|
||||
h.dns = d
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,28 +67,6 @@ func (h *Handler) policy() policy.Session {
|
||||
return p
|
||||
}
|
||||
|
||||
func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
|
||||
ips, _, err := h.dns.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: (localAddr == nil || localAddr.Family().IsIPv4()) && h.config.preferIP4(),
|
||||
IPv6Enable: (localAddr == nil || localAddr.Family().IsIPv6()) && h.config.preferIP6(),
|
||||
})
|
||||
{ // Resolve fallback
|
||||
if (len(ips) == 0 || err != nil) && h.config.hasFallback() && localAddr == nil {
|
||||
ips, _, err = h.dns.LookupIP(domain, dns.IPOption{
|
||||
IPv4Enable: h.config.fallbackIP4(),
|
||||
IPv6Enable: h.config.fallbackIP6(),
|
||||
})
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", domain)
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
return net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
}
|
||||
|
||||
func isValidAddress(addr *net.IPOrDomain) bool {
|
||||
if addr == nil {
|
||||
return false
|
||||
@@ -114,6 +88,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
|
||||
destination := ob.Target
|
||||
origTargetAddr := ob.OriginalTarget.Address
|
||||
if origTargetAddr == nil {
|
||||
origTargetAddr = ob.Target.Address
|
||||
}
|
||||
dialer.SetOutboundGateway(ctx, ob)
|
||||
outGateway := ob.Gateway
|
||||
UDPOverride := net.UDPDestination(nil, 0)
|
||||
if h.config.DestinationOverride != nil {
|
||||
server := h.config.DestinationOverride.Server
|
||||
@@ -133,17 +113,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
var conn stat.Connection
|
||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||
dialDest := destination
|
||||
if h.config.hasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||
ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())
|
||||
if ip != nil {
|
||||
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||
strategy := h.config.DomainStrategy
|
||||
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
|
||||
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
|
||||
}
|
||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
if h.config.DomainStrategy.ForceIP() {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
dialDest = net.Destination{
|
||||
Network: dialDest.Network,
|
||||
Address: ip,
|
||||
Address: net.IPAddress(ips[dice.Roll(len(ips))]),
|
||||
Port: dialDest.Port,
|
||||
}
|
||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||
} else if h.config.forceIP() {
|
||||
return dns.ErrEmptyResponse
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +190,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
writer = buf.NewWriter(conn)
|
||||
}
|
||||
} else {
|
||||
writer = NewPacketWriter(conn, h, ctx, UDPOverride, destination)
|
||||
writer = NewPacketWriter(conn, h, UDPOverride, destination)
|
||||
if h.config.Noises != nil {
|
||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||
writer = &NoisePacketWriter{
|
||||
@@ -339,7 +326,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
}
|
||||
|
||||
// DialDest means the dial target used in the dialer when creating conn
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
@@ -360,9 +347,9 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride
|
||||
PacketConnWrapper: c,
|
||||
Counter: counter,
|
||||
Handler: h,
|
||||
Context: ctx,
|
||||
UDPOverride: UDPOverride,
|
||||
resolvedUDPAddr: resolvedUDPAddr,
|
||||
ResolvedUDPAddr: resolvedUDPAddr,
|
||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -373,14 +360,14 @@ type PacketWriter struct {
|
||||
*internet.PacketConnWrapper
|
||||
stats.Counter
|
||||
*Handler
|
||||
context.Context
|
||||
UDPOverride net.Destination
|
||||
|
||||
// Dest of udp packets might be a domain, we will resolve them to IP
|
||||
// But resolver will return a random one if the domain has many IPs
|
||||
// Resulting in these packets being sent to many different IPs randomly
|
||||
// So, cache and keep the resolve result
|
||||
resolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||
ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||
LocalAddr net.Address
|
||||
}
|
||||
|
||||
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
@@ -400,20 +387,22 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
b.UDP.Port = w.UDPOverride.Port
|
||||
}
|
||||
if b.UDP.Address.Family().IsDomain() {
|
||||
if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||
if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||
b.UDP.Address = ip
|
||||
} else {
|
||||
ShouldUseSystemResolver := true
|
||||
if w.Handler.config.hasStrategy() {
|
||||
ip = w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
|
||||
if ip != nil {
|
||||
if w.Handler.config.DomainStrategy.HasStrategy() {
|
||||
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr)
|
||||
if err != nil {
|
||||
// drop packet if resolve failed when forceIP
|
||||
if w.Handler.config.DomainStrategy.ForceIP() {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
ip = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
ShouldUseSystemResolver = false
|
||||
}
|
||||
// drop packet if resolve failed when forceIP
|
||||
if ip == nil && w.Handler.config.forceIP() {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if ShouldUseSystemResolver {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||
@@ -425,7 +414,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
}
|
||||
}
|
||||
if ip != nil {
|
||||
b.UDP.Address, _ = w.resolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
|
||||
b.UDP.Address, _ = w.ResolvedUDPAddr.LoadOrStore(b.UDP.Address.Domain(), ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -496,7 +485,10 @@ func (w *NoisePacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
|
||||
err = w.Writer.WriteMultiBuffer(buf.MultiBuffer{buf.FromBytes(noise)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.DelayMin != 0 || n.DelayMax != 0 {
|
||||
time.Sleep(time.Duration(crypto.RandBetween(int64(n.DelayMin), int64(n.DelayMax))) * time.Millisecond)
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/xtls/xray-core/proxy/freedom"
|
||||
"github.com/xtls/xray-core/proxy/socks"
|
||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
xproxy "golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
@@ -83,7 +84,7 @@ func TestResolveIP(t *testing.T) {
|
||||
{
|
||||
Tag: "direct",
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||
DomainStrategy: freedom.Config_USE_IP,
|
||||
DomainStrategy: internet.DomainStrategy_USE_IP,
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user