Compare commits

...

32 Commits

Author SHA1 Message Date
世界
a37cab48d2 Bump version 2022-09-10 23:13:58 +08:00
世界
c586c8f361 Fix socks4 request 2022-09-10 22:53:06 +08:00
世界
e68fa3e12d Fix processing empty dns result 2022-09-10 22:52:54 +08:00
世界
7f5b9e0e3b Run build on main branch 2022-09-10 22:52:54 +08:00
世界
f7bed32c6f Bump version 2022-09-09 14:43:42 +08:00
世界
ef7f2d82c0 Fix match 4in6 address in ip_cidr 2022-09-09 14:07:02 +08:00
世界
7aa97a332e Fix documentation 2022-09-09 13:54:02 +08:00
世界
7c30dde96b Minor fixes 2022-09-08 18:33:59 +08:00
GyDi
9cef2a0a8f Fix clashapi log level format error 2022-09-08 18:04:06 +08:00
世界
f376683fc3 Update documentation 2022-09-07 23:10:36 +08:00
世界
4b61d6e875 Fix hysteria stream error 2022-09-07 19:16:20 +08:00
世界
7d83e350fd Refine test 2022-09-07 19:16:20 +08:00
世界
500ba69548 Fix processing vmess termination signal 2022-09-07 19:16:20 +08:00
世界
9a422549b1 Fix json format error message 2022-09-07 13:23:26 +08:00
世界
3b48fa455e Fix naive inbound temporary 2022-09-07 12:30:54 +08:00
zakuwaki
ef013e0639 Suppress accept proxyproto failed #65 2022-09-06 23:16:31 +08:00
世界
8f8437a88d Fix wireguard reconnect 2022-09-06 00:11:43 +08:00
世界
1b091c9b07 Update documentation 2022-09-04 13:15:10 +08:00
世界
4801b6f057 Fix DNS routing 2022-09-04 12:49:38 +08:00
世界
9078bc2de5 Fix write trojan udp 2022-09-03 16:58:55 +08:00
世界
b69464dfe9 Update documentation for dial fields 2022-09-03 13:02:41 +08:00
世界
62fa48293a Merge dialer options 2022-09-03 12:55:10 +08:00
世界
b206d0889b Fix dial parallel in direct outbound 2022-09-03 12:01:48 +08:00
世界
ee691d81bf Fix write zero 2022-09-03 09:25:30 +08:00
void aire()
56876a67cc Fix documentation typo (#60) 2022-09-02 19:04:03 +08:00
世界
4a0df713aa Add ws compatibility test 2022-09-01 20:32:47 +08:00
世界
ef801cbfbe Fix server install script 2022-09-01 20:32:47 +08:00
世界
9378fc88d2 Add with_wireguard to default server tag 2022-09-01 20:16:20 +08:00
世界
f46bfcc3d8 Move unstable branch to dev-next 2022-08-31 23:45:42 +08:00
0x7d274284
ccdb238843 Fix documentation typo (#57) 2022-08-31 23:42:36 +08:00
世界
f1f61b4e2b Fix install documentation 2022-08-31 23:37:30 +08:00
世界
a44cb745d9 Fix write log timestamp 2022-08-31 23:35:43 +08:00
72 changed files with 585 additions and 291 deletions

View File

@@ -1,10 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
PROJECTS=$(dirname "$0")/../.. PROJECTS=$(dirname "$0")/../..
go get -x github.com/sagernet/$1@$(git -C $PROJECTS/$1 rev-parse HEAD)
go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD)
go get -x github.com/sagernet/sing-dns@$(git -C $PROJECTS/sing-dns rev-parse HEAD)
go get -x github.com/sagernet/sing-tun@$(git -C $PROJECTS/sing-tun rev-parse HEAD)
go get -x github.com/sagernet/sing-shadowsocks@$(git -C $PROJECTS/sing-shadowsocks rev-parse HEAD)
go get -x github.com/sagernet/sing-vmess@$(git -C $PROJECTS/sing-vmess rev-parse HEAD)
go mod tidy go mod tidy

View File

@@ -3,14 +3,18 @@ name: Debug build
on: on:
push: push:
branches: branches:
- main
- dev - dev
- dev-next
paths-ignore: paths-ignore:
- '**.md' - '**.md'
- '.github/**' - '.github/**'
- '!.github/workflows/debug.yml' - '!.github/workflows/debug.yml'
pull_request: pull_request:
branches: branches:
- main
- dev - dev
- dev-next
jobs: jobs:
build: build:

View File

@@ -2,7 +2,7 @@ name: Generate Documents
on: on:
push: push:
branches: branches:
- main - dev
paths: paths:
- docs/** - docs/**
- .github/workflows/mkdocs.yml - .github/workflows/mkdocs.yml

View File

@@ -7,8 +7,8 @@ ENV GOPROXY ${GOPROXY}
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
RUN set -ex \ RUN set -ex \
&& apk add git build-base \ && apk add git build-base \
&& export COMMIT=$(git rev-parse HEAD) \ && export COMMIT=$(git rev-parse --short HEAD) \
&& go build -v -trimpath -tags 'with_quic,with_acme,with_wireguard,with_clash_api' \ && go build -v -trimpath -tags 'no_gvisor,with_quic,with_wireguard,with_acme' \
-o /go/bin/sing-box \ -o /go/bin/sing-box \
-ldflags "-X github.com/sagernet/sing-box/constant.Commit=${COMMIT} -w -s -buildid=" \ -ldflags "-X github.com/sagernet/sing-box/constant.Commit=${COMMIT} -w -s -buildid=" \
./cmd/sing-box ./cmd/sing-box

View File

@@ -38,7 +38,7 @@ func format() error {
return E.Cause(err, "read config") return E.Cause(err, "read config")
} }
var options option.Options var options option.Options
err = json.Unmarshal(configContent, &options) err = options.UnmarshalJSON(configContent)
if err != nil { if err != nil {
return E.Cause(err, "decode config") return E.Cause(err, "decode config")
} }

View File

@@ -9,7 +9,6 @@ import (
"syscall" "syscall"
"github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/common/json"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@@ -46,7 +45,7 @@ func readConfig() (option.Options, error) {
return option.Options{}, E.Cause(err, "read config") return option.Options{}, E.Cause(err, "read config")
} }
var options option.Options var options option.Options
err = json.Unmarshal(configContent, &options) err = options.UnmarshalJSON(configContent)
if err != nil { if err != nil {
return option.Options{}, E.Cause(err, "decode config") return option.Options{}, E.Cause(err, "decode config")
} }

View File

@@ -1,6 +1,13 @@
package baderror package baderror
import "strings" import (
"context"
"io"
"net"
"strings"
E "github.com/sagernet/sing/common/exceptions"
)
func Contains(err error, msgList ...string) bool { func Contains(err error, msgList ...string) bool {
for _, msg := range msgList { for _, msg := range msgList {
@@ -10,3 +17,46 @@ func Contains(err error, msgList ...string) bool {
} }
return false return false
} }
func WrapH2(err error) error {
if err == nil {
return nil
}
err = E.Unwrap(err)
if err == io.ErrUnexpectedEOF {
return io.EOF
}
if Contains(err, "client disconnected", "body closed by handler") {
return net.ErrClosed
}
return err
}
func WrapGRPC(err error) error {
// grpc uses stupid internal error types
if err == nil {
return nil
}
if Contains(err, "EOF") {
return io.EOF
}
if Contains(err, "Canceled") {
return context.Canceled
}
if Contains(err,
"the client connection is closing",
"server closed the stream without sending trailers") {
return net.ErrClosed
}
return err
}
func WrapQUIC(err error) error {
if err == nil {
return nil
}
if Contains(err, "canceled with error code 0") {
return net.ErrClosed
}
return err
}

View File

@@ -1,26 +0,0 @@
package baderror
import (
"context"
"io"
"net"
)
func WrapGRPC(err error) error {
// grpc uses stupid internal error types
if err == nil {
return nil
}
if Contains(err, "EOF") {
return io.EOF
}
if Contains(err, "Canceled") {
return context.Canceled
}
if Contains(err,
"the client connection is closing",
"server closed the stream without sending trailers") {
return net.ErrClosed
}
return err
}

View File

@@ -1,22 +0,0 @@
package baderror
import (
"io"
"net"
E "github.com/sagernet/sing/common/exceptions"
)
func WrapH2(err error) error {
if err == nil {
return nil
}
err = E.Unwrap(err)
if err == io.ErrUnexpectedEOF {
return io.EOF
}
if Contains(err, "client disconnected", "body closed by handler") {
return net.ErrClosed
}
return err
}

View File

@@ -10,15 +10,12 @@ import (
) )
func New(router adapter.Router, options option.DialerOptions) N.Dialer { func New(router adapter.Router, options option.DialerOptions) N.Dialer {
var dialer N.Dialer
if options.Detour == "" { if options.Detour == "" {
return NewDefault(router, options) dialer = NewDefault(router, options)
} else { } else {
return NewDetour(router, options.Detour) dialer = NewDetour(router, options.Detour)
} }
}
func NewOutbound(router adapter.Router, options option.OutboundDialerOptions) N.Dialer {
dialer := New(router, options.DialerOptions)
domainStrategy := dns.DomainStrategy(options.DomainStrategy) domainStrategy := dns.DomainStrategy(options.DomainStrategy)
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" { if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
dialer = NewResolveDialer(router, dialer, domainStrategy, time.Duration(options.FallbackDelay)) dialer = NewResolveDialer(router, dialer, domainStrategy, time.Duration(options.FallbackDelay))

View File

@@ -1,6 +1,6 @@
package constant package constant
var ( var (
Version = "1.0-beta3" Version = "1.0.2"
Commit = "" Commit = ""
) )

View File

@@ -1,9 +1,35 @@
#### 1.0.1
* Fix match 4in6 address in ip_cidr
* Fix clash api log level format error
* Fix clash api unknown proxy type
#### 1.0
* Fix wireguard reconnect
* Fix naive inbound
* Fix json format error message
* Fix processing vmess termination signal
* Fix hysteria stream error
* Fix listener close when proxyproto failed
#### 1.0-rc1
* Fix write log timestamp
* Fix write zero
* Fix dial parallel in direct outbound
* Fix write trojan udp
* Fix DNS routing
* Add attribute support for geosite
* Update documentation for [Dial Fields](/configuration/shared/dial)
#### 1.0-beta3 #### 1.0-beta3
* Add [chained inbound](/configuration/shared/listen#detour) support * Add [chained inbound](/configuration/shared/listen#detour) support
* Add process_path rule item * Add process_path rule item
* Add macOS redirect support * Add macOS redirect support
* Add ShadowTLS [Inbound](/configuration/inbound/shadowtls), [Outbound](/configuration/outbound/shadowtls) and [Examples](/examples/shadowtls) * Add ShadowTLS [Inbound](/configuration/inbound/shadowtls), [Outbound](/configuration/outbound/shadowtls)
and [Examples](/examples/shadowtls)
* Fix search android package in non-owner users * Fix search android package in non-owner users
* Fix socksaddr type condition * Fix socksaddr type condition
* Fix smux session status * Fix smux session status

View File

@@ -16,12 +16,14 @@
### Fields ### Fields
| Field | Available Context |
|-----------------------------------------------------------------------------------|-------------------|
| `bind_interface` /`bind_address` /`routing_mark` /`reuse_addr` /`connect_timeout` | `detour` not set |
#### detour #### detour
The tag of the upstream outbound. The tag of the upstream outbound.
Other dial fields will be ignored when enabled.
#### bind_interface #### bind_interface
The network interface to bind to. The network interface to bind to.
@@ -57,13 +59,16 @@ One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
If set, the requested domain name will be resolved to IP before connect. If set, the requested domain name will be resolved to IP before connect.
`dns.strategy` will be used if empty. | Outbound | Effected domains | Fallback Value |
|----------|--------------------------|-------------------------------------------|
| `direct` | Domain in request | Take `inbound.domain_strategy` if not set |
| others | Domain in server address | / |
#### fallback_delay #### fallback_delay
The length of time to wait before spawning a RFC 6555 Fast Fallback connection. The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
That is, is the amount of time to wait for IPv6 to succeed before assuming That is, is the amount of time to wait for connection to succeed before assuming
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set. that IPv4/IPv6 is misconfigured and falling back to other type of addresses.
If zero, a default delay of 300ms is used. If zero, a default delay of 300ms is used.
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`. Only take effect when `domain_strategy` is set.

View File

@@ -35,7 +35,7 @@
"password": "8JCsPssfgS8tiRwiMlhARg==", "password": "8JCsPssfgS8tiRwiMlhARg==",
"detour": "shadowtls-out", "detour": "shadowtls-out",
"multiplex": { "multiplex": {
"enabled": 1, "enabled": true,
"max_connections": 4, "max_connections": 4,
"min_streams": 4 "min_streams": 4
} }
@@ -52,4 +52,4 @@
} }
] ]
} }
``` ```

View File

@@ -11,7 +11,7 @@ the public internet.
##### on Linux ##### on Linux
`auto-route` cannot automatically hijack DNS requests with `systemd-resoled` enabled, you can switch to NetworkManager. `auto-route` cannot automatically hijack DNS requests with `systemd-resolved` enabled, you can switch to NetworkManager.
#### System proxy #### System proxy

View File

@@ -10,7 +10,7 @@
##### Linux ##### Linux
`auto-route` 无法自动劫持 DNS 请求如果 `systemd-resoled` 开启, 您可以切换到 NetworkManager. `auto-route` 无法自动劫持 DNS 请求如果 `systemd-resolved` 开启, 您可以切换到 NetworkManager.
#### 系统代理 #### 系统代理

View File

@@ -36,7 +36,7 @@ func getConfigs(logFactory log.Factory) func(w http.ResponseWriter, r *http.Requ
logLevel := logFactory.Level() logLevel := logFactory.Level()
if logLevel == log.LevelTrace { if logLevel == log.LevelTrace {
logLevel = log.LevelDebug logLevel = log.LevelDebug
} else if logLevel > log.LevelError { } else if logLevel < log.LevelError {
logLevel = log.LevelError logLevel = log.LevelError
} }
render.JSON(w, r, &configSchema{ render.JSON(w, r, &configSchema{

View File

@@ -75,11 +75,13 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
clashType = "Shadowsocks" clashType = "Shadowsocks"
case C.TypeVMess: case C.TypeVMess:
clashType = "Vmess" clashType = "Vmess"
case C.TypeTrojan:
clashType = "Trojan"
case C.TypeSelector: case C.TypeSelector:
clashType = "Selector" clashType = "Selector"
isGroup = true isGroup = true
default: default:
clashType = "Unknown" clashType = "Socks"
} }
info.Put("type", clashType) info.Put("type", clashType)
info.Put("name", detour.Tag()) info.Put("name", detour.Tag())

6
go.mod
View File

@@ -20,11 +20,11 @@ require (
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812 github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
@@ -39,6 +39,8 @@ require (
gvisor.dev/gvisor v0.0.0-20220819163037-ba6e795b139a gvisor.dev/gvisor v0.0.0-20220819163037-ba6e795b139a
) )
//replace github.com/sagernet/sing => ../sing
require ( require (
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect

8
go.sum
View File

@@ -135,16 +135,16 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/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.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812 h1:z5AqoJcMy+MaD9pstLt08c95t2Txlzvp5pk4lqXBQPc= github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f h1:w1TJq7Lw3It35tDyMsZLtYz4T2msf1UK9JxC85L5+sk=
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ= github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY= github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM= github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU=
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c h1:92Gn78/z/t6CkzZ4XWG/uPiCxhUmjPULFEHFMDY6K8k= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f h1:6l9aXZqAl1JqXJWi89KHpWnM/moQUPGG+XiwMc+yD0A=
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=

View File

@@ -40,7 +40,11 @@ func (a *myInboundAdapter) loopTCPIn() {
for { for {
conn, err := tcpListener.Accept() conn, err := tcpListener.Accept()
if err != nil { if err != nil {
return if E.IsClosed(err) {
return
}
a.logger.Error("accept: ", err)
continue
} }
go a.injectTCP(conn, adapter.InboundContext{}) go a.injectTCP(conn, adapter.InboundContext{})
} }

View File

@@ -20,7 +20,6 @@ import (
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth" "github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" 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"
@@ -361,7 +360,7 @@ func (c *naiveH1Conn) WriteBuffer(buffer *buf.Buffer) error {
n, err = bufio.Copy(w, c.Conn) n, err = bufio.Copy(w, c.Conn)
} }
return n, wrapHttpError(err) return n, wrapHttpError(err)
}*/ }
func (c *naiveH1Conn) ReadFrom(r io.Reader) (n int64, err error) { func (c *naiveH1Conn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writePadding < kFirstPaddings { if c.writePadding < kFirstPaddings {
@@ -371,13 +370,14 @@ func (c *naiveH1Conn) ReadFrom(r io.Reader) (n int64, err error) {
} }
return n, wrapHttpError(err) return n, wrapHttpError(err)
} }
*/
func (c *naiveH1Conn) Upstream() any { func (c *naiveH1Conn) Upstream() any {
return c.Conn return c.Conn
} }
func (c *naiveH1Conn) ReaderReplaceable() bool { func (c *naiveH1Conn) ReaderReplaceable() bool {
return c.readRemaining == kFirstPaddings return c.readPadding == kFirstPaddings
} }
func (c *naiveH1Conn) WriterReplaceable() bool { func (c *naiveH1Conn) WriterReplaceable() bool {
@@ -539,7 +539,7 @@ func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
n, err = bufio.Copy(w, c.reader) n, err = bufio.Copy(w, c.reader)
} }
return n, wrapHttpError(err) return n, wrapHttpError(err)
}*/ }
func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) { func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writePadding < kFirstPaddings { if c.writePadding < kFirstPaddings {
@@ -548,7 +548,7 @@ func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) {
n, err = bufio.Copy(c.writer, r) n, err = bufio.Copy(c.writer, r)
} }
return n, wrapHttpError(err) return n, wrapHttpError(err)
} }*/
func (c *naiveH2Conn) Close() error { func (c *naiveH2Conn) Close() error {
return common.Close( return common.Close(
@@ -586,7 +586,7 @@ func (c *naiveH2Conn) UpstreamWriter() any {
} }
func (c *naiveH2Conn) ReaderReplaceable() bool { func (c *naiveH2Conn) ReaderReplaceable() bool {
return c.readRemaining == kFirstPaddings return c.readPadding == kFirstPaddings
} }
func (c *naiveH2Conn) WriterReplaceable() bool { func (c *naiveH2Conn) WriterReplaceable() bool {

View File

@@ -71,7 +71,7 @@ func (f Formatter) Format(ctx context.Context, level Level, tag string, message
case f.DisableTimestamp: case f.DisableTimestamp:
message = levelString + " " + message message = levelString + " " + message
case f.FullTimestamp: case f.FullTimestamp:
message = F.ToString(int(timestamp.Sub(f.BaseTime)/time.Second)) + " " + levelString + " " + message message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message
default: default:
message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message
} }
@@ -136,7 +136,7 @@ func (f Formatter) FormatWithSimple(ctx context.Context, level Level, tag string
case f.DisableTimestamp: case f.DisableTimestamp:
message = levelString + " " + message message = levelString + " " + message
case f.FullTimestamp: case f.FullTimestamp:
message = F.ToString(int(timestamp.Sub(f.BaseTime)/time.Second)) + " " + levelString + " " + message message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message
default: default:
message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message
} }

View File

@@ -8,7 +8,7 @@ type DirectInboundOptions struct {
} }
type DirectOutboundOptions struct { type DirectOutboundOptions struct {
OutboundDialerOptions DialerOptions
OverrideAddress string `json:"override_address,omitempty"` OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"` OverridePort uint16 `json:"override_port,omitempty"`
ProxyProtocol uint8 `json:"proxy_protocol,omitempty"` ProxyProtocol uint8 `json:"proxy_protocol,omitempty"`

View File

@@ -17,7 +17,7 @@ type HysteriaInboundOptions struct {
} }
type HysteriaOutboundOptions struct { type HysteriaOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
Up string `json:"up,omitempty"` Up string `json:"up,omitempty"`
UpMbps int `json:"up_mbps,omitempty"` UpMbps int `json:"up_mbps,omitempty"`

View File

@@ -113,10 +113,6 @@ type DialerOptions struct {
ReuseAddr bool `json:"reuse_addr,omitempty"` ReuseAddr bool `json:"reuse_addr,omitempty"`
ConnectTimeout Duration `json:"connect_timeout,omitempty"` ConnectTimeout Duration `json:"connect_timeout,omitempty"`
TCPFastOpen bool `json:"tcp_fast_open,omitempty"` TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
}
type OutboundDialerOptions struct {
DialerOptions
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
FallbackDelay Duration `json:"fallback_delay,omitempty"` FallbackDelay Duration `json:"fallback_delay,omitempty"`
} }

View File

@@ -22,7 +22,7 @@ type ShadowsocksDestination struct {
} }
type ShadowsocksOutboundOptions struct { type ShadowsocksOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
Method string `json:"method"` Method string `json:"method"`
Password string `json:"password"` Password string `json:"password"`

View File

@@ -11,7 +11,7 @@ type ShadowTLSHandshakeOptions struct {
} }
type ShadowTLSOutboundOptions struct { type ShadowTLSOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
TLS *OutboundTLSOptions `json:"tls,omitempty"` TLS *OutboundTLSOptions `json:"tls,omitempty"`
} }

View File

@@ -15,7 +15,7 @@ type HTTPMixedInboundOptions struct {
} }
type SocksOutboundOptions struct { type SocksOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
@@ -25,7 +25,7 @@ type SocksOutboundOptions struct {
} }
type HTTPOutboundOptions struct { type HTTPOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`

View File

@@ -1,7 +1,7 @@
package option package option
type SSHOutboundOptions struct { type SSHOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
User string `json:"user,omitempty"` User string `json:"user,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`

View File

@@ -1,7 +1,7 @@
package option package option
type TorOutboundOptions struct { type TorOutboundOptions struct {
OutboundDialerOptions DialerOptions
ExecutablePath string `json:"executable_path,omitempty"` ExecutablePath string `json:"executable_path,omitempty"`
ExtraArgs []string `json:"extra_args,omitempty"` ExtraArgs []string `json:"extra_args,omitempty"`
DataDirectory string `json:"data_directory,omitempty"` DataDirectory string `json:"data_directory,omitempty"`

View File

@@ -15,7 +15,7 @@ type TrojanUser struct {
} }
type TrojanOutboundOptions struct { type TrojanOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
Password string `json:"password"` Password string `json:"password"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`

View File

@@ -14,7 +14,7 @@ type VMessUser struct {
} }
type VMessOutboundOptions struct { type VMessOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
UUID string `json:"uuid"` UUID string `json:"uuid"`
Security string `json:"security"` Security string `json:"security"`

View File

@@ -1,7 +1,7 @@
package option package option
type WireGuardOutboundOptions struct { type WireGuardOutboundOptions struct {
OutboundDialerOptions DialerOptions
ServerOptions ServerOptions
LocalAddress Listable[string] `json:"local_address"` LocalAddress Listable[string] `json:"local_address"`
PrivateKey string `json:"private_key"` PrivateKey string `json:"private_key"`

View File

@@ -4,12 +4,14 @@ import (
"context" "context"
"net" "net"
"net/netip" "net/netip"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/dialer"
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-dns"
E "github.com/sagernet/sing/common/exceptions" 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"
@@ -17,11 +19,16 @@ import (
"github.com/pires/go-proxyproto" "github.com/pires/go-proxyproto"
) )
var _ adapter.Outbound = (*Direct)(nil) var (
_ adapter.Outbound = (*Direct)(nil)
_ N.ParallelDialer = (*Direct)(nil)
)
type Direct struct { type Direct struct {
myOutboundAdapter myOutboundAdapter
dialer N.Dialer dialer N.Dialer
domainStrategy dns.DomainStrategy
fallbackDelay time.Duration
overrideOption int overrideOption int
overrideDestination M.Socksaddr overrideDestination M.Socksaddr
proxyProto uint8 proxyProto uint8
@@ -36,8 +43,10 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti
logger: logger, logger: logger,
tag: tag, tag: tag,
}, },
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), domainStrategy: dns.DomainStrategy(options.DomainStrategy),
proxyProto: options.ProxyProtocol, fallbackDelay: time.Duration(options.FallbackDelay),
dialer: dialer.New(router, options.DialerOptions),
proxyProto: options.ProxyProtocol,
} }
if options.ProxyProtocol > 2 { if options.ProxyProtocol > 2 {
return nil, E.New("invalid proxy protocol option: ", options.ProxyProtocol) return nil, E.New("invalid proxy protocol option: ", options.ProxyProtocol)
@@ -99,6 +108,53 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
return conn, nil return conn, nil
} }
func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
ctx, metadata := adapter.AppendContext(ctx)
originDestination := metadata.Destination
metadata.Outbound = h.tag
metadata.Destination = destination
switch h.overrideOption {
case 1, 2:
// override address
return h.DialContext(ctx, network, destination)
case 3:
destination.Port = h.overrideDestination.Port
}
network = N.NetworkName(network)
switch network {
case N.NetworkTCP:
h.logger.InfoContext(ctx, "outbound connection to ", destination)
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
}
var domainStrategy dns.DomainStrategy
if h.domainStrategy != dns.DomainStrategyAsIS {
domainStrategy = h.domainStrategy
} else {
domainStrategy = metadata.DomainStrategy
}
conn, err := N.DialParallel(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.fallbackDelay)
if err != nil {
return nil, err
}
if h.proxyProto > 0 {
source := metadata.Source
if !source.IsValid() {
source = M.SocksaddrFromNet(conn.LocalAddr())
}
if originDestination.Addr.Is6() {
source = M.SocksaddrFrom(netip.AddrFrom16(source.Addr.As16()), source.Port)
}
header := proxyproto.HeaderProxyFromAddrs(h.proxyProto, source.TCPAddr(), originDestination.TCPAddr())
_, err = header.WriteTo(conn)
if err != nil {
conn.Close()
return nil, E.Cause(err, "write proxy protocol header")
}
}
return conn, nil
}
func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag metadata.Outbound = h.tag

View File

@@ -77,12 +77,9 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
if err != nil { if err != nil {
return err return err
} }
if len(message.Questions) > 0 { metadataInQuery := metadata
question := message.Questions[0]
metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
}
go func() error { go func() error {
response, err := d.router.Exchange(ctx, &message) response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
if err != nil { if err != nil {
return err return err
} }
@@ -125,13 +122,10 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
if err != nil { if err != nil {
return err return err
} }
if len(message.Questions) > 0 {
question := message.Questions[0]
metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
}
timeout.Update() timeout.Update()
metadataInQuery := metadata
go func() error { go func() error {
response, err := d.router.Exchange(ctx, &message) response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -24,7 +24,7 @@ type HTTP struct {
} }
func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) { func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) {
detour, err := dialer.NewTLS(dialer.NewOutbound(router, options.OutboundDialerOptions), options.Server, common.PtrValueOrDefault(options.TLS)) detour, err := dialer.NewTLS(dialer.New(router, options.DialerOptions), options.Server, common.PtrValueOrDefault(options.TLS))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -117,7 +117,7 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
tag: tag, tag: tag,
}, },
ctx: ctx, ctx: ctx,
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
quicConfig: quicConfig, quicConfig: quicConfig,

View File

@@ -44,7 +44,7 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
logger: logger, logger: logger,
tag: tag, tag: tag,
}, },
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
method: method, method: method,
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
uot: options.UoT, uot: options.UoT,

