Compare commits
10 Commits
v1.3-beta7
...
v1.3-beta2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b290d0ed32 | ||
|
|
2afe662646 | ||
|
|
107a9a3b51 | ||
|
|
3d0c64f523 | ||
|
|
422ca34ac2 | ||
|
|
6d63f9255f | ||
|
|
6f2cc9761d | ||
|
|
b484d9bca6 | ||
|
|
58c4fd745a | ||
|
|
7d1e6affb3 |
12
.github/workflows/debug.yml
vendored
12
.github/workflows/debug.yml
vendored
@@ -31,6 +31,12 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go-${{ hashFiles('**/go.sum') }}
|
||||||
- name: Add cache to Go proxy
|
- name: Add cache to Go proxy
|
||||||
run: |
|
run: |
|
||||||
version=`git rev-parse HEAD`
|
version=`git rev-parse HEAD`
|
||||||
@@ -190,6 +196,12 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go-${{ hashFiles('**/go.sum') }}
|
||||||
- name: Build
|
- name: Build
|
||||||
id: build
|
id: build
|
||||||
run: make
|
run: make
|
||||||
|
|||||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -31,6 +31,12 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go-${{ hashFiles('**/go.sum') }}
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
13
Makefile
13
Makefile
@@ -77,20 +77,13 @@ test_stdio:
|
|||||||
go mod tidy && \
|
go mod tidy && \
|
||||||
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
||||||
|
|
||||||
android:
|
|
||||||
go run ./cmd/internal/build_libbox -target android
|
|
||||||
|
|
||||||
ios:
|
|
||||||
go run ./cmd/internal/build_libbox -target ios
|
|
||||||
|
|
||||||
lib:
|
lib:
|
||||||
go run ./cmd/internal/build_libbox -target android
|
go run ./cmd/internal/build_libbox
|
||||||
go run ./cmd/internal/build_libbox -target ios
|
|
||||||
|
|
||||||
lib_install:
|
lib_install:
|
||||||
go get -v -d
|
go get -v -d
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20230413023804-244d7ff07035
|
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20221130124640-349ebaa752ca
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20230413023804-244d7ff07035
|
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20221130124640-349ebaa752ca
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin dist sing-box
|
rm -rf bin dist sing-box
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ The universal proxy platform.
|
|||||||
|
|
||||||
https://sing-box.sagernet.org
|
https://sing-box.sagernet.org
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
https://community.sagernet.org/c/sing-box/
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -35,11 +35,6 @@ type OutboundGroup interface {
|
|||||||
All() []string
|
All() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type URLTestGroup interface {
|
|
||||||
OutboundGroup
|
|
||||||
URLTest(ctx context.Context, url string) (map[string]uint16, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OutboundTag(detour Outbound) string {
|
func OutboundTag(detour Outbound) string {
|
||||||
if group, isGroup := detour.(OutboundGroup); isGroup {
|
if group, isGroup := detour.(OutboundGroup); isGroup {
|
||||||
return group.Now()
|
return group.Now()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type Conn struct {
|
|||||||
element *list.Element[io.Closer]
|
element *list.Element[io.Closer]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(conn net.Conn) (net.Conn, error) {
|
func NewConn(conn net.Conn) (*Conn, error) {
|
||||||
connAccess.Lock()
|
connAccess.Lock()
|
||||||
element := openConnection.PushBack(conn)
|
element := openConnection.PushBack(conn)
|
||||||
connAccess.Unlock()
|
connAccess.Unlock()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type PacketConn struct {
|
|||||||
element *list.Element[io.Closer]
|
element *list.Element[io.Closer]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
|
func NewPacketConn(conn net.PacketConn) (*PacketConn, error) {
|
||||||
connAccess.Lock()
|
connAccess.Lock()
|
||||||
element := openConnection.PushBack(conn)
|
element := openConnection.PushBack(conn)
|
||||||
connAccess.Unlock()
|
connAccess.Unlock()
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, M.SocksaddrFrom(destinationAddress, destination.Port)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResolveDialer) Upstream() any {
|
func (d *ResolveDialer) Upstream() any {
|
||||||
|
|||||||
@@ -414,11 +414,7 @@ func (c *ClientPacketAddrConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if destination.IsFqdn() {
|
addr = destination.UDPAddr()
|
||||||
addr = destination
|
|
||||||
} else {
|
|
||||||
addr = destination.UDPAddr()
|
|
||||||
}
|
|
||||||
var length uint16
|
var length uint16
|
||||||
err = binary.Read(c.ExtendedConn, binary.BigEndian, &length)
|
err = binary.Read(c.ExtendedConn, binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ package process
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os/user"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Searcher interface {
|
type Searcher interface {
|
||||||
@@ -30,15 +28,5 @@ type Info struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
||||||
info, err := searcher.FindProcessInfo(ctx, network, source, destination)
|
return findProcessInfo(searcher, ctx, network, source, destination)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if info.UserId != -1 {
|
|
||||||
osUser, _ := user.LookupId(F.ToString(info.UserId))
|
|
||||||
if osUser != nil {
|
|
||||||
info.User = osUser.Username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
25
common/process/searcher_with_name.go
Normal file
25
common/process/searcher_with_name.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build linux && !android
|
||||||
|
|
||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/netip"
|
||||||
|
"os/user"
|
||||||
|
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
)
|
||||||
|
|
||||||
|
func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
||||||
|
info, err := searcher.FindProcessInfo(ctx, network, source, destination)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if info.UserId != -1 {
|
||||||
|
osUser, _ := user.LookupId(F.ToString(info.UserId))
|
||||||
|
if osUser != nil {
|
||||||
|
info.User = osUser.Username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
12
common/process/searcher_without_name.go
Normal file
12
common/process/searcher_without_name.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//go:build !linux || android
|
||||||
|
|
||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
||||||
|
return searcher.FindProcessInfo(ctx, network, source, destination)
|
||||||
|
}
|
||||||
@@ -24,12 +24,12 @@ func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout
|
|||||||
}
|
}
|
||||||
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "set read deadline")
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = buffer.ReadOnceFrom(conn)
|
_, err = buffer.ReadOnceFrom(conn)
|
||||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "read payload")
|
return nil, err
|
||||||
}
|
}
|
||||||
var metadata *adapter.InboundContext
|
var metadata *adapter.InboundContext
|
||||||
var errors []error
|
var errors []error
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ func NewSTDServer(ctx context.Context, router adapter.Router, logger log.Logger,
|
|||||||
tlsConfig.ServerName = options.ServerName
|
tlsConfig.ServerName = options.ServerName
|
||||||
}
|
}
|
||||||
if len(options.ALPN) > 0 {
|
if len(options.ALPN) > 0 {
|
||||||
tlsConfig.NextProtos = append(options.ALPN, tlsConfig.NextProtos...)
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, options.ALPN...)
|
||||||
}
|
}
|
||||||
if options.MinVersion != "" {
|
if options.MinVersion != "" {
|
||||||
minVersion, err := ParseTLSVersion(options.MinVersion)
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ func (s *HistoryStorage) StoreURLTestHistory(tag string, history *History) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) {
|
func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) {
|
||||||
if link == "" {
|
|
||||||
link = "https://www.gstatic.com/generate_204"
|
|
||||||
}
|
|
||||||
linkURL, err := url.Parse(link)
|
linkURL, err := url.Parse(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,30 +1,3 @@
|
|||||||
#### 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
|
|
||||||
|
|
||||||
* Add Clash.Meta API compatibility for Clash API
|
|
||||||
* Download Yacd-meta by default if the specified Clash `external_ui` directory is empty
|
|
||||||
* Add path and headers option for HTTP outbound
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
#### 1.3-beta4
|
|
||||||
|
|
||||||
* Fix bugs
|
|
||||||
|
|
||||||
#### 1.3-beta2
|
#### 1.3-beta2
|
||||||
|
|
||||||
* Download clash-dashboard if the specified Clash `external_ui` directory is empty
|
* Download clash-dashboard if the specified Clash `external_ui` directory is empty
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
"clash_api": {
|
"clash_api": {
|
||||||
"external_controller": "127.0.0.1:9090",
|
"external_controller": "127.0.0.1:9090",
|
||||||
"external_ui": "folder",
|
"external_ui": "folder",
|
||||||
"external_ui_download_url": "",
|
|
||||||
"external_ui_download_detour": "",
|
|
||||||
"secret": "",
|
"secret": "",
|
||||||
"default_mode": "rule",
|
"default_mode": "rule",
|
||||||
"store_selected": false,
|
"store_selected": false,
|
||||||
@@ -55,18 +53,6 @@ A relative path to the configuration directory or an absolute path to a
|
|||||||
directory in which you put some static web resource. sing-box will then
|
directory in which you put some static web resource. sing-box will then
|
||||||
serve it at `http://{{external-controller}}/ui`.
|
serve it at `http://{{external-controller}}/ui`.
|
||||||
|
|
||||||
#### external_ui_download_url
|
|
||||||
|
|
||||||
ZIP download URL for the external UI, will be used if the specified `external_ui` directory is empty.
|
|
||||||
|
|
||||||
`https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip` will be used if empty.
|
|
||||||
|
|
||||||
#### external_ui_download_detour
|
|
||||||
|
|
||||||
The tag of the outbound to download the external UI.
|
|
||||||
|
|
||||||
Default outbound will be used if empty.
|
|
||||||
|
|
||||||
#### secret
|
#### secret
|
||||||
|
|
||||||
Secret for the RESTful API (optional)
|
Secret for the RESTful API (optional)
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
"clash_api": {
|
"clash_api": {
|
||||||
"external_controller": "127.0.0.1:9090",
|
"external_controller": "127.0.0.1:9090",
|
||||||
"external_ui": "folder",
|
"external_ui": "folder",
|
||||||
"external_ui_download_url": "",
|
|
||||||
"external_ui_download_detour": "",
|
|
||||||
"secret": "",
|
"secret": "",
|
||||||
"default_mode": "rule",
|
"default_mode": "rule",
|
||||||
"store_selected": false,
|
"store_selected": false,
|
||||||
@@ -53,18 +51,6 @@ RESTful web API 监听地址。如果为空,则禁用 Clash API。
|
|||||||
|
|
||||||
到静态网页资源目录的相对路径或绝对路径。sing-box 会在 `http://{{external-controller}}/ui` 下提供它。
|
到静态网页资源目录的相对路径或绝对路径。sing-box 会在 `http://{{external-controller}}/ui` 下提供它。
|
||||||
|
|
||||||
#### external_ui_download_url
|
|
||||||
|
|
||||||
静态网页资源的 ZIP 下载 URL,如果指定的 `external_ui` 目录为空,将使用。
|
|
||||||
|
|
||||||
默认使用 `https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip`。
|
|
||||||
|
|
||||||
#### external_ui_download_detour
|
|
||||||
|
|
||||||
用于下载静态网页资源的出站的标签。
|
|
||||||
|
|
||||||
如果为空,将使用默认出站。
|
|
||||||
|
|
||||||
#### secret
|
#### secret
|
||||||
|
|
||||||
RESTful API 的密钥(可选)
|
RESTful API 的密钥(可选)
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
"server_port": 1080,
|
"server_port": 1080,
|
||||||
"username": "sekai",
|
"username": "sekai",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"path": "",
|
|
||||||
"headers": {},
|
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
|
||||||
... // Dial Fields
|
... // Dial Fields
|
||||||
@@ -41,14 +39,6 @@ Basic authorization username.
|
|||||||
|
|
||||||
Basic authorization password.
|
Basic authorization password.
|
||||||
|
|
||||||
#### path
|
|
||||||
|
|
||||||
Path of HTTP request.
|
|
||||||
|
|
||||||
#### headers
|
|
||||||
|
|
||||||
Extra headers of HTTP request.
|
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
|
TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
"server_port": 1080,
|
"server_port": 1080,
|
||||||
"username": "sekai",
|
"username": "sekai",
|
||||||
"password": "admin",
|
"password": "admin",
|
||||||
"path": "",
|
|
||||||
"headers": {},
|
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
|
||||||
... // 拨号字段
|
... // 拨号字段
|
||||||
@@ -41,14 +39,6 @@ Basic 认证用户名。
|
|||||||
|
|
||||||
Basic 认证密码。
|
Basic 认证密码。
|
||||||
|
|
||||||
#### path
|
|
||||||
|
|
||||||
HTTP 请求路径。
|
|
||||||
|
|
||||||
#### headers
|
|
||||||
|
|
||||||
HTTP 请求的额外标头。
|
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
|
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"proxy-b",
|
"proxy-b",
|
||||||
"proxy-c"
|
"proxy-c"
|
||||||
],
|
],
|
||||||
"url": "https://www.gstatic.com/generate_204",
|
"url": "http://www.gstatic.com/generate_204",
|
||||||
"interval": "1m",
|
"interval": "1m",
|
||||||
"tolerance": 50
|
"tolerance": 50
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ List of outbound tags to test.
|
|||||||
|
|
||||||
#### url
|
#### url
|
||||||
|
|
||||||
The URL to test. `https://www.gstatic.com/generate_204` will be used if empty.
|
The URL to test. `http://www.gstatic.com/generate_204` will be used if empty.
|
||||||
|
|
||||||
#### interval
|
#### interval
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"proxy-b",
|
"proxy-b",
|
||||||
"proxy-c"
|
"proxy-c"
|
||||||
],
|
],
|
||||||
"url": "https://www.gstatic.com/generate_204",
|
"url": "http://www.gstatic.com/generate_204",
|
||||||
"interval": "1m",
|
"interval": "1m",
|
||||||
"tolerance": 50
|
"tolerance": 50
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#### url
|
#### url
|
||||||
|
|
||||||
用于测试的链接。默认使用 `https://www.gstatic.com/generate_204`。
|
用于测试的链接。默认使用 `http://www.gstatic.com/generate_204`。
|
||||||
|
|
||||||
#### interval
|
#### interval
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package clashapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
|
||||||
"github.com/sagernet/websocket"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"github.com/go-chi/render"
|
|
||||||
)
|
|
||||||
|
|
||||||
// API created by Clash.Meta
|
|
||||||
|
|
||||||
func (s *Server) setupMetaAPI(r chi.Router) {
|
|
||||||
r.Get("/memory", memory(s.trafficManager))
|
|
||||||
r.Mount("/group", groupRouter(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Memory struct {
|
|
||||||
Inuse uint64 `json:"inuse"`
|
|
||||||
OSLimit uint64 `json:"oslimit"` // maybe we need it in the future
|
|
||||||
}
|
|
||||||
|
|
||||||
func memory(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var wsConn *websocket.Conn
|
|
||||||
if websocket.IsWebSocketUpgrade(r) {
|
|
||||||
var err error
|
|
||||||
wsConn, err = upgrader.Upgrade(w, r, nil)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if wsConn == nil {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
render.Status(r, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
tick := time.NewTicker(time.Second)
|
|
||||||
defer tick.Stop()
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
var err error
|
|
||||||
first := true
|
|
||||||
for range tick.C {
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
inuse := trafficManager.Snapshot().Memory
|
|
||||||
|
|
||||||
// make chat.js begin with zero
|
|
||||||
// this is shit var,but we need output 0 for first time
|
|
||||||
if first {
|
|
||||||
first = false
|
|
||||||
inuse = 0
|
|
||||||
}
|
|
||||||
if err := json.NewEncoder(buf).Encode(Memory{
|
|
||||||
Inuse: inuse,
|
|
||||||
OSLimit: 0,
|
|
||||||
}); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if wsConn == nil {
|
|
||||||
_, err = w.Write(buf.Bytes())
|
|
||||||
w.(http.Flusher).Flush()
|
|
||||||
} else {
|
|
||||||
err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
package clashapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
|
||||||
"github.com/sagernet/sing-box/outbound"
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/batch"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"github.com/go-chi/render"
|
|
||||||
)
|
|
||||||
|
|
||||||
func groupRouter(server *Server) http.Handler {
|
|
||||||
r := chi.NewRouter()
|
|
||||||
r.Get("/", getGroups(server))
|
|
||||||
r.Route("/{name}", func(r chi.Router) {
|
|
||||||
r.Use(parseProxyName, findProxyByName(server.router))
|
|
||||||
r.Get("/", getGroup(server))
|
|
||||||
r.Get("/delay", getGroupDelay(server))
|
|
||||||
})
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGroups(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
groups := common.Map(common.Filter(server.router.Outbounds(), func(it adapter.Outbound) bool {
|
|
||||||
_, isGroup := it.(adapter.OutboundGroup)
|
|
||||||
return isGroup
|
|
||||||
}), func(it adapter.Outbound) *badjson.JSONObject {
|
|
||||||
return proxyInfo(server, it)
|
|
||||||
})
|
|
||||||
render.JSON(w, r, render.M{
|
|
||||||
"proxies": groups,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGroup(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
|
||||||
if _, ok := proxy.(adapter.OutboundGroup); ok {
|
|
||||||
render.JSON(w, r, proxyInfo(server, proxy))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
render.Status(r, http.StatusNotFound)
|
|
||||||
render.JSON(w, r, ErrNotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
|
||||||
group, ok := proxy.(adapter.OutboundGroup)
|
|
||||||
if !ok {
|
|
||||||
render.Status(r, http.StatusNotFound)
|
|
||||||
render.JSON(w, r, ErrNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
query := r.URL.Query()
|
|
||||||
url := query.Get("url")
|
|
||||||
if strings.HasPrefix(url, "http://") {
|
|
||||||
url = ""
|
|
||||||
}
|
|
||||||
timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
render.Status(r, http.StatusBadRequest)
|
|
||||||
render.JSON(w, r, ErrBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(r.Context(), time.Millisecond*time.Duration(timeout))
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
var result map[string]uint16
|
|
||||||
if urlTestGroup, isURLTestGroup := group.(adapter.URLTestGroup); isURLTestGroup {
|
|
||||||
result, err = urlTestGroup.URLTest(ctx, url)
|
|
||||||
} else {
|
|
||||||
outbounds := common.FilterNotNil(common.Map(group.All(), func(it string) adapter.Outbound {
|
|
||||||
itOutbound, _ := server.router.Outbound(it)
|
|
||||||
return itOutbound
|
|
||||||
}))
|
|
||||||
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
|
|
||||||
checked := make(map[string]bool)
|
|
||||||
result = make(map[string]uint16)
|
|
||||||
var resultAccess sync.Mutex
|
|
||||||
for _, detour := range outbounds {
|
|
||||||
tag := detour.Tag()
|
|
||||||
realTag := outbound.RealTag(detour)
|
|
||||||
if checked[realTag] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
checked[realTag] = true
|
|
||||||
p, loaded := server.router.Outbound(realTag)
|
|
||||||
if !loaded {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
b.Go(realTag, func() (any, error) {
|
|
||||||
t, err := urltest.URLTest(ctx, url, p)
|
|
||||||
if err != nil {
|
|
||||||
server.logger.Debug("outbound ", tag, " unavailable: ", err)
|
|
||||||
server.urlTestHistory.DeleteURLTestHistory(realTag)
|
|
||||||
} else {
|
|
||||||
server.logger.Debug("outbound ", tag, " available: ", t, "ms")
|
|
||||||
server.urlTestHistory.StoreURLTestHistory(realTag, &urltest.History{
|
|
||||||
Time: time.Now(),
|
|
||||||
Delay: t,
|
|
||||||
})
|
|
||||||
resultAccess.Lock()
|
|
||||||
result[tag] = t
|
|
||||||
resultAccess.Unlock()
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
b.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
render.Status(r, http.StatusGatewayTimeout)
|
|
||||||
render.JSON(w, r, newError(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
render.JSON(w, r, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -215,9 +214,6 @@ func getProxyDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
|||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
query := r.URL.Query()
|
query := r.URL.Query()
|
||||||
url := query.Get("url")
|
url := query.Get("url")
|
||||||
if strings.HasPrefix(url, "http://") {
|
|
||||||
url = ""
|
|
||||||
}
|
|
||||||
timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 16)
|
timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
render.Status(r, http.StatusBadRequest)
|
render.Status(r, http.StatusBadRequest)
|
||||||
|
|||||||
@@ -109,8 +109,6 @@ func NewServer(router adapter.Router, logFactory log.ObservableFactory, options
|
|||||||
r.Mount("/profile", profileRouter())
|
r.Mount("/profile", profileRouter())
|
||||||
r.Mount("/cache", cacheRouter(router))
|
r.Mount("/cache", cacheRouter(router))
|
||||||
r.Mount("/dns", dnsRouter(router))
|
r.Mount("/dns", dnsRouter(router))
|
||||||
|
|
||||||
server.setupMetaAPI(r)
|
|
||||||
})
|
})
|
||||||
if options.ExternalUI != "" {
|
if options.ExternalUI != "" {
|
||||||
server.externalUI = C.BasePath(os.ExpandEnv(options.ExternalUI))
|
server.externalUI = C.BasePath(os.ExpandEnv(options.ExternalUI))
|
||||||
@@ -408,5 +406,5 @@ func getLogs(logFactory log.ObservableFactory) func(w http.ResponseWriter, r *ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
func version(w http.ResponseWriter, r *http.Request) {
|
func version(w http.ResponseWriter, r *http.Request) {
|
||||||
render.JSON(w, r, render.M{"version": "sing-box " + C.Version, "premium": true, "meta": true})
|
render.JSON(w, r, render.M{"version": "sing-box " + C.Version, "premium": true})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (s *Server) downloadExternalUI() error {
|
|||||||
if s.externalUIDownloadURL != "" {
|
if s.externalUIDownloadURL != "" {
|
||||||
downloadURL = s.externalUIDownloadURL
|
downloadURL = s.externalUIDownloadURL
|
||||||
} else {
|
} else {
|
||||||
downloadURL = "https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip"
|
downloadURL = "https://github.com/Dreamacro/clash-dashboard/archive/refs/heads/gh-pages.zip"
|
||||||
}
|
}
|
||||||
s.logger.Info("downloading external ui")
|
s.logger.Info("downloading external ui")
|
||||||
var detour adapter.Outbound
|
var detour adapter.Outbound
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package trafficontrol
|
package trafficontrol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi/compatible"
|
"github.com/sagernet/sing-box/experimental/clashapi/compatible"
|
||||||
@@ -19,15 +18,12 @@ type Manager struct {
|
|||||||
connections compatible.Map[string, tracker]
|
connections compatible.Map[string, tracker]
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
// process *process.Process
|
|
||||||
memory uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager() *Manager {
|
func NewManager() *Manager {
|
||||||
manager := &Manager{
|
manager := &Manager{
|
||||||
ticker: time.NewTicker(time.Second),
|
ticker: time.NewTicker(time.Second),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
// process: &process.Process{Pid: int32(os.Getpid())},
|
|
||||||
}
|
}
|
||||||
go manager.handle()
|
go manager.handle()
|
||||||
return manager
|
return manager
|
||||||
@@ -62,18 +58,10 @@ func (m *Manager) Snapshot() *Snapshot {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
//if memoryInfo, err := m.process.MemoryInfo(); err == nil {
|
|
||||||
// m.memory = memoryInfo.RSS
|
|
||||||
//} else {
|
|
||||||
var memStats runtime.MemStats
|
|
||||||
runtime.ReadMemStats(&memStats)
|
|
||||||
m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased
|
|
||||||
|
|
||||||
return &Snapshot{
|
return &Snapshot{
|
||||||
UploadTotal: m.uploadTotal.Load(),
|
UploadTotal: m.uploadTotal.Load(),
|
||||||
DownloadTotal: m.downloadTotal.Load(),
|
DownloadTotal: m.downloadTotal.Load(),
|
||||||
Connections: connections,
|
Connections: connections,
|
||||||
Memory: m.memory,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,5 +100,4 @@ type Snapshot struct {
|
|||||||
DownloadTotal int64 `json:"downloadTotal"`
|
DownloadTotal int64 `json:"downloadTotal"`
|
||||||
UploadTotal int64 `json:"uploadTotal"`
|
UploadTotal int64 `json:"uploadTotal"`
|
||||||
Connections []tracker `json:"connections"`
|
Connections []tracker `json:"connections"`
|
||||||
Memory uint64 `json:"memory"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/sagernet/sing/common/atomic"
|
"github.com/sagernet/sing/common/atomic"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/debug"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/observable"
|
"github.com/sagernet/sing/common/observable"
|
||||||
"github.com/sagernet/sing/common/x/list"
|
"github.com/sagernet/sing/common/x/list"
|
||||||
@@ -72,9 +71,7 @@ func (s *CommandServer) loopConnection(listener net.Listener) {
|
|||||||
go func() {
|
go func() {
|
||||||
hErr := s.handleConnection(conn)
|
hErr := s.handleConnection(conn)
|
||||||
if hErr != nil && !E.IsClosed(err) {
|
if hErr != nil && !E.IsClosed(err) {
|
||||||
if debug.Enabled {
|
log.Warn("log-server: process connection: ", hErr)
|
||||||
log.Warn("log-server: process connection: ", hErr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (s *CommandServer) handleStatusConn(conn net.Conn) error {
|
|||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return nil
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
//go:build darwin || linux
|
|
||||||
|
|
||||||
package libbox
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
var stderrFile *os.File
|
|
||||||
|
|
||||||
func RedirectStderr(path string) error {
|
|
||||||
if stats, err := os.Stat(path); err == nil && stats.Size() > 0 {
|
|
||||||
_ = os.Rename(path, path+".old")
|
|
||||||
}
|
|
||||||
outputFile, err := os.Create(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = unix.Dup2(int(outputFile.Fd()), int(os.Stderr.Fd()))
|
|
||||||
if err != nil {
|
|
||||||
outputFile.Close()
|
|
||||||
os.Remove(outputFile.Name())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
stderrFile = outputFile
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
16
go.mod
16
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.15.0
|
github.com/Dreamacro/clash v1.14.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
|
||||||
@@ -12,7 +12,7 @@ require (
|
|||||||
github.com/go-chi/chi/v5 v5.0.8
|
github.com/go-chi/chi/v5 v5.0.8
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-chi/render v1.0.2
|
github.com/go-chi/render v1.0.2
|
||||||
github.com/gofrs/uuid/v5 v5.0.0
|
github.com/gofrs/uuid v4.4.0+incompatible
|
||||||
github.com/hashicorp/yamux v0.1.1
|
github.com/hashicorp/yamux v0.1.1
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16
|
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
@@ -22,15 +22,15 @@ require (
|
|||||||
github.com/oschwald/maxminddb-golang v1.10.0
|
github.com/oschwald/maxminddb-golang v1.10.0
|
||||||
github.com/pires/go-proxyproto v0.7.0
|
github.com/pires/go-proxyproto v0.7.0
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
|
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
|
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
|
||||||
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
|
github.com/sagernet/sing v0.2.2
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
|
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1
|
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1
|
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661
|
||||||
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
|
github.com/sagernet/sing-vmess v0.1.4-0.20230408141409-03460e4b014a
|
||||||
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
|
||||||
|
|||||||
32
go.sum
32
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.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE=
|
github.com/Dreamacro/clash v1.14.0 h1:ehJ/C/1m9LEjmME72WSE/Y2YqbR3Q54AbjqiRCvtyW4=
|
||||||
github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE=
|
github.com/Dreamacro/clash v1.14.0/go.mod h1:ia2CU7V713H1QdCqMwOLK9U9V5Ay8X0voj3yQr2tk+I=
|
||||||
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=
|
||||||
@@ -33,8 +33,8 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
|
|||||||
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@@ -101,8 +101,8 @@ 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-20230413023804-244d7ff07035 h1:KttYh6bBhIw8Y6/Ljn7CGwC3CKZn788rzMJmeAKjY+8=
|
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca h1:w56+kf8BeqLqllrRJ1tdwKc3sCdWOn/DuNHpY9fAiqs=
|
||||||
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca/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=
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 h1:tztuJB+giOWNRKQEBVY2oI3PsheTooMdh+/yxemYQYY=
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 h1:tztuJB+giOWNRKQEBVY2oI3PsheTooMdh+/yxemYQYY=
|
||||||
@@ -111,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 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
|
github.com/sagernet/sing v0.2.2 h1:qfEdSLuwFgIIkeLOcwVQkVDzKLHtclXb93Ql0zZA+aE=
|
||||||
github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
github.com/sagernet/sing v0.2.2/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
|
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/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440/go.mod h1:69PNSHyEmXdjf6C+bXBOdr2GQnPeEyWjIzo/MV8gmz8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw=
|
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4 h1:mKpXBBnAhTy9/CvDKqt5cN78LKX8cVUqjoWEXI/g0No=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I=
|
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4/go.mod h1:NFEROpOEiLG+lEoSPNpSL2yDyXx6q0OJvwWnEAd40cI=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1 h1:Gf8YD/4zCjfM9xxVzI0QVYAnjMCtsDHcIp84CUdY3VA=
|
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1/go.mod h1:espnHDPRQeG95ZoU3xfHDFnc6Nt4GvbbuPV2okN+x/E=
|
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U=
|
||||||
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 h1:aZ03KgmR9COPitVqo8NTPHeaHmbJYDZ8mkumnUV4oGQ=
|
github.com/sagernet/sing-vmess v0.1.4-0.20230408141409-03460e4b014a h1:kClgb0phf3Jn1nKufk9eGTcnGriXpdbm5/dYtP613tA=
|
||||||
github.com/sagernet/sing-vmess v0.1.4/go.mod h1:NensKZJDgfPsUf3TzFD8kTuzI3CQfN1Tj3Eygti5Isg=
|
github.com/sagernet/sing-vmess v0.1.4-0.20230408141409-03460e4b014a/go.mod h1:xuq/+XxniuiYqxK9Qdz9OPRqcDgjkwR2PaobjmNZbLM=
|
||||||
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=
|
||||||
|
|||||||
@@ -90,9 +90,6 @@ func (n *Naive) Start() error {
|
|||||||
n.httpServer = &http.Server{
|
n.httpServer = &http.Server{
|
||||||
Handler: n,
|
Handler: n,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
BaseContext: func(listener net.Listener) context.Context {
|
|
||||||
return n.ctx
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
var sErr error
|
var sErr error
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ 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"
|
||||||
@@ -27,7 +25,7 @@ var (
|
|||||||
|
|
||||||
type ShadowsocksMulti struct {
|
type ShadowsocksMulti struct {
|
||||||
myInboundAdapter
|
myInboundAdapter
|
||||||
service shadowsocks.MultiService[int]
|
service *shadowaead_2022.MultiService[int]
|
||||||
users []option.ShadowsocksUser
|
users []option.ShadowsocksUser
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,26 +49,16 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
|
|||||||
} else {
|
} else {
|
||||||
udpTimeout = int64(C.UDPTimeout.Seconds())
|
udpTimeout = int64(C.UDPTimeout.Seconds())
|
||||||
}
|
}
|
||||||
var (
|
if !common.Contains(shadowaead_2022.List, options.Method) {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package ntp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -10,7 +9,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/common/settings"
|
"github.com/sagernet/sing-box/common/settings"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
@@ -22,7 +20,7 @@ var _ adapter.TimeService = (*Service)(nil)
|
|||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel common.ContextCancelCauseFunc
|
cancel context.CancelFunc
|
||||||
server M.Socksaddr
|
server M.Socksaddr
|
||||||
writeToSystem bool
|
writeToSystem bool
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
@@ -32,7 +30,7 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) *Service {
|
func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) *Service {
|
||||||
ctx, cancel := common.ContextWithCancelCause(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
server := options.ServerOptions.Build()
|
server := options.ServerOptions.Build()
|
||||||
if server.Port == 0 {
|
if server.Port == 0 {
|
||||||
server.Port = 123
|
server.Port = 123
|
||||||
@@ -66,7 +64,7 @@ func (s *Service) Start() error {
|
|||||||
|
|
||||||
func (s *Service) Close() error {
|
func (s *Service) Close() error {
|
||||||
s.ticker.Stop()
|
s.ticker.Stop()
|
||||||
s.cancel(os.ErrClosed)
|
s.cancel()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,omitempty"`
|
Password string `json:"password"`
|
||||||
Users []ShadowsocksUser `json:"users,omitempty"`
|
Users []ShadowsocksUser `json:"users,omitempty"`
|
||||||
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ type SocksOutboundOptions struct {
|
|||||||
type HTTPOutboundOptions struct {
|
type HTTPOutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
TLS *OutboundTLSOptions `json:"tls,omitempty"`
|
TLS *OutboundTLSOptions `json:"tls,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
Headers map[string]Listable[string] `json:"headers,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, t
|
|||||||
case C.TypeSelector:
|
case C.TypeSelector:
|
||||||
return NewSelector(router, logger, tag, options.SelectorOptions)
|
return NewSelector(router, logger, tag, options.SelectorOptions)
|
||||||
case C.TypeURLTest:
|
case C.TypeURLTest:
|
||||||
return NewURLTest(ctx, router, logger, tag, options.URLTestOptions)
|
return NewURLTest(router, logger, tag, options.URLTestOptions)
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown outbound type: ", options.Type)
|
return nil, E.New("unknown outbound type: ", options.Type)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,6 @@ 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
|
||||||
@@ -125,12 +121,3 @@ 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)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -102,10 +102,11 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
|
|||||||
|
|
||||||
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
fastClose, cancel := context.WithCancel(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(ctx context.Context) error {
|
group.Append0(func(ctx context.Context) error {
|
||||||
|
defer cancel()
|
||||||
_buffer := buf.StackNewSize(dns.FixedPacketSize)
|
_buffer := buf.StackNewSize(dns.FixedPacketSize)
|
||||||
defer common.KeepAlive(_buffer)
|
defer common.KeepAlive(_buffer)
|
||||||
buffer := common.Dup(_buffer)
|
buffer := common.Dup(_buffer)
|
||||||
@@ -114,13 +115,11 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
buffer.FullReset()
|
buffer.FullReset()
|
||||||
destination, err := conn.ReadPacket(buffer)
|
destination, err := conn.ReadPacket(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var message mDNS.Msg
|
var message mDNS.Msg
|
||||||
err = message.Unpack(buffer.Bytes())
|
err = message.Unpack(buffer.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeout.Update()
|
timeout.Update()
|
||||||
@@ -128,22 +127,17 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
go func() error {
|
go func() error {
|
||||||
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
|
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeout.Update()
|
timeout.Update()
|
||||||
responseBuffer := buf.NewPacket()
|
responseBuffer := buf.NewPacket()
|
||||||
n, err := response.PackBuffer(responseBuffer.FreeBytes())
|
n, err := response.PackBuffer(responseBuffer.FreeBytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
|
||||||
responseBuffer.Release()
|
responseBuffer.Release()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
responseBuffer.Truncate(len(n))
|
responseBuffer.Truncate(len(n))
|
||||||
err = conn.WritePacket(responseBuffer, destination)
|
err = conn.WritePacket(responseBuffer, destination)
|
||||||
if err != nil {
|
|
||||||
cancel(err)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -15,14 +14,14 @@ import (
|
|||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
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"
|
||||||
sHTTP "github.com/sagernet/sing/protocol/http"
|
"github.com/sagernet/sing/protocol/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*HTTP)(nil)
|
var _ adapter.Outbound = (*HTTP)(nil)
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
myOutboundAdapter
|
myOutboundAdapter
|
||||||
client *sHTTP.Client
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@@ -30,13 +29,6 @@ func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, option
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var headers http.Header
|
|
||||||
if options.Headers != nil {
|
|
||||||
headers = make(http.Header)
|
|
||||||
for key, values := range options.Headers {
|
|
||||||
headers[key] = values
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &HTTP{
|
return &HTTP{
|
||||||
myOutboundAdapter{
|
myOutboundAdapter{
|
||||||
protocol: C.TypeHTTP,
|
protocol: C.TypeHTTP,
|
||||||
@@ -45,14 +37,7 @@ func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, option
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
},
|
},
|
||||||
sHTTP.NewClient(sHTTP.Options{
|
http.NewClient(detour, options.ServerOptions.Build(), options.Username, options.Password, nil),
|
||||||
Dialer: detour,
|
|
||||||
Server: options.ServerOptions.Build(),
|
|
||||||
Username: options.Username,
|
|
||||||
Password: options.Password,
|
|
||||||
Path: options.Path,
|
|
||||||
Headers: headers,
|
|
||||||
}),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -20,14 +19,12 @@ 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 {
|
||||||
myOutboundAdapter
|
myOutboundAdapter
|
||||||
ctx context.Context
|
|
||||||
tags []string
|
tags []string
|
||||||
link string
|
link string
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
@@ -35,7 +32,7 @@ type URLTest struct {
|
|||||||
group *URLTestGroup
|
group *URLTestGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.URLTestOutboundOptions) (*URLTest, error) {
|
func NewURLTest(router adapter.Router, logger log.ContextLogger, tag string, options option.URLTestOutboundOptions) (*URLTest, error) {
|
||||||
outbound := &URLTest{
|
outbound := &URLTest{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
myOutboundAdapter: myOutboundAdapter{
|
||||||
protocol: C.TypeURLTest,
|
protocol: C.TypeURLTest,
|
||||||
@@ -43,7 +40,6 @@ func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
},
|
},
|
||||||
ctx: ctx,
|
|
||||||
tags: options.Outbounds,
|
tags: options.Outbounds,
|
||||||
link: options.URL,
|
link: options.URL,
|
||||||
interval: time.Duration(options.Interval),
|
interval: time.Duration(options.Interval),
|
||||||
@@ -71,12 +67,11 @@ 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.router, s.logger, outbounds, s.link, s.interval, s.tolerance)
|
||||||
go s.group.CheckOutbounds()
|
return s.group.Start()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) Close() error {
|
func (s URLTest) Close() error {
|
||||||
return common.Close(
|
return common.Close(
|
||||||
common.PtrOrNil(s.group),
|
common.PtrOrNil(s.group),
|
||||||
)
|
)
|
||||||
@@ -90,31 +85,39 @@ func (s *URLTest) All() []string {
|
|||||||
return s.tags
|
return s.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
|
|
||||||
return s.group.URLTest(ctx, link)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
s.logger.ErrorContext(ctx, err)
|
s.logger.ErrorContext(ctx, err)
|
||||||
s.group.history.DeleteURLTestHistory(outbound.Tag())
|
go s.group.checkOutbounds()
|
||||||
|
outbounds := s.group.Fallback(outbound)
|
||||||
|
for _, fallback := range outbounds {
|
||||||
|
conn, err = fallback.DialContext(ctx, network, destination)
|
||||||
|
if err == nil {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
s.logger.ErrorContext(ctx, err)
|
s.logger.ErrorContext(ctx, err)
|
||||||
s.group.history.DeleteURLTestHistory(outbound.Tag())
|
go s.group.checkOutbounds()
|
||||||
|
outbounds := s.group.Fallback(outbound)
|
||||||
|
for _, fallback := range outbounds {
|
||||||
|
conn, err = fallback.ListenPacket(ctx, destination)
|
||||||
|
if err == nil {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +129,7 @@ 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
|
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
outbounds []adapter.Outbound
|
outbounds []adapter.Outbound
|
||||||
@@ -141,12 +138,15 @@ 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{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16) *URLTestGroup {
|
func NewURLTestGroup(router adapter.Router, logger log.Logger, outbounds []adapter.Outbound, link string, interval time.Duration, tolerance uint16) *URLTestGroup {
|
||||||
|
if link == "" {
|
||||||
|
//goland:noinspection HttpUrlsUsage
|
||||||
|
link = "http://www.gstatic.com/generate_204"
|
||||||
|
}
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
interval = C.DefaultURLTestInterval
|
interval = C.DefaultURLTestInterval
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,6 @@ func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logg
|
|||||||
history = urltest.NewHistoryStorage()
|
history = urltest.NewHistoryStorage()
|
||||||
}
|
}
|
||||||
return &URLTestGroup{
|
return &URLTestGroup{
|
||||||
ctx: ctx,
|
|
||||||
router: router,
|
router: router,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
outbounds: outbounds,
|
outbounds: outbounds,
|
||||||
@@ -172,23 +171,13 @@ func NewURLTestGroup(ctx context.Context, router adapter.Router, logger log.Logg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Start() {
|
func (g *URLTestGroup) Start() error {
|
||||||
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
|
||||||
@@ -248,26 +237,20 @@ 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)
|
b, _ := batch.New(context.Background(), batch.WithConcurrencyNum[any](10))
|
||||||
}
|
|
||||||
|
|
||||||
func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
|
|
||||||
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
|
|
||||||
checked := make(map[string]bool)
|
checked := make(map[string]bool)
|
||||||
result := make(map[string]uint16)
|
|
||||||
var resultAccess sync.Mutex
|
|
||||||
for _, detour := range g.outbounds {
|
for _, detour := range g.outbounds {
|
||||||
tag := detour.Tag()
|
tag := detour.Tag()
|
||||||
realTag := RealTag(detour)
|
realTag := RealTag(detour)
|
||||||
@@ -286,7 +269,7 @@ func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uin
|
|||||||
b.Go(realTag, func() (any, error) {
|
b.Go(realTag, func() (any, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.TCPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.TCPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
t, err := urltest.URLTest(ctx, link, p)
|
t, err := urltest.URLTest(ctx, g.link, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.logger.Debug("outbound ", tag, " unavailable: ", err)
|
g.logger.Debug("outbound ", tag, " unavailable: ", err)
|
||||||
g.history.DeleteURLTestHistory(realTag)
|
g.history.DeleteURLTestHistory(realTag)
|
||||||
@@ -296,13 +279,9 @@ func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uin
|
|||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Delay: t,
|
Delay: t,
|
||||||
})
|
})
|
||||||
resultAccess.Lock()
|
|
||||||
result[tag] = t
|
|
||||||
resultAccess.Unlock()
|
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
b.Wait()
|
b.Wait()
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, outbound, dialer.New(router, options.DialerOptions), isConnect, connectAddr, reserved)
|
outbound.bind = wireguard.NewClientBind(ctx, 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")
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
if metadata.InboundOptions.SniffEnabled {
|
if metadata.InboundOptions.SniffEnabled {
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
buffer.FullReset()
|
buffer.FullReset()
|
||||||
sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost)
|
sniffMetadata, _ := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost)
|
||||||
if sniffMetadata != nil {
|
if sniffMetadata != nil {
|
||||||
metadata.Protocol = sniffMetadata.Protocol
|
metadata.Protocol = sniffMetadata.Protocol
|
||||||
metadata.Domain = sniffMetadata.Domain
|
metadata.Domain = sniffMetadata.Domain
|
||||||
@@ -675,8 +675,6 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
} else {
|
} else {
|
||||||
r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
|
r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol)
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
|
||||||
r.logger.TraceContext(ctx, "sniffed no protocol: ", err)
|
|
||||||
}
|
}
|
||||||
if !buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
conn = bufio.NewCachedConn(conn, buffer)
|
conn = bufio.NewCachedConn(conn, buffer)
|
||||||
|
|||||||
23
test/go.mod
23
test/go.mod
@@ -7,14 +7,14 @@ require github.com/sagernet/sing-box v0.0.0
|
|||||||
replace github.com/sagernet/sing-box => ../
|
replace github.com/sagernet/sing-box => ../
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/docker/docker v23.0.3+incompatible
|
github.com/docker/docker v20.10.18+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/gofrs/uuid/v5 v5.0.0
|
github.com/gofrs/uuid v4.4.0+incompatible
|
||||||
github.com/sagernet/sing v0.2.2
|
github.com/sagernet/sing v0.2.2-0.20230407053809-308e421e33c2
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4
|
github.com/sagernet/sing-shadowsocks v0.2.0
|
||||||
github.com/spyzhov/ajson v0.8.0
|
github.com/spyzhov/ajson v0.7.1
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.2
|
||||||
go.uber.org/goleak v1.2.1
|
go.uber.org/goleak v1.2.0
|
||||||
golang.org/x/net v0.9.0
|
golang.org/x/net v0.9.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ require (
|
|||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 // indirect
|
github.com/insomniacslk/dhcp v0.0.0-20230327135226-74ae03f2425e // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.15 // indirect
|
github.com/klauspost/compress v1.15.15 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||||
@@ -70,15 +70,16 @@ require (
|
|||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||||
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440 // indirect
|
github.com/sagernet/sing-dns v0.1.5-0.20230407055526-2a27418e7855 // indirect
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 // indirect
|
github.com/sagernet/sing-shadowtls v0.1.0 // indirect
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab // indirect
|
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab // indirect
|
||||||
github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 // indirect
|
github.com/sagernet/sing-vmess v0.1.3 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
|
||||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
go.etcd.io/bbolt v1.3.7 // indirect
|
go.etcd.io/bbolt v1.3.7 // indirect
|
||||||
@@ -86,7 +87,7 @@ require (
|
|||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect
|
go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect
|
||||||
golang.org/x/crypto v0.8.0 // indirect
|
golang.org/x/crypto v0.7.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.7.0 // indirect
|
golang.org/x/sys v0.7.0 // indirect
|
||||||
|
|||||||
48
test/go.sum
48
test/go.sum
@@ -25,8 +25,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
|
github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc=
|
||||||
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
@@ -43,8 +43,8 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
|
|||||||
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
@@ -61,8 +61,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
|
|||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E=
|
github.com/insomniacslk/dhcp v0.0.0-20230327135226-74ae03f2425e h1:8ChxkWKTVYg7LKBvYNLNRnlobgbPrzzossZUoST2T7o=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI=
|
github.com/insomniacslk/dhcp v0.0.0-20230327135226-74ae03f2425e/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI=
|
||||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
@@ -126,18 +126,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.2 h1:qfEdSLuwFgIIkeLOcwVQkVDzKLHtclXb93Ql0zZA+aE=
|
github.com/sagernet/sing v0.2.2-0.20230407053809-308e421e33c2 h1:VjeHDxEgpB2fqK5G16yBvtLacibvg3h2MsIjal0UXH0=
|
||||||
github.com/sagernet/sing v0.2.2/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
github.com/sagernet/sing v0.2.2-0.20230407053809-308e421e33c2/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
|
||||||
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.20230407055526-2a27418e7855 h1:a3W2X1n5C/oYGp/Dd26eoymME3iXN8TJq7LZtO2MSUY=
|
||||||
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.20230407055526-2a27418e7855/go.mod h1:69PNSHyEmXdjf6C+bXBOdr2GQnPeEyWjIzo/MV8gmz8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4 h1:mKpXBBnAhTy9/CvDKqt5cN78LKX8cVUqjoWEXI/g0No=
|
github.com/sagernet/sing-shadowsocks v0.2.0 h1:ILDWL7pwWfkPLEbviE/MyCgfjaBmJY/JVVY+5jhSb58=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4/go.mod h1:NFEROpOEiLG+lEoSPNpSL2yDyXx6q0OJvwWnEAd40cI=
|
github.com/sagernet/sing-shadowsocks v0.2.0/go.mod h1:ysYzszRLpNzJSorvlWRMuzU6Vchsp7sd52q+JNY4axw=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc=
|
github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U=
|
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
||||||
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.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc=
|
github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
|
||||||
github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7/go.mod h1:A9iGfwYmAEmVg8bavkqQ7Hx7nr9Pc2oWMYDwbLIBDjY=
|
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
|
||||||
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=
|
||||||
@@ -149,8 +149,10 @@ github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl
|
|||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/spyzhov/ajson v0.8.0 h1:sFXyMbi4Y/BKjrsfkUZHSjA2JM1184enheSjjoT/zCc=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/spyzhov/ajson v0.8.0/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/spyzhov/ajson v0.7.1 h1:1MDIlPc6x0zjNtpa7tDzRAyFAvRX+X8ZsvtYz5lZg6A=
|
||||||
|
github.com/spyzhov/ajson v0.7.1/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
@@ -174,8 +176,8 @@ go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
|||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
@@ -187,10 +189,11 @@ 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.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@@ -225,6 +228,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/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-20220715151400-c0bba94af5f8/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-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var muxProtocols = []mux.Protocol{
|
var muxProtocols = []mux.Protocol{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/spyzhov/ajson"
|
"github.com/spyzhov/ajson"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/spyzhov/ajson"
|
"github.com/spyzhov/ajson"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-box/transport/vless"
|
"github.com/sagernet/sing-box/transport/vless"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/spyzhov/ajson"
|
"github.com/spyzhov/ajson"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
"github.com/spyzhov/ajson"
|
"github.com/spyzhov/ajson"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,30 +17,22 @@ type NATPacketConn struct {
|
|||||||
func NewNATPacketConn(conn N.PacketConn, origin M.Socksaddr, destination M.Socksaddr) *NATPacketConn {
|
func NewNATPacketConn(conn N.PacketConn, origin M.Socksaddr, destination M.Socksaddr) *NATPacketConn {
|
||||||
return &NATPacketConn{
|
return &NATPacketConn{
|
||||||
PacketConn: conn,
|
PacketConn: conn,
|
||||||
origin: socksaddrWithoutPort(origin),
|
origin: origin,
|
||||||
destination: socksaddrWithoutPort(destination),
|
destination: destination,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NATPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
func (c *NATPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
||||||
destination, err = c.PacketConn.ReadPacket(buffer)
|
destination, err = c.PacketConn.ReadPacket(buffer)
|
||||||
if socksaddrWithoutPort(destination) == c.origin {
|
if destination == c.origin {
|
||||||
destination = M.Socksaddr{
|
destination = c.destination
|
||||||
Addr: c.destination.Addr,
|
|
||||||
Fqdn: c.destination.Fqdn,
|
|
||||||
Port: destination.Port,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *NATPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
func (c *NATPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
if socksaddrWithoutPort(destination) == c.destination {
|
if destination == c.destination {
|
||||||
destination = M.Socksaddr{
|
destination = c.origin
|
||||||
Addr: c.origin.Addr,
|
|
||||||
Fqdn: c.origin.Fqdn,
|
|
||||||
Port: destination.Port,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return c.PacketConn.WritePacket(buffer, destination)
|
return c.PacketConn.WritePacket(buffer, destination)
|
||||||
}
|
}
|
||||||
@@ -48,8 +40,3 @@ func (c *NATPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr)
|
|||||||
func (c *NATPacketConn) Upstream() any {
|
func (c *NATPacketConn) Upstream() any {
|
||||||
return c.PacketConn
|
return c.PacketConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func socksaddrWithoutPort(destination M.Socksaddr) M.Socksaddr {
|
|
||||||
destination.Port = 0
|
|
||||||
return destination
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -498,12 +498,7 @@ func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = copy(p, msg.Data)
|
n = copy(p, msg.Data)
|
||||||
destination := M.ParseSocksaddrHostPort(msg.Host, msg.Port)
|
addr = M.ParseSocksaddrHostPort(msg.Host, msg.Port).UDPAddr()
|
||||||
if destination.IsFqdn() {
|
|
||||||
addr = destination
|
|
||||||
} else {
|
|
||||||
addr = destination.UDPAddr()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -131,11 +131,7 @@ func (c *ClientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = buffer.Len()
|
n = buffer.Len()
|
||||||
if destination.IsFqdn() {
|
addr = destination.UDPAddr()
|
||||||
addr = destination
|
|
||||||
} else {
|
|
||||||
addr = destination.UDPAddr()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,11 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks
|
|||||||
}
|
}
|
||||||
switch options.Type {
|
switch options.Type {
|
||||||
case C.V2RayTransportTypeHTTP:
|
case C.V2RayTransportTypeHTTP:
|
||||||
return v2rayhttp.NewClient(ctx, dialer, serverAddr, options.HTTPOptions, tlsConfig)
|
return v2rayhttp.NewClient(ctx, dialer, serverAddr, options.HTTPOptions, tlsConfig), nil
|
||||||
case C.V2RayTransportTypeGRPC:
|
case C.V2RayTransportTypeGRPC:
|
||||||
|
if tlsConfig == nil {
|
||||||
|
return nil, C.ErrTLSRequired
|
||||||
|
}
|
||||||
return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig)
|
return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig)
|
||||||
case C.V2RayTransportTypeWebsocket:
|
case C.V2RayTransportTypeWebsocket:
|
||||||
return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil
|
return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ type Client struct {
|
|||||||
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
||||||
var dialOptions []grpc.DialOption
|
var dialOptions []grpc.DialOption
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
if len(tlsConfig.NextProtos()) == 0 {
|
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
|
||||||
}
|
|
||||||
dialOptions = append(dialOptions, grpc.WithTransportCredentials(NewTLSTransportCredentials(tlsConfig)))
|
dialOptions = append(dialOptions, grpc.WithTransportCredentials(NewTLSTransportCredentials(tlsConfig)))
|
||||||
} else {
|
} else {
|
||||||
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
@@ -104,10 +102,10 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
client := NewGunServiceClient(clientConn).(GunServiceCustomNameClient)
|
client := NewGunServiceClient(clientConn).(GunServiceCustomNameClient)
|
||||||
ctx, cancel := common.ContextWithCancelCause(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
stream, err := client.TunCustomName(ctx, c.serviceName)
|
stream, err := client.TunCustomName(ctx, c.serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel(err)
|
cancel()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return deadline.NewConn(NewGRPCConn(stream, cancel)), nil
|
return deadline.NewConn(NewGRPCConn(stream, cancel)), nil
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package v2raygrpc
|
package v2raygrpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/baderror"
|
"github.com/sagernet/sing-box/common/baderror"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,11 +14,11 @@ var _ net.Conn = (*GRPCConn)(nil)
|
|||||||
|
|
||||||
type GRPCConn struct {
|
type GRPCConn struct {
|
||||||
GunService
|
GunService
|
||||||
cancel common.ContextCancelCauseFunc
|
cancel context.CancelFunc
|
||||||
cache []byte
|
cache []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGRPCConn(service GunService, cancel common.ContextCancelCauseFunc) *GRPCConn {
|
func NewGRPCConn(service GunService, cancel context.CancelFunc) *GRPCConn {
|
||||||
if client, isClient := service.(GunService_TunClient); isClient {
|
if client, isClient := service.(GunService_TunClient); isClient {
|
||||||
service = &clientConnWrapper{client}
|
service = &clientConnWrapper{client}
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,6 @@ func (c *GRPCConn) Read(b []byte) (n int, err error) {
|
|||||||
hunk, err := c.Recv()
|
hunk, err := c.Recv()
|
||||||
err = baderror.WrapGRPC(err)
|
err = baderror.WrapGRPC(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.cancel(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n = copy(b, hunk.Data)
|
n = copy(b, hunk.Data)
|
||||||
@@ -50,14 +49,13 @@ func (c *GRPCConn) Read(b []byte) (n int, err error) {
|
|||||||
func (c *GRPCConn) Write(b []byte) (n int, err error) {
|
func (c *GRPCConn) Write(b []byte) (n int, err error) {
|
||||||
err = baderror.WrapGRPC(c.Send(&Hunk{Data: b}))
|
err = baderror.WrapGRPC(c.Send(&Hunk{Data: b}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.cancel(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GRPCConn) Close() error {
|
func (c *GRPCConn) Close() error {
|
||||||
c.cancel(net.ErrClosed)
|
c.cancel()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/bufio/deadline"
|
"github.com/sagernet/sing/common/bufio/deadline"
|
||||||
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"
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
gM "google.golang.org/grpc/metadata"
|
gM "google.golang.org/grpc/metadata"
|
||||||
@@ -33,9 +31,7 @@ type Server struct {
|
|||||||
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler) (*Server, error) {
|
func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler N.TCPConnectionHandler) (*Server, error) {
|
||||||
var serverOptions []grpc.ServerOption
|
var serverOptions []grpc.ServerOption
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
if !common.Contains(tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
tlsConfig.SetNextProtos([]string{"h2"})
|
||||||
tlsConfig.SetNextProtos(append([]string{"h2"}, tlsConfig.NextProtos()...))
|
|
||||||
}
|
|
||||||
serverOptions = append(serverOptions, grpc.Creds(NewTLSTransportCredentials(tlsConfig)))
|
serverOptions = append(serverOptions, grpc.Creds(NewTLSTransportCredentials(tlsConfig)))
|
||||||
}
|
}
|
||||||
if options.IdleTimeout > 0 {
|
if options.IdleTimeout > 0 {
|
||||||
@@ -50,7 +46,7 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Tun(server GunService_TunServer) error {
|
func (s *Server) Tun(server GunService_TunServer) error {
|
||||||
ctx, cancel := common.ContextWithCancelCause(s.ctx)
|
ctx, cancel := context.WithCancel(s.ctx)
|
||||||
conn := NewGRPCConn(server, cancel)
|
conn := NewGRPCConn(server, cancel)
|
||||||
var metadata M.Metadata
|
var metadata M.Metadata
|
||||||
if remotePeer, loaded := peer.FromContext(server.Context()); loaded {
|
if remotePeer, loaded := peer.FromContext(server.Context()); loaded {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package v2raygrpclite
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -31,57 +32,56 @@ type Client struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
transport *http2.Transport
|
transport http.RoundTripper
|
||||||
options option.V2RayGRPCOptions
|
options option.V2RayGRPCOptions
|
||||||
url *url.URL
|
url *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) adapter.V2RayClientTransport {
|
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) adapter.V2RayClientTransport {
|
||||||
client := &Client{
|
var transport http.RoundTripper
|
||||||
|
if tlsConfig == nil {
|
||||||
|
transport = &http.Transport{
|
||||||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
|
transport = &http2.Transport{
|
||||||
|
ReadIdleTimeout: time.Duration(options.IdleTimeout),
|
||||||
|
PingTimeout: time.Duration(options.PingTimeout),
|
||||||
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
|
||||||
|
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tls.ClientHandshake(ctx, conn, tlsConfig)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Client{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
dialer: dialer,
|
dialer: dialer,
|
||||||
serverAddr: serverAddr,
|
serverAddr: serverAddr,
|
||||||
options: options,
|
options: options,
|
||||||
transport: &http2.Transport{
|
transport: transport,
|
||||||
ReadIdleTimeout: time.Duration(options.IdleTimeout),
|
|
||||||
PingTimeout: time.Duration(options.PingTimeout),
|
|
||||||
DisableCompression: true,
|
|
||||||
},
|
|
||||||
url: &url.URL{
|
url: &url.URL{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: serverAddr.String(),
|
Host: serverAddr.String(),
|
||||||
Path: "/" + options.ServiceName + "/Tun",
|
Path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)),
|
||||||
RawPath: "/" + url.PathEscape(options.ServiceName) + "/Tun",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if tlsConfig == nil {
|
|
||||||
client.transport.DialTLSContext = func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
|
|
||||||
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if len(tlsConfig.NextProtos()) == 0 {
|
|
||||||
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
|
||||||
}
|
|
||||||
client.transport.DialTLSContext = func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
|
|
||||||
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tls.ClientHandshake(ctx, conn, tlsConfig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
||||||
pipeInReader, pipeInWriter := io.Pipe()
|
pipeInReader, pipeInWriter := io.Pipe()
|
||||||
request := &http.Request{
|
request := &http.Request{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Body: pipeInReader,
|
Body: pipeInReader,
|
||||||
URL: c.url,
|
URL: c.url,
|
||||||
Header: defaultClientHeader,
|
Proto: "HTTP/2",
|
||||||
|
ProtoMajor: 2,
|
||||||
|
Header: defaultClientHeader,
|
||||||
}
|
}
|
||||||
request = request.WithContext(ctx)
|
request = request.WithContext(ctx)
|
||||||
conn := newLateGunConn(pipeInWriter)
|
conn := newLateGunConn(pipeInWriter)
|
||||||
@@ -97,8 +97,6 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Close() error {
|
func (c *Client) Close() error {
|
||||||
if c.transport != nil {
|
v2rayhttp.CloseIdleConnections(c.transport)
|
||||||
v2rayhttp.CloseIdleConnections(c.transport)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,6 @@ func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
|
|||||||
dataLen := buffer.Len()
|
dataLen := buffer.Len()
|
||||||
varLen := rw.UVariantLen(uint64(dataLen))
|
varLen := rw.UVariantLen(uint64(dataLen))
|
||||||
header := buffer.ExtendHeader(6 + varLen)
|
header := buffer.ExtendHeader(6 + varLen)
|
||||||
_ = header[6]
|
|
||||||
header[0] = 0x00
|
header[0] = 0x00
|
||||||
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
||||||
header[5] = 0x0A
|
header[5] = 0x0A
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package v2raygrpclite
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -44,16 +46,13 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
|
|||||||
server := &Server{
|
server := &Server{
|
||||||
tlsConfig: tlsConfig,
|
tlsConfig: tlsConfig,
|
||||||
handler: handler,
|
handler: handler,
|
||||||
path: "/" + options.ServiceName + "/Tun",
|
path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)),
|
||||||
h2Server: &http2.Server{
|
h2Server: &http2.Server{
|
||||||
IdleTimeout: time.Duration(options.IdleTimeout),
|
IdleTimeout: time.Duration(options.IdleTimeout),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
server.httpServer = &http.Server{
|
server.httpServer = &http.Server{
|
||||||
Handler: server,
|
Handler: server,
|
||||||
BaseContext: func(net.Listener) context.Context {
|
|
||||||
return ctx
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
|
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
|
||||||
return server, nil
|
return server, nil
|
||||||
@@ -94,16 +93,14 @@ func (s *Server) fallbackRequest(ctx context.Context, writer http.ResponseWriter
|
|||||||
} else if fErr == os.ErrInvalid {
|
} else if fErr == os.ErrInvalid {
|
||||||
fErr = nil
|
fErr = nil
|
||||||
}
|
}
|
||||||
if statusCode > 0 {
|
writer.WriteHeader(statusCode)
|
||||||
writer.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Serve(listener net.Listener) error {
|
func (s *Server) Serve(listener net.Listener) error {
|
||||||
if s.tlsConfig != nil {
|
if s.tlsConfig != nil {
|
||||||
if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
if len(s.tlsConfig.NextProtos()) == 0 {
|
||||||
s.tlsConfig.SetNextProtos(append([]string{"h2"}, s.tlsConfig.NextProtos()...))
|
s.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
}
|
}
|
||||||
listener = aTLS.NewListener(listener, s.tlsConfig)
|
listener = aTLS.NewListener(listener, s.tlsConfig)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -15,7 +16,6 @@ import (
|
|||||||
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"
|
||||||
sHTTP "github.com/sagernet/sing/protocol/http"
|
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
@@ -34,7 +34,7 @@ type Client struct {
|
|||||||
headers http.Header
|
headers http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPOptions, tlsConfig tls.Config) adapter.V2RayClientTransport {
|
||||||
var transport http.RoundTripper
|
var transport http.RoundTripper
|
||||||
if tlsConfig == nil {
|
if tlsConfig == nil {
|
||||||
transport = &http.Transport{
|
transport = &http.Transport{
|
||||||
@@ -43,9 +43,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(tlsConfig.NextProtos()) == 0 {
|
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
||||||
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
|
|
||||||
}
|
|
||||||
transport = &http2.Transport{
|
transport = &http2.Transport{
|
||||||
ReadIdleTimeout: time.Duration(options.IdleTimeout),
|
ReadIdleTimeout: time.Duration(options.IdleTimeout),
|
||||||
PingTimeout: time.Duration(options.PingTimeout),
|
PingTimeout: time.Duration(options.PingTimeout),
|
||||||
@@ -79,15 +77,14 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
|
|||||||
}
|
}
|
||||||
uri.Host = serverAddr.String()
|
uri.Host = serverAddr.String()
|
||||||
uri.Path = options.Path
|
uri.Path = options.Path
|
||||||
err := sHTTP.URLSetPath(&uri, options.Path)
|
if !strings.HasPrefix(uri.Path, "/") {
|
||||||
if err != nil {
|
uri.Path = "/" + uri.Path
|
||||||
return nil, E.New("failed to set path: " + err.Error())
|
|
||||||
}
|
}
|
||||||
for key, valueList := range options.Headers {
|
for key, valueList := range options.Headers {
|
||||||
client.headers[key] = valueList
|
client.headers[key] = valueList
|
||||||
}
|
}
|
||||||
client.url = &uri
|
client.url = &uri
|
||||||
return client, nil
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
||||||
|
|||||||
@@ -70,9 +70,6 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig t
|
|||||||
Handler: server,
|
Handler: server,
|
||||||
ReadHeaderTimeout: C.TCPTimeout,
|
ReadHeaderTimeout: C.TCPTimeout,
|
||||||
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
|
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
|
||||||
BaseContext: func(net.Listener) context.Context {
|
|
||||||
return ctx
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
|
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
|
||||||
return server, nil
|
return server, nil
|
||||||
@@ -105,40 +102,28 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
writer.(http.Flusher).Flush()
|
||||||
|
|
||||||
var metadata M.Metadata
|
var metadata M.Metadata
|
||||||
metadata.Source = sHttp.SourceAddress(request)
|
metadata.Source = sHttp.SourceAddress(request)
|
||||||
if h, ok := writer.(http.Hijacker); ok {
|
if h, ok := writer.(http.Hijacker); ok {
|
||||||
var requestBody *buf.Buffer
|
|
||||||
if contentLength := int(request.ContentLength); contentLength > 0 {
|
|
||||||
requestBody = buf.NewSize(contentLength)
|
|
||||||
_, err := requestBody.ReadFullFrom(request.Body, contentLength)
|
|
||||||
if err != nil {
|
|
||||||
s.fallbackRequest(request.Context(), writer, request, 0, E.Cause(err, "read request"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
|
||||||
writer.(http.Flusher).Flush()
|
|
||||||
conn, reader, err := h.Hijack()
|
conn, reader, err := h.Hijack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.fallbackRequest(request.Context(), writer, request, 0, E.Cause(err, "hijack conn"))
|
s.fallbackRequest(request.Context(), writer, request, http.StatusInternalServerError, E.Cause(err, "hijack conn"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if cacheLen := reader.Reader.Buffered(); cacheLen > 0 {
|
if cacheLen := reader.Reader.Buffered(); cacheLen > 0 {
|
||||||
cache := buf.NewSize(cacheLen)
|
cache := buf.NewSize(cacheLen)
|
||||||
_, err = cache.ReadFullFrom(reader.Reader, cacheLen)
|
_, err = cache.ReadFullFrom(reader.Reader, cacheLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.fallbackRequest(request.Context(), writer, request, 0, E.Cause(err, "read cache"))
|
s.fallbackRequest(request.Context(), writer, request, http.StatusInternalServerError, E.Cause(err, "read cache"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = bufio.NewCachedConn(conn, cache)
|
conn = bufio.NewCachedConn(conn, cache)
|
||||||
}
|
}
|
||||||
if requestBody != nil {
|
|
||||||
conn = bufio.NewCachedConn(conn, requestBody)
|
|
||||||
}
|
|
||||||
s.handler.NewConnection(request.Context(), conn, metadata)
|
s.handler.NewConnection(request.Context(), conn, metadata)
|
||||||
} else {
|
} else {
|
||||||
writer.WriteHeader(http.StatusOK)
|
|
||||||
conn := NewHTTP2Wrapper(&ServerHTTPConn{
|
conn := NewHTTP2Wrapper(&ServerHTTPConn{
|
||||||
NewHTTPConn(request.Body, writer),
|
NewHTTPConn(request.Body, writer),
|
||||||
writer.(http.Flusher),
|
writer.(http.Flusher),
|
||||||
@@ -156,19 +141,12 @@ func (s *Server) fallbackRequest(ctx context.Context, writer http.ResponseWriter
|
|||||||
} else if fErr == os.ErrInvalid {
|
} else if fErr == os.ErrInvalid {
|
||||||
fErr = nil
|
fErr = nil
|
||||||
}
|
}
|
||||||
if statusCode > 0 {
|
writer.WriteHeader(statusCode)
|
||||||
writer.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Serve(listener net.Listener) error {
|
func (s *Server) Serve(listener net.Listener) error {
|
||||||
if s.tlsConfig != nil {
|
if s.tlsConfig != nil {
|
||||||
if len(s.tlsConfig.NextProtos()) == 0 {
|
|
||||||
s.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
|
|
||||||
} else if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
|
||||||
s.tlsConfig.SetNextProtos(append([]string{"h2"}, s.tlsConfig.NextProtos()...))
|
|
||||||
}
|
|
||||||
listener = aTLS.NewListener(listener, s.tlsConfig)
|
listener = aTLS.NewListener(listener, s.tlsConfig)
|
||||||
}
|
}
|
||||||
return s.httpServer.Serve(listener)
|
return s.httpServer.Serve(listener)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -14,7 +15,6 @@ import (
|
|||||||
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"
|
||||||
sHTTP "github.com/sagernet/sing/protocol/http"
|
|
||||||
"github.com/sagernet/websocket"
|
"github.com/sagernet/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,9 +58,8 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
|
|||||||
}
|
}
|
||||||
uri.Host = serverAddr.String()
|
uri.Host = serverAddr.String()
|
||||||
uri.Path = options.Path
|
uri.Path = options.Path
|
||||||
err := sHTTP.URLSetPath(&uri, options.Path)
|
if !strings.HasPrefix(uri.Path, "/") {
|
||||||
if err != nil {
|
uri.Path = "/" + uri.Path
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
headers := make(http.Header)
|
headers := make(http.Header)
|
||||||
for key, value := range options.Headers {
|
for key, value := range options.Headers {
|
||||||
|
|||||||
@@ -69,14 +69,6 @@ func (c *WebsocketConn) SetDeadline(t time.Time) error {
|
|||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WebsocketConn) SetReadDeadline(t time.Time) error {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *WebsocketConn) SetWriteDeadline(t time.Time) error {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *WebsocketConn) Upstream() any {
|
func (c *WebsocketConn) Upstream() any {
|
||||||
return c.Conn.NetConn()
|
return c.Conn.NetConn()
|
||||||
}
|
}
|
||||||
@@ -203,15 +195,24 @@ func (c *EarlyWebsocketConn) RemoteAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) SetDeadline(t time.Time) error {
|
func (c *EarlyWebsocketConn) SetDeadline(t time.Time) error {
|
||||||
return os.ErrInvalid
|
if c.conn == nil {
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
return c.conn.SetDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) SetReadDeadline(t time.Time) error {
|
func (c *EarlyWebsocketConn) SetReadDeadline(t time.Time) error {
|
||||||
return os.ErrInvalid
|
if c.conn == nil {
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
return c.conn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) SetWriteDeadline(t time.Time) error {
|
func (c *EarlyWebsocketConn) SetWriteDeadline(t time.Time) error {
|
||||||
return os.ErrInvalid
|
if c.conn == nil {
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
return c.conn.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) Upstream() any {
|
func (c *EarlyWebsocketConn) Upstream() any {
|
||||||
|
|||||||
@@ -53,9 +53,6 @@ func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsCon
|
|||||||
Handler: server,
|
Handler: server,
|
||||||
ReadHeaderTimeout: C.TCPTimeout,
|
ReadHeaderTimeout: C.TCPTimeout,
|
||||||
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
|
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
|
||||||
BaseContext: func(net.Listener) context.Context {
|
|
||||||
return ctx
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return server, nil
|
return server, nil
|
||||||
}
|
}
|
||||||
@@ -99,7 +96,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
wsConn, err := upgrader.Upgrade(writer, request, nil)
|
wsConn, err := upgrader.Upgrade(writer, request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.fallbackRequest(request.Context(), writer, request, 0, E.Cause(err, "upgrade websocket connection"))
|
s.fallbackRequest(request.Context(), writer, request, http.StatusBadRequest, E.Cause(err, "upgrade websocket connection"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var metadata M.Metadata
|
var metadata M.Metadata
|
||||||
@@ -119,9 +116,7 @@ func (s *Server) fallbackRequest(ctx context.Context, writer http.ResponseWriter
|
|||||||
} else if fErr == os.ErrInvalid {
|
} else if fErr == os.ErrInvalid {
|
||||||
fErr = nil
|
fErr = nil
|
||||||
}
|
}
|
||||||
if statusCode > 0 {
|
writer.WriteHeader(statusCode)
|
||||||
writer.WriteHeader(statusCode)
|
|
||||||
}
|
|
||||||
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
s.handler.NewError(request.Context(), E.Cause(E.Errors(err, E.Cause(fErr, "fallback connection")), "process connection from ", request.RemoteAddr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
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/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -198,11 +198,7 @@ func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.destination.IsFqdn() {
|
addr = c.destination.UDPAddr()
|
||||||
addr = c.destination
|
|
||||||
} else {
|
|
||||||
addr = c.destination.UDPAddr()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
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/gofrs/uuid/v5"
|
"github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service[T comparable] struct {
|
type Service[T comparable] struct {
|
||||||
@@ -147,11 +147,7 @@ func (c *serverPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.destination.IsFqdn() {
|
addr = c.destination.UDPAddr()
|
||||||
addr = c.destination
|
|
||||||
} else {
|
|
||||||
addr = c.destination.UDPAddr()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,7 +18,6 @@ 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
|
||||||
@@ -29,10 +28,9 @@ type ClientBind struct {
|
|||||||
reserved [3]uint8
|
reserved [3]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientBind(ctx context.Context, errorHandler E.Handler, dialer N.Dialer, isConnect bool, connectAddr M.Socksaddr, reserved [3]uint8) *ClientBind {
|
func NewClientBind(ctx context.Context, 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,
|
||||||
@@ -69,10 +67,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, err
|
return nil, &wireError{err}
|
||||||
}
|
}
|
||||||
c.conn = &wireConn{
|
c.conn = &wireConn{
|
||||||
PacketConn: &bufio.UnbindPacketConn{
|
NetPacketConn: &bufio.UnbindPacketConn{
|
||||||
ExtendedConn: bufio.NewExtendedConn(udpConn),
|
ExtendedConn: bufio.NewExtendedConn(udpConn),
|
||||||
Addr: c.connectAddr,
|
Addr: c.connectAddr,
|
||||||
},
|
},
|
||||||
@@ -81,11 +79,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, err
|
return nil, &wireError{err}
|
||||||
}
|
}
|
||||||
c.conn = &wireConn{
|
c.conn = &wireConn{
|
||||||
PacketConn: bufio.NewPacketConn(udpConn),
|
NetPacketConn: bufio.NewPacketConn(udpConn),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.conn, nil
|
return c.conn, nil
|
||||||
@@ -104,31 +102,30 @@ 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 {
|
||||||
select {
|
err = &wireError{err}
|
||||||
case <-c.done:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
c.errorHandler.NewError(context.Background(), E.Cause(err, "connect to server"))
|
|
||||||
err = nil
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n, addr, err := udpConn.ReadFrom(b)
|
buffer := buf.With(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:
|
||||||
c.errorHandler.NewError(context.Background(), E.Cause(err, "read packet"))
|
err = &wireError{err}
|
||||||
}
|
}
|
||||||
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(M.SocksaddrFromNet(addr))
|
ep = Endpoint(destination)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +167,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.WriteTo(b, destination)
|
err = udpConn.WritePacket(buf.As(b), destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
udpConn.Close()
|
udpConn.Close()
|
||||||
}
|
}
|
||||||
@@ -182,7 +179,7 @@ func (c *ClientBind) ParseEndpoint(s string) (conn.Endpoint, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type wireConn struct {
|
type wireConn struct {
|
||||||
net.PacketConn
|
N.NetPacketConn
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
}
|
}
|
||||||
@@ -195,7 +192,7 @@ func (w *wireConn) Close() error {
|
|||||||
return net.ErrClosed
|
return net.ErrClosed
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
w.PacketConn.Close()
|
w.NetPacketConn.Close()
|
||||||
close(w.done)
|
close(w.done)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
22
transport/wireguard/error.go
Normal file
22
transport/wireguard/error.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
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