mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-08 09:13:17 +03:00
Compare commits
37 Commits
v1.3-beta5
...
v1.3-beta7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bd143b9bd | ||
|
|
3c10ed3a0c | ||
|
|
ac508fe472 | ||
|
|
7141ed6e0c | ||
|
|
1574012767 | ||
|
|
09ee24ce63 | ||
|
|
2113ade341 | ||
|
|
1d0e052971 | ||
|
|
0b4d0da1b1 | ||
|
|
4e7eed989b | ||
|
|
0708f871d0 | ||
|
|
f95c617844 | ||
|
|
afdd32b656 | ||
|
|
20acbbe68f | ||
|
|
a486add3ec | ||
|
|
a0d27078bd | ||
|
|
afcc8b204f | ||
|
|
9b762e3c2e | ||
|
|
de1b5971e1 | ||
|
|
5c20d0b4d5 | ||
|
|
9df96ac7f1 | ||
|
|
87cd925144 | ||
|
|
fecb796000 | ||
|
|
cfb6c804aa | ||
|
|
11c50c7558 | ||
|
|
34cc7f176e | ||
|
|
b54da9c6af | ||
|
|
f44f86b832 | ||
|
|
4ebf40f582 | ||
|
|
53e4302143 | ||
|
|
cf778eda4f | ||
|
|
bb63429079 | ||
|
|
f7f9a7ae20 | ||
|
|
8699412a4c | ||
|
|
0d7aa19cd1 | ||
|
|
50a7295360 | ||
|
|
e57b6ae98d |
@@ -8,6 +8,10 @@ The universal proxy platform.
|
|||||||
|
|
||||||
https://sing-box.sagernet.org
|
https://sing-box.sagernet.org
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
https://community.sagernet.org/c/sing-box/
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
#### 1.3-beta7
|
||||||
|
|
||||||
|
* Add `path` and `headers` options for HTTP outbound
|
||||||
|
* Add multi-user support for Shadowsocks legacy AEAD inbound
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.2.4
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.3-beta6
|
||||||
|
|
||||||
|
* Fix WireGuard reconnect
|
||||||
|
* Perform URLTest recheck after network changes
|
||||||
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
#### 1.3-beta5
|
#### 1.3-beta5
|
||||||
|
|
||||||
* Add Clash.Meta API compatibility for Clash API
|
* Add Clash.Meta API compatibility for Clash API
|
||||||
|
|||||||
12
go.mod
12
go.mod
@@ -4,7 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
berty.tech/go-libtor v1.0.385
|
berty.tech/go-libtor v1.0.385
|
||||||
github.com/Dreamacro/clash v1.14.0
|
github.com/Dreamacro/clash v1.15.0
|
||||||
github.com/caddyserver/certmagic v0.17.2
|
github.com/caddyserver/certmagic v0.17.2
|
||||||
github.com/cretz/bine v0.2.0
|
github.com/cretz/bine v0.2.0
|
||||||
github.com/dustin/go-humanize v1.0.1
|
github.com/dustin/go-humanize v1.0.1
|
||||||
@@ -25,12 +25,12 @@ require (
|
|||||||
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.2.3-0.20230413023204-48b019b13e78
|
github.com/sagernet/sing v0.2.3
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230412123110-1a7c32b4e2e7
|
github.com/sagernet/sing-shadowsocks v0.2.1
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230409094821-9abef019436f
|
github.com/sagernet/sing-shadowtls v0.1.1
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
|
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
|
||||||
github.com/sagernet/sing-vmess v0.1.4-0.20230412122845-9470e68f5e45
|
github.com/sagernet/sing-vmess v0.1.4
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
||||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
||||||
|
|||||||
26
go.sum
26
go.sum
@@ -1,7 +1,7 @@
|
|||||||
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
||||||
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
||||||
github.com/Dreamacro/clash v1.14.0 h1:ehJ/C/1m9LEjmME72WSE/Y2YqbR3Q54AbjqiRCvtyW4=
|
github.com/Dreamacro/clash v1.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE=
|
||||||
github.com/Dreamacro/clash v1.14.0/go.mod h1:ia2CU7V713H1QdCqMwOLK9U9V5Ay8X0voj3yQr2tk+I=
|
github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE=
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
@@ -101,8 +101,6 @@ github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt
|
|||||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023437-ec061884b992 h1:WkcHhOX3ce9ElLKDUQKJrAt7SjpKNnASsPbMfqfZEPc=
|
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023437-ec061884b992/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035 h1:KttYh6bBhIw8Y6/Ljn7CGwC3CKZn788rzMJmeAKjY+8=
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035 h1:KttYh6bBhIw8Y6/Ljn7CGwC3CKZn788rzMJmeAKjY+8=
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||||
@@ -113,18 +111,18 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||||
github.com/sagernet/sing v0.2.3-0.20230413023204-48b019b13e78 h1:bTE9RgURmiFiTjXaYN6q9BYPTBPKIzlFYNy2p+WOubI=
|
github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
|
||||||
github.com/sagernet/sing v0.2.3-0.20230413023204-48b019b13e78/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440 h1:VH8/BcOVuApHtS+vKP+khxlGRcXH7KKhgkTDtNynqSQ=
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440/go.mod h1:69PNSHyEmXdjf6C+bXBOdr2GQnPeEyWjIzo/MV8gmz8=
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230412123110-1a7c32b4e2e7 h1:3WDMIF1aE/twc5gJ+9PF2ZJqUxwZ80MPtNBKE3yBevU=
|
github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230412123110-1a7c32b4e2e7/go.mod h1:WoVjGUvRqsx5yhYeDAB5CijCHpNDi0LUPHl3cf7u8Lc=
|
github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230409094821-9abef019436f h1:qzQvpcDm60zPW8UlZa8UEaBoFORFeGAnhDncPc3VWT4=
|
github.com/sagernet/sing-shadowtls v0.1.1 h1:Gf8YD/4zCjfM9xxVzI0QVYAnjMCtsDHcIp84CUdY3VA=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230409094821-9abef019436f/go.mod h1:MxB+Q9H0pAHcrlvNmwSs1crljRwHFFVhtXyOMBy44Nw=
|
github.com/sagernet/sing-shadowtls v0.1.1/go.mod h1:espnHDPRQeG95ZoU3xfHDFnc6Nt4GvbbuPV2okN+x/E=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab h1:a9oeWuPBuIZ70qMhIIH6RrYhp886xN9jJIwsuu4ZFUo=
|
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab h1:a9oeWuPBuIZ70qMhIIH6RrYhp886xN9jJIwsuu4ZFUo=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab/go.mod h1:4YxIDEkkCjGXDOTMPw1SXpLmCQUFAWuaQN250oo+928=
|
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab/go.mod h1:4YxIDEkkCjGXDOTMPw1SXpLmCQUFAWuaQN250oo+928=
|
||||||
github.com/sagernet/sing-vmess v0.1.4-0.20230412122845-9470e68f5e45 h1:QqYhWah3u+o2tvLRuTfEu3BwsGpf/wNnVK/VNQV2YBM=
|
github.com/sagernet/sing-vmess v0.1.4 h1:aZ03KgmR9COPitVqo8NTPHeaHmbJYDZ8mkumnUV4oGQ=
|
||||||
github.com/sagernet/sing-vmess v0.1.4-0.20230412122845-9470e68f5e45/go.mod h1:eULig3LgaeNiWSquSlzXF42Joypsj3fO1W+Qy93o6hk=
|
github.com/sagernet/sing-vmess v0.1.4/go.mod h1:NensKZJDgfPsUf3TzFD8kTuzI3CQfN1Tj3Eygti5Isg=
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing-shadowsocks"
|
||||||
|
"github.com/sagernet/sing-shadowsocks/shadowaead"
|
||||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
@@ -25,7 +27,7 @@ var (
|
|||||||
|
|
||||||
type ShadowsocksMulti struct {
|
type ShadowsocksMulti struct {
|
||||||
myInboundAdapter
|
myInboundAdapter
|
||||||
service *shadowaead_2022.MultiService[int]
|
service shadowsocks.MultiService[int]
|
||||||
users []option.ShadowsocksUser
|
users []option.ShadowsocksUser
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,16 +51,26 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
|
|||||||
} else {
|
} else {
|
||||||
udpTimeout = int64(C.UDPTimeout.Seconds())
|
udpTimeout = int64(C.UDPTimeout.Seconds())
|
||||||
}
|
}
|
||||||
if !common.Contains(shadowaead_2022.List, options.Method) {
|
var (
|
||||||
|
service shadowsocks.MultiService[int]
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if common.Contains(shadowaead_2022.List, options.Method) {
|
||||||
|
service, err = shadowaead_2022.NewMultiServiceWithPassword[int](
|
||||||
|
options.Method,
|
||||||
|
options.Password,
|
||||||
|
udpTimeout,
|
||||||
|
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound),
|
||||||
|
router.TimeFunc(),
|
||||||
|
)
|
||||||
|
} else if common.Contains(shadowaead.List, options.Method) {
|
||||||
|
service, err = shadowaead.NewMultiService[int](
|
||||||
|
options.Method,
|
||||||
|
udpTimeout,
|
||||||
|
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
|
||||||
|
} else {
|
||||||
return nil, E.New("unsupported method: " + options.Method)
|
return nil, E.New("unsupported method: " + options.Method)
|
||||||
}
|
}
|
||||||
service, err := shadowaead_2022.NewMultiServiceWithPassword[int](
|
|
||||||
options.Method,
|
|
||||||
options.Password,
|
|
||||||
udpTimeout,
|
|
||||||
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound),
|
|
||||||
router.TimeFunc(),
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type ShadowsocksInboundOptions struct {
|
|||||||
ListenOptions
|
ListenOptions
|
||||||
Network NetworkList `json:"network,omitempty"`
|
Network NetworkList `json:"network,omitempty"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password,omitempty"`
|
||||||
Users []ShadowsocksUser `json:"users,omitempty"`
|
Users []ShadowsocksUser `json:"users,omitempty"`
|
||||||
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ func (a *myOutboundAdapter) Network() []string {
|
|||||||
return a.network
|
return a.network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *myOutboundAdapter) NewError(ctx context.Context, err error) {
|
||||||
|
NewError(a.logger, ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
|
func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
@@ -121,3 +125,12 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro
|
|||||||
}
|
}
|
||||||
return bufio.CopyConn(ctx, conn, serverConn)
|
return bufio.CopyConn(ctx, conn, serverConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewError(logger log.ContextLogger, ctx context.Context, err error) {
|
||||||
|
common.Close(err)
|
||||||
|
if E.IsClosedOrCanceled(err) {
|
||||||
|
logger.DebugContext(ctx, "connection closed: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.ErrorContext(ctx, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ adapter.Outbound = (*URLTest)(nil)
|
_ adapter.Outbound = (*URLTest)(nil)
|
||||||
_ adapter.OutboundGroup = (*URLTest)(nil)
|
_ adapter.OutboundGroup = (*URLTest)(nil)
|
||||||
|
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
@@ -71,7 +72,8 @@ func (s *URLTest) Start() error {
|
|||||||
outbounds = append(outbounds, detour)
|
outbounds = append(outbounds, detour)
|
||||||
}
|
}
|
||||||
s.group = NewURLTestGroup(s.ctx, s.router, s.logger, outbounds, s.link, s.interval, s.tolerance)
|
s.group = NewURLTestGroup(s.ctx, s.router, s.logger, outbounds, s.link, s.interval, s.tolerance)
|
||||||
return s.group.Start()
|
go s.group.CheckOutbounds()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) Close() error {
|
func (s *URLTest) Close() error {
|
||||||
@@ -93,6 +95,7 @@ func (s *URLTest) URLTest(ctx context.Context, link string) (map[string]uint16,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
s.group.Start()
|
||||||
outbound := s.group.Select(network)
|
outbound := s.group.Select(network)
|
||||||
conn, err := outbound.DialContext(ctx, network, destination)
|
conn, err := outbound.DialContext(ctx, network, destination)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -104,6 +107,7 @@ func (s *URLTest) DialContext(ctx context.Context, network string, destination M
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
s.group.Start()
|
||||||
outbound := s.group.Select(N.NetworkUDP)
|
outbound := s.group.Select(N.NetworkUDP)
|
||||||
conn, err := outbound.ListenPacket(ctx, destination)
|
conn, err := outbound.ListenPacket(ctx, destination)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -122,6 +126,11 @@ func (s *URLTest) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
|
|||||||
return NewPacketConnection(ctx, s, conn, metadata)
|
return NewPacketConnection(ctx, s, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *URLTest) InterfaceUpdated() error {
|
||||||
|
go s.group.CheckOutbounds()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type URLTestGroup struct {
|
type URLTestGroup struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
@@ -132,6 +141,7 @@ type URLTestGroup struct {
|
|||||||
tolerance uint16
|
tolerance uint16
|
||||||
history *urltest.HistoryStorage
|
history *urltest.HistoryStorage
|
||||||
|
|
||||||
|
access sync.Mutex
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
}
|
}
|
||||||
@@ -162,13 +172,23 @@ func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Start() error {
|
func (g *URLTestGroup) Start() {
|
||||||
|
if g.ticker != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.access.Lock()
|
||||||
|
defer g.access.Unlock()
|
||||||
|
if g.ticker != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
g.ticker = time.NewTicker(g.interval)
|
g.ticker = time.NewTicker(g.interval)
|
||||||
go g.loopCheck()
|
go g.loopCheck()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Close() error {
|
func (g *URLTestGroup) Close() error {
|
||||||
|
if g.ticker == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
close(g.close)
|
close(g.close)
|
||||||
return nil
|
return nil
|
||||||
@@ -228,18 +248,18 @@ func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) loopCheck() {
|
func (g *URLTestGroup) loopCheck() {
|
||||||
go g.checkOutbounds()
|
go g.CheckOutbounds()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.close:
|
case <-g.close:
|
||||||
return
|
return
|
||||||
case <-g.ticker.C:
|
case <-g.ticker.C:
|
||||||
g.checkOutbounds()
|
g.CheckOutbounds()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) checkOutbounds() {
|
func (g *URLTestGroup) CheckOutbounds() {
|
||||||
_, _ = g.URLTest(g.ctx, g.link)
|
_, _ = g.URLTest(g.ctx, g.link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
|
|||||||
connectAddr = options.ServerOptions.Build()
|
connectAddr = options.ServerOptions.Build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outbound.bind = wireguard.NewClientBind(ctx, dialer.New(router, options.DialerOptions), isConnect, connectAddr, reserved)
|
outbound.bind = wireguard.NewClientBind(ctx, outbound, dialer.New(router, options.DialerOptions), isConnect, connectAddr, reserved)
|
||||||
localPrefixes := common.Map(options.LocalAddress, option.ListenPrefix.Build)
|
localPrefixes := common.Map(options.LocalAddress, option.ListenPrefix.Build)
|
||||||
if len(localPrefixes) == 0 {
|
if len(localPrefixes) == 0 {
|
||||||
return nil, E.New("missing local address")
|
return nil, E.New("missing local address")
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ type TLSObfs struct {
|
|||||||
func (to *TLSObfs) read(b []byte, discardN int) (int, error) {
|
func (to *TLSObfs) read(b []byte, discardN int) (int, error) {
|
||||||
buf := B.Get(discardN)
|
buf := B.Get(discardN)
|
||||||
_, err := io.ReadFull(to.Conn, buf)
|
_, err := io.ReadFull(to.Conn, buf)
|
||||||
|
B.Put(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
B.Put(buf)
|
|
||||||
|
|
||||||
sizeBuf := make([]byte, 2)
|
sizeBuf := make([]byte, 2)
|
||||||
_, err = io.ReadFull(to.Conn, sizeBuf)
|
_, err = io.ReadFull(to.Conn, sizeBuf)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/wireguard-go/conn"
|
"github.com/sagernet/wireguard-go/conn"
|
||||||
@@ -18,6 +18,7 @@ var _ conn.Bind = (*ClientBind)(nil)
|
|||||||
|
|
||||||
type ClientBind struct {
|
type ClientBind struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
errorHandler E.Handler
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
reservedForEndpoint map[M.Socksaddr][3]uint8
|
reservedForEndpoint map[M.Socksaddr][3]uint8
|
||||||
connAccess sync.Mutex
|
connAccess sync.Mutex
|
||||||
@@ -28,9 +29,10 @@ type ClientBind struct {
|
|||||||
reserved [3]uint8
|
reserved [3]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientBind(ctx context.Context, dialer N.Dialer, isConnect bool, connectAddr M.Socksaddr, reserved [3]uint8) *ClientBind {
|
func NewClientBind(ctx context.Context, errorHandler E.Handler, dialer N.Dialer, isConnect bool, connectAddr M.Socksaddr, reserved [3]uint8) *ClientBind {
|
||||||
return &ClientBind{
|
return &ClientBind{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
errorHandler: errorHandler,
|
||||||
dialer: dialer,
|
dialer: dialer,
|
||||||
reservedForEndpoint: make(map[M.Socksaddr][3]uint8),
|
reservedForEndpoint: make(map[M.Socksaddr][3]uint8),
|
||||||
isConnect: isConnect,
|
isConnect: isConnect,
|
||||||
@@ -67,10 +69,10 @@ func (c *ClientBind) connect() (*wireConn, error) {
|
|||||||
if c.isConnect {
|
if c.isConnect {
|
||||||
udpConn, err := c.dialer.DialContext(c.ctx, N.NetworkUDP, c.connectAddr)
|
udpConn, err := c.dialer.DialContext(c.ctx, N.NetworkUDP, c.connectAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &wireError{err}
|
return nil, err
|
||||||
}
|
}
|
||||||
c.conn = &wireConn{
|
c.conn = &wireConn{
|
||||||
NetPacketConn: &bufio.UnbindPacketConn{
|
PacketConn: &bufio.UnbindPacketConn{
|
||||||
ExtendedConn: bufio.NewExtendedConn(udpConn),
|
ExtendedConn: bufio.NewExtendedConn(udpConn),
|
||||||
Addr: c.connectAddr,
|
Addr: c.connectAddr,
|
||||||
},
|
},
|
||||||
@@ -79,11 +81,11 @@ func (c *ClientBind) connect() (*wireConn, error) {
|
|||||||
} else {
|
} else {
|
||||||
udpConn, err := c.dialer.ListenPacket(c.ctx, M.Socksaddr{Addr: netip.IPv4Unspecified()})
|
udpConn, err := c.dialer.ListenPacket(c.ctx, M.Socksaddr{Addr: netip.IPv4Unspecified()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &wireError{err}
|
return nil, err
|
||||||
}
|
}
|
||||||
c.conn = &wireConn{
|
c.conn = &wireConn{
|
||||||
NetPacketConn: bufio.NewPacketConn(udpConn),
|
PacketConn: bufio.NewPacketConn(udpConn),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.conn, nil
|
return c.conn, nil
|
||||||
@@ -102,30 +104,31 @@ func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint1
|
|||||||
func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
|
func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
|
||||||
udpConn, err := c.connect()
|
udpConn, err := c.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = &wireError{err}
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
c.errorHandler.NewError(context.Background(), E.Cause(err, "connect to server"))
|
||||||
|
err = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buffer := buf.With(b)
|
n, addr, err := udpConn.ReadFrom(b)
|
||||||
destination, err := udpConn.ReadPacket(buffer)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
udpConn.Close()
|
udpConn.Close()
|
||||||
select {
|
select {
|
||||||
case <-c.done:
|
case <-c.done:
|
||||||
default:
|
default:
|
||||||
err = &wireError{err}
|
c.errorHandler.NewError(context.Background(), E.Cause(err, "read packet"))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = buffer.Len()
|
|
||||||
if buffer.Start() > 0 {
|
|
||||||
copy(b, buffer.Bytes())
|
|
||||||
}
|
|
||||||
if n > 3 {
|
if n > 3 {
|
||||||
b[1] = 0
|
b[1] = 0
|
||||||
b[2] = 0
|
b[2] = 0
|
||||||
b[3] = 0
|
b[3] = 0
|
||||||
}
|
}
|
||||||
ep = Endpoint(destination)
|
ep = Endpoint(M.SocksaddrFromNet(addr))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +170,7 @@ func (c *ClientBind) Send(b []byte, ep conn.Endpoint) error {
|
|||||||
b[2] = reserved[1]
|
b[2] = reserved[1]
|
||||||
b[3] = reserved[2]
|
b[3] = reserved[2]
|
||||||
}
|
}
|
||||||
err = udpConn.WritePacket(buf.As(b), destination)
|
_, err = udpConn.WriteTo(b, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
udpConn.Close()
|
udpConn.Close()
|
||||||
}
|
}
|
||||||
@@ -179,7 +182,7 @@ func (c *ClientBind) ParseEndpoint(s string) (conn.Endpoint, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type wireConn struct {
|
type wireConn struct {
|
||||||
N.NetPacketConn
|
net.PacketConn
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
}
|
}
|
||||||
@@ -192,7 +195,7 @@ func (w *wireConn) Close() error {
|
|||||||
return net.ErrClosed
|
return net.ErrClosed
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
w.NetPacketConn.Close()
|
w.PacketConn.Close()
|
||||||
close(w.done)
|
close(w.done)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package wireguard
|
|
||||||
|
|
||||||
import "net"
|
|
||||||
|
|
||||||
type wireError struct {
|
|
||||||
cause error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wireError) Error() string {
|
|
||||||
return w.cause.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wireError) Timeout() bool {
|
|
||||||
if cause, causeNet := w.cause.(net.Error); causeNet {
|
|
||||||
return cause.Timeout()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wireError) Temporary() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user