View File

@@ -34,7 +34,7 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
logger: logger, logger: logger,
tag: tag, tag: tag,
}, },
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
} }
if options.TLS == nil || !options.TLS.Enabled { if options.TLS == nil || !options.TLS.Enabled {

View File

@@ -25,7 +25,7 @@ type Socks struct {
} }
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) { func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
detour := dialer.NewOutbound(router, options.OutboundDialerOptions) detour := dialer.New(router, options.DialerOptions)
var version socks.Version var version socks.Version
var err error var err error
if options.Version != "" { if options.Version != "" {

View File

@@ -47,7 +47,7 @@ func NewSSH(ctx context.Context, router adapter.Router, logger log.ContextLogger
tag: tag, tag: tag,
}, },
ctx: ctx, ctx: ctx,
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
user: options.User, user: options.User,
hostKeyAlgorithms: options.HostKeyAlgorithms, hostKeyAlgorithms: options.HostKeyAlgorithms,

View File

@@ -66,7 +66,7 @@ func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger
tag: tag, tag: tag,
}, },
ctx: ctx, ctx: ctx,
proxy: NewProxyListener(ctx, logger, dialer.NewOutbound(router, options.OutboundDialerOptions)), proxy: NewProxyListener(ctx, logger, dialer.New(router, options.DialerOptions)),
startConf: &startConf, startConf: &startConf,
options: options.Options, options: options.Options,
}, nil }, nil

View File

@@ -13,6 +13,7 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/v2ray" "github.com/sagernet/sing-box/transport/v2ray"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions" 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"
@@ -40,7 +41,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
logger: logger, logger: logger,
tag: tag, tag: tag,
}, },
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
key: trojan.Key(options.Password), key: trojan.Key(options.Password),
} }
@@ -125,7 +126,7 @@ func (h *trojanDialer) DialContext(ctx context.Context, network string, destinat
case N.NetworkTCP: case N.NetworkTCP:
return trojan.NewClientConn(conn, h.key, destination), nil return trojan.NewClientConn(conn, h.key, destination), nil
case N.NetworkUDP: case N.NetworkUDP:
return trojan.NewClientPacketConn(conn, h.key), nil return &bufio.BindPacketConn{PacketConn: trojan.NewClientPacketConn(conn, h.key), Addr: destination}, nil
default: default:
return nil, E.Extend(N.ErrUnknownNetwork, network) return nil, E.Extend(N.ErrUnknownNetwork, network)
} }
@@ -136,5 +137,5 @@ func (h *trojanDialer) ListenPacket(ctx context.Context, destination M.Socksaddr
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conn.(*trojan.ClientPacketConn), nil return conn.(net.PacketConn), nil
} }

View File

@@ -42,7 +42,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
logger: logger, logger: logger,
tag: tag, tag: tag,
}, },
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
} }
var err error var err error

View File

@@ -64,7 +64,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
}, },
ctx: ctx, ctx: ctx,
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), dialer: dialer.New(router, options.DialerOptions),
} }
var endpointIp netip.Addr var endpointIp netip.Addr
if !outbound.serverAddr.IsFqdn() { if !outbound.serverAddr.IsFqdn() {
@@ -275,6 +275,7 @@ func (c *wireClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort u
func (c *wireClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) { func (c *wireClientBind) 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}
return return
} }
n, err = udpConn.Read(b) n, err = udpConn.Read(b)
@@ -332,10 +333,6 @@ func (w *wireError) Temporary() bool {
return true return true
} }
func (w *wireError) Unwrap() error {
return w.cause
}
type wireConn struct { type wireConn struct {
net.Conn net.Conn
access sync.Mutex access sync.Mutex

View File

@@ -10,7 +10,7 @@ DIR=$(dirname "$0")
PROJECT=$DIR/../.. PROJECT=$DIR/../..
pushd $PROJECT pushd $PROJECT
go install -v -trimpath -ldflags "-s -w -buildid=" -tags "no_gvisor" ./cmd/sing-box go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_wireguard,with_acme ./cmd/sing-box
popd popd
sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/ sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e -o pipefail set -e -o pipefail
curl -o go.tar.gz https://go.dev/dl/go1.19.linux-amd64.tar.gz curl -Lo go.tar.gz https://go.dev/dl/go1.19.linux-amd64.tar.gz
sudo rm -rf /usr/local/go sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go.tar.gz sudo tar -C /usr/local -xzf go.tar.gz
rm go.tar.gz rm go.tar.gz

View File

@@ -10,7 +10,7 @@ DIR=$(dirname "$0")
PROJECT=$DIR/../.. PROJECT=$DIR/../..
pushd $PROJECT pushd $PROJECT
go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_acme ./cmd/sing-box go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_wireguard,with_acme ./cmd/sing-box
popd popd
sudo systemctl stop sing-box sudo systemctl stop sing-box

View File

@@ -52,6 +52,7 @@ func (r *Router) Exchange(ctx context.Context, message *dnsmessage.Message) (*dn
case dnsmessage.TypeAAAA: case dnsmessage.TypeAAAA:
metadata.IPVersion = 6 metadata.IPVersion = 6
} }
metadata.Domain = string(message.Questions[0].Name.Data[:message.Questions[0].Name.Length-1])
} }
ctx, transport, strategy := r.matchDNS(ctx) ctx, transport, strategy := r.matchDNS(ctx)
ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout) ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout)
@@ -68,6 +69,8 @@ func (r *Router) Exchange(ctx context.Context, message *dnsmessage.Message) (*dn
func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
r.dnsLogger.DebugContext(ctx, "lookup domain ", domain) r.dnsLogger.DebugContext(ctx, "lookup domain ", domain)
ctx, metadata := adapter.AppendContext(ctx)
metadata.Domain = domain
ctx, transport, transportStrategy := r.matchDNS(ctx) ctx, transport, transportStrategy := r.matchDNS(ctx)
if strategy == dns.DomainStrategyAsIS { if strategy == dns.DomainStrategyAsIS {
strategy = transportStrategy strategy = transportStrategy
@@ -79,6 +82,9 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
r.dnsLogger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(addrs), " ")) r.dnsLogger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(addrs), " "))
} else { } else {
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain)) r.dnsLogger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain))
if err == nil {
err = dns.RCodeNameError
}
} }
return addrs, err return addrs, err
} }

View File

@@ -59,13 +59,13 @@ func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool { func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
if r.isSource { if r.isSource {
return r.ipSet.Contains(metadata.Source.Addr) return r.match(metadata.Source.Addr)
} else { } else {
if metadata.Destination.IsIP() { if metadata.Destination.IsIP() {
return r.ipSet.Contains(metadata.Destination.Addr) return r.match(metadata.Destination.Addr)
} else { } else {
for _, address := range metadata.DestinationAddresses { for _, address := range metadata.DestinationAddresses {
if r.ipSet.Contains(address) { if r.match(address) {
return true return true
} }
} }
@@ -74,6 +74,14 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
return false return false
} }
func (r *IPCIDRItem) match(address netip.Addr) bool {
if address.Is4In6() {
return r.ipSet.Contains(netip.AddrFrom4(address.As4()))
} else {
return r.ipSet.Contains(address)
}
}
func (r *IPCIDRItem) String() string { func (r *IPCIDRItem) String() string {
return r.description return r.description
} }

View File

@@ -22,6 +22,10 @@ func startInstance(t *testing.T, options option.Options) {
options.Log = &option.LogOptions{ options.Log = &option.LogOptions{
Level: "trace", Level: "trace",
} }
} else {
options.Log = &option.LogOptions{
Level: "warning",
}
} }
var instance *box.Box var instance *box.Box
var err error var err error

View File

@@ -183,6 +183,7 @@ func testPingPongWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)
if err != nil { if err != nil {
return err return err
} }
defer c.Close()
pingCh, pongCh, test := newPingPongPair() pingCh, pongCh, test := newPingPongPair()
go func() { go func() {
@@ -245,6 +246,7 @@ func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.Packe
if err != nil { if err != nil {
return err return err
} }
defer pc.Close()
go func() { go func() {
if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil { if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil {
@@ -301,6 +303,7 @@ func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error
if err != nil { if err != nil {
return err return err
} }
defer c.Close()
go func() { go func() {
c, err := l.Accept() c, err := l.Accept()
@@ -432,6 +435,7 @@ func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.Pack
if err != nil { if err != nil {
return err return err
} }
defer pc.Close()
go func() { go func() {
sendHash, err := writeRandData(pc, rAddr) sendHash, err := writeRandData(pc, rAddr)

View File

@@ -0,0 +1,52 @@
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": "127.0.0.1",
"port": "1080",
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true,
"ip": "127.0.0.1"
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "127.0.0.1",
"port": 1234,
"users": [
{
"id": ""
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "example.org",
"certificates": [
{
"certificateFile": "/path/to/certificate.crt",
"keyFile": "/path/to/private.key"
}
]
},
"wsSettings": {
"maxEarlyData": 2048,
"earlyDataHeaderName": ""
}
}
}
]
}

View File

@@ -0,0 +1,41 @@
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": 1234,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "b831381d-6324-4d53-ad4f-8cda48b30811"
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "example.org",
"certificates": [
{
"certificateFile": "/path/to/certificate.crt",
"keyFile": "/path/to/private.key"
}
]
},
"wsSettings": {
"maxEarlyData": 2048,
"earlyDataHeaderName": ""
}
}
}
],
"outbounds": [
{
"protocol": "freedom"
}
]
}

View File

@@ -10,9 +10,6 @@ import (
func TestProxyProtocol(t *testing.T) { func TestProxyProtocol(t *testing.T) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -10,13 +10,15 @@ require (
github.com/docker/docker v20.10.17+incompatible github.com/docker/docker v20.10.17+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/gofrs/uuid v4.2.0+incompatible github.com/gofrs/uuid v4.2.0+incompatible
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812 github.com/sagernet/sing v0.0.0-20220903085538-02b9ca1cc133
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/spyzhov/ajson v0.7.1 github.com/spyzhov/ajson v0.7.1
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
) )
//replace github.com/sagernet/sing => ../../sing
require ( require (
berty.tech/go-libtor v1.0.385 // indirect berty.tech/go-libtor v1.0.385 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Microsoft/go-winio v0.5.1 // indirect
@@ -59,25 +61,25 @@ require (
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
github.com/sagernet/netlink v0.0.0-20220826133217-3fb4ff92ea17 // indirect github.com/sagernet/netlink v0.0.0-20220826133217-3fb4ff92ea17 // indirect
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 // indirect github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961 // indirect
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 // indirect github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 // indirect
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c // indirect github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f // indirect
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 // indirect github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.22.0 // indirect go.uber.org/zap v1.22.0 // indirect
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 // indirect golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 // indirect golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
google.golang.org/grpc v1.49.0 // indirect google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect

View File

@@ -155,18 +155,18 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/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.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812 h1:z5AqoJcMy+MaD9pstLt08c95t2Txlzvp5pk4lqXBQPc= github.com/sagernet/sing v0.0.0-20220903085538-02b9ca1cc133 h1:krnb8wKEFIdXhmJYlhJMbEcPsJFISy2fz90uHVz7hMU=
github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ= github.com/sagernet/sing v0.0.0-20220903085538-02b9ca1cc133/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY= github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961 h1:5JeqhvCGV6AQQiAO0V67Loh2eyO3JNjIQnvRF8NnTE0=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM= github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961/go.mod h1:vKBBy4mNJRaFuJ8H6kYIOPofsZ1JT5mgdwIlebtvnZ4=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU=
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c h1:92Gn78/z/t6CkzZ4XWG/uPiCxhUmjPULFEHFMDY6K8k= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f h1:6l9aXZqAl1JqXJWi89KHpWnM/moQUPGG+XiwMc+yD0A=
github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 h1:pB1Dh1NbwVrLhQhotr4O4Hs3yhiBzmg3AvnUyYjL4x4= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@@ -205,8 +205,8 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
@@ -275,8 +275,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -311,8 +311,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b h1:qgrKnOfe1zyURRNdmDlGbN32i38Zjmw0B1+TMdHcOvg=
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b/go.mod h1:6y4CqPAy54NwiN4nC8K+R1eMpQDB1P2d25qmunh2RSA=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View File

@@ -14,9 +14,6 @@ func TestHysteriaSelf(t *testing.T) {
} }
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -92,9 +89,6 @@ func TestHysteriaInbound(t *testing.T) {
} }
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeHysteria, Type: C.TypeHysteria,
@@ -145,9 +139,6 @@ func TestHysteriaOutbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -13,9 +13,6 @@ func TestChainedInbound(t *testing.T) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -62,10 +59,8 @@ func TestChainedInbound(t *testing.T) {
ShadowsocksOptions: option.ShadowsocksOutboundOptions{ ShadowsocksOptions: option.ShadowsocksOutboundOptions{
Method: method, Method: method,
Password: password, Password: password,
OutboundDialerOptions: option.OutboundDialerOptions{ DialerOptions: option.DialerOptions{
DialerOptions: option.DialerOptions{ Detour: "detour-out",
Detour: "detour-out",
},
}, },
}, },
}, },

View File

@@ -37,9 +37,6 @@ func testShadowsocksMux(t *testing.T, protocol string) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -101,9 +98,6 @@ func testShadowsocksMux(t *testing.T, protocol string) {
func testVMessMux(t *testing.T, protocol string) { func testVMessMux(t *testing.T, protocol string) {
user, _ := uuid.NewV4() user, _ := uuid.NewV4()
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -13,9 +13,6 @@ import (
func TestNaiveInboundWithNginx(t *testing.T) { func TestNaiveInboundWithNginx(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,
@@ -62,9 +59,6 @@ func TestNaiveInboundWithNginx(t *testing.T) {
func TestNaiveInbound(t *testing.T) { func TestNaiveInbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,
@@ -110,9 +104,6 @@ func TestNaiveHTTP3Inbound(t *testing.T) {
} }
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,

View File

@@ -77,9 +77,6 @@ func testShadowsocksInboundWithShadowsocksRust(t *testing.T, method string, pass
Cmd: []string{"-s", F.ToString("127.0.0.1:", serverPort), "-b", F.ToString("0.0.0.0:", clientPort), "-m", method, "-k", password, "-U"}, Cmd: []string{"-s", F.ToString("127.0.0.1:", serverPort), "-b", F.ToString("0.0.0.0:", clientPort), "-m", method, "-k", password, "-U"},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
@@ -105,9 +102,6 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
Cmd: []string{"-s", F.ToString("0.0.0.0:", serverPort), "-m", method, "-k", password, "-U"}, Cmd: []string{"-s", F.ToString("0.0.0.0:", serverPort), "-m", method, "-k", password, "-U"},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -138,9 +132,6 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
func testShadowsocksSelf(t *testing.T, method string, password string) { func testShadowsocksSelf(t *testing.T, method string, password string) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -199,9 +190,6 @@ func TestShadowsocksUoT(t *testing.T) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -60,10 +60,11 @@ func TestShadowTLS(t *testing.T) {
ShadowsocksOptions: option.ShadowsocksOutboundOptions{ ShadowsocksOptions: option.ShadowsocksOutboundOptions{
Method: method, Method: method,
Password: password, Password: password,
OutboundDialerOptions: option.OutboundDialerOptions{ DialerOptions: option.DialerOptions{
DialerOptions: option.DialerOptions{ Detour: "detour",
Detour: "detour", },
}, MultiplexOptions: &option.MultiplexOptions{
Enabled: true,
}, },
}, },
}, },
@@ -95,7 +96,7 @@ func TestShadowTLS(t *testing.T) {
}}, }},
}, },
}) })
testTCP(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func TestShadowTLSOutbound(t *testing.T) { func TestShadowTLSOutbound(t *testing.T) {
@@ -131,10 +132,8 @@ func TestShadowTLSOutbound(t *testing.T) {
{ {
Type: C.TypeSocks, Type: C.TypeSocks,
SocksOptions: option.SocksOutboundOptions{ SocksOptions: option.SocksOutboundOptions{
OutboundDialerOptions: option.OutboundDialerOptions{ DialerOptions: option.DialerOptions{
DialerOptions: option.DialerOptions{ Detour: "detour",
Detour: "detour",
},
}, },
}, },
}, },

View File

@@ -20,9 +20,6 @@ func TestTrojanOutbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -58,9 +55,6 @@ func TestTrojanOutbound(t *testing.T) {
func TestTrojanSelf(t *testing.T) { func TestTrojanSelf(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -27,9 +27,6 @@ func testV2RayGRPCInbound(t *testing.T, forceLite bool) {
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
@@ -125,9 +122,6 @@ func testV2RayGRPCOutbound(t *testing.T, forceLite bool) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -11,31 +11,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestV2RayWebscoketSelf(t *testing.T) {
t.Run("basic", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
})
})
t.Run("v2ray early data", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: 2048,
},
})
})
t.Run("xray early data", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: 2048,
EarlyDataHeaderName: "Sec-WebSocket-Protocol",
},
})
})
}
func TestV2RayHTTPSelf(t *testing.T) { func TestV2RayHTTPSelf(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{ testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeHTTP, Type: C.V2RayTransportTypeHTTP,
@@ -69,9 +44,6 @@ func testVMessTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -148,9 +120,6 @@ func testTrojanTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -229,9 +198,6 @@ func TestVMessQUICSelf(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -307,9 +273,6 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
user, err := uuid.DefaultGenerator.NewV4() user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err) require.NoError(t, err)
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

197
test/v2ray_ws_test.go Normal file
View File

@@ -0,0 +1,197 @@
package main
import (
"net/netip"
"os"
"testing"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/gofrs/uuid"
"github.com/spyzhov/ajson"
"github.com/stretchr/testify/require"
)
func TestV2RayWebsocket(t *testing.T) {
t.Run("self", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
})
})
t.Run("self-early-data", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: 2048,
},
})
})
t.Run("self-xray-early-data", func(t *testing.T) {
testV2RayTransportSelf(t, &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: 2048,
EarlyDataHeaderName: "Sec-WebSocket-Protocol",
},
})
})
t.Run("inbound", func(t *testing.T) {
testV2RayWebsocketInbound(t, 0, "")
})
t.Run("inbound-early-data", func(t *testing.T) {
testV2RayWebsocketInbound(t, 2048, "")
})
t.Run("inbound-xray-early-data", func(t *testing.T) {
testV2RayWebsocketInbound(t, 2048, "Sec-WebSocket-Protocol")
})
t.Run("outbound", func(t *testing.T) {
testV2RayWebsocketOutbound(t, 0, "")
})
t.Run("outbound-early-data", func(t *testing.T) {
testV2RayWebsocketOutbound(t, 2048, "")
})
t.Run("outbound-xray-early-data", func(t *testing.T) {
testV2RayWebsocketOutbound(t, 2048, "Sec-WebSocket-Protocol")
})
}
func testV2RayWebsocketInbound(t *testing.T, maxEarlyData uint32, earlyDataHeaderName string) {
userId, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Users: []option.VMessUser{
{
Name: "sekai",
UUID: userId.String(),
},
},
TLS: &option.InboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
KeyPath: keyPem,
},
Transport: &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: maxEarlyData,
EarlyDataHeaderName: earlyDataHeaderName,
},
},
},
},
},
})
content, err := os.ReadFile("config/vmess-ws-client.json")
require.NoError(t, err)
config, err := ajson.Unmarshal(content)
require.NoError(t, err)
config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort))
outbound := config.MustKey("outbounds").MustIndex(0)
settings := outbound.MustKey("settings").MustKey("vnext").MustIndex(0)
settings.MustKey("port").SetNumeric(float64(serverPort))
user := settings.MustKey("users").MustIndex(0)
user.MustKey("id").SetString(userId.String())
wsSettings := outbound.MustKey("streamSettings").MustKey("wsSettings")
wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
content, err = ajson.Marshal(config)
require.NoError(t, err)
startDockerContainer(t, DockerOptions{
Image: ImageV2RayCore,
Ports: []uint16{serverPort, testPort},
EntryPoint: "v2ray",
Stdin: content,
Bind: map[string]string{
certPem: "/path/to/certificate.crt",
keyPem: "/path/to/private.key",
},
})
testSuitSimple(t, clientPort, testPort)
}
func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHeaderName string) {
userId, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
content, err := os.ReadFile("config/vmess-ws-server.json")
require.NoError(t, err)
config, err := ajson.Unmarshal(content)
require.NoError(t, err)
inbound := config.MustKey("inbounds").MustIndex(0)
inbound.MustKey("port").SetNumeric(float64(serverPort))
inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(userId.String())
wsSettings := inbound.MustKey("streamSettings").MustKey("wsSettings")
wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
content, err = ajson.Marshal(config)
require.NoError(t, err)
startDockerContainer(t, DockerOptions{
Image: ImageV2RayCore,
Ports: []uint16{serverPort, testPort},
EntryPoint: "v2ray",
Stdin: content,
Env: []string{"V2RAY_VMESS_AEAD_FORCED=false"},
Bind: map[string]string{
certPem: "/path/to/certificate.crt",
keyPem: "/path/to/private.key",
},
})
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeVMess,
Tag: "vmess-out",
VMessOptions: option.VMessOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: userId.String(),
Security: "zero",
TLS: &option.OutboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
},
Transport: &option.V2RayTransportOptions{
Type: C.V2RayTransportTypeWebsocket,
WebsocketOptions: option.V2RayWebsocketOptions{
MaxEarlyData: maxEarlyData,
EarlyDataHeaderName: earlyDataHeaderName,
},
},
},
},
},
})
testSuitSimple(t, clientPort, testPort)
}

View File

@@ -182,9 +182,6 @@ func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, al
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
@@ -231,9 +228,6 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, g
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
@@ -267,9 +261,6 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, g
func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) { func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -21,9 +21,6 @@ func TestWireGuard(t *testing.T) {
}) })
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
startInstance(t, option.Options{ startInstance(t, option.Options{
Log: &option.LogOptions{
Level: "error",
},
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,

View File

@@ -6,6 +6,7 @@ import (
"syscall" "syscall"
"github.com/sagernet/quic-go" "github.com/sagernet/quic-go"
"github.com/sagernet/sing-box/common/baderror"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
) )
@@ -38,6 +39,16 @@ type StreamWrapper struct {
quic.Stream quic.Stream
} }
func (s *StreamWrapper) Read(p []byte) (n int, err error) {
n, err = s.Stream.Read(p)
return n, baderror.WrapQUIC(err)
}
func (s *StreamWrapper) Write(p []byte) (n int, err error) {
n, err = s.Stream.Write(p)
return n, baderror.WrapQUIC(err)
}
func (s *StreamWrapper) LocalAddr() net.Addr { func (s *StreamWrapper) LocalAddr() net.Addr {
return s.Conn.LocalAddr() return s.Conn.LocalAddr()
} }
@@ -50,14 +61,6 @@ func (s *StreamWrapper) Upstream() any {
return s.Stream return s.Stream
} }
func (s *StreamWrapper) ReaderReplaceable() bool {
return true
}
func (s *StreamWrapper) WriterReplaceable() bool {
return true
}
func (s *StreamWrapper) Close() error { func (s *StreamWrapper) Close() error {
s.CancelRead(0) s.CancelRead(0)
s.Stream.Close() s.Stream.Close()

View File

@@ -167,6 +167,9 @@ func (c *EarlyWebsocketConn) SetWriteDeadline(t time.Time) error {
func wrapError(err error) error { func wrapError(err error) error {
if websocket.IsCloseError(err, websocket.CloseNormalClosure) { if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
return io.EOF
}
if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) {
return net.ErrClosed return net.ErrClosed
} }
return err return err