mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-29 21:27:28 +03:00
Compare commits
1 Commits
v1.0-beta1
...
dev-daemon
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f48f8c5d1c |
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,5 +1,6 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: "Create a report to help us improve."
|
description: "Create a report to help us improve."
|
||||||
|
labels: [ bug ]
|
||||||
body:
|
body:
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: terms
|
id: terms
|
||||||
@@ -55,7 +56,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: log
|
id: config
|
||||||
attributes:
|
attributes:
|
||||||
label: Server and client log file
|
label: Server and client log file
|
||||||
value: |-
|
value: |-
|
||||||
|
|||||||
11
Makefile
11
Makefile
@@ -1,6 +1,6 @@
|
|||||||
NAME = sing-box
|
NAME = sing-box
|
||||||
COMMIT = $(shell git rev-parse --short HEAD)
|
COMMIT = $(shell git rev-parse --short HEAD)
|
||||||
TAGS ?= with_quic,with_wireguard,with_clash_api
|
TAGS ?= with_quic,with_wireguard,with_clash_api,with_daemon
|
||||||
PARAMS = -v -trimpath -tags '$(TAGS)' -ldflags \
|
PARAMS = -v -trimpath -tags '$(TAGS)' -ldflags \
|
||||||
'-X "github.com/sagernet/sing-box/constant.Commit=$(COMMIT)" \
|
'-X "github.com/sagernet/sing-box/constant.Commit=$(COMMIT)" \
|
||||||
-w -s -buildid='
|
-w -s -buildid='
|
||||||
@@ -49,14 +49,7 @@ snapshot:
|
|||||||
ghr --delete --draft --prerelease -p 1 nightly dist/release
|
ghr --delete --draft --prerelease -p 1 nightly dist/release
|
||||||
rm -r dist
|
rm -r dist
|
||||||
|
|
||||||
release:
|
snapshot_install:
|
||||||
goreleaser release --rm-dist --skip-publish
|
|
||||||
mkdir dist/release
|
|
||||||
mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
|
|
||||||
ghr --delete --draft --prerelease -p 3 $(shell git describe --tags) dist/release
|
|
||||||
rm -r dist
|
|
||||||
|
|
||||||
release_install:
|
|
||||||
go install -v github.com/goreleaser/goreleaser@latest
|
go install -v github.com/goreleaser/goreleaser@latest
|
||||||
go install -v github.com/tcnksm/ghr@latest
|
go install -v github.com/tcnksm/ghr@latest
|
||||||
|
|
||||||
|
|||||||
272
cmd/sing-box/cmd_daemon.go
Normal file
272
cmd/sing-box/cmd_daemon.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
//go:build with_daemon
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/json"
|
||||||
|
"github.com/sagernet/sing-box/experimental/daemon"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var commandDaemon = &cobra.Command{
|
||||||
|
Use: "daemon",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
commandDaemon.AddCommand(commandDaemonInstall)
|
||||||
|
commandDaemon.AddCommand(commandDaemonUninstall)
|
||||||
|
commandDaemon.AddCommand(commandDaemonStart)
|
||||||
|
commandDaemon.AddCommand(commandDaemonStop)
|
||||||
|
commandDaemon.AddCommand(commandDaemonRestart)
|
||||||
|
commandDaemon.AddCommand(commandDaemonRun)
|
||||||
|
mainCommand.AddCommand(commandDaemon)
|
||||||
|
mainCommand.AddCommand(commandStart)
|
||||||
|
mainCommand.AddCommand(commandStop)
|
||||||
|
mainCommand.AddCommand(commandStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonInstall = &cobra.Command{
|
||||||
|
Use: "install",
|
||||||
|
Short: "Install daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := installDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonUninstall = &cobra.Command{
|
||||||
|
Use: "uninstall",
|
||||||
|
Short: "Uninstall daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := uninstallDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonStart = &cobra.Command{
|
||||||
|
Use: "start",
|
||||||
|
Short: "Start daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := startDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonStop = &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := stopDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonRestart = &cobra.Command{
|
||||||
|
Use: "restart",
|
||||||
|
Short: "Restart daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := restartDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandDaemonRun = &cobra.Command{
|
||||||
|
Use: "run",
|
||||||
|
Short: "Run daemon",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := runDaemon()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
func installDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Install()
|
||||||
|
}
|
||||||
|
|
||||||
|
func uninstallDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Uninstall()
|
||||||
|
}
|
||||||
|
|
||||||
|
func startDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func restartDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDaemon() error {
|
||||||
|
instance, err := daemon.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return instance.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandStart = &cobra.Command{
|
||||||
|
Use: "start",
|
||||||
|
Short: "Start service",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := startService()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandStop = &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop service",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := stopService()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandStatus = &cobra.Command{
|
||||||
|
Use: "status",
|
||||||
|
Short: "Check service",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := checkService()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
func doRequest(method string, path string, params url.Values, body io.ReadCloser) ([]byte, error) {
|
||||||
|
requestURL := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Path: path,
|
||||||
|
Host: net.JoinHostPort("127.0.0.1", F.ToString(daemon.DefaultDaemonPort)),
|
||||||
|
}
|
||||||
|
if params != nil {
|
||||||
|
requestURL.RawQuery = params.Encode()
|
||||||
|
}
|
||||||
|
request, err := http.NewRequest(method, requestURL.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response, err := http.DefaultClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
var content []byte
|
||||||
|
if response.StatusCode != http.StatusNoContent {
|
||||||
|
content, err = io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNoContent {
|
||||||
|
return nil, E.New(string(content))
|
||||||
|
}
|
||||||
|
return content, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ping() error {
|
||||||
|
response, err := doRequest("GET", "/ping", nil, nil)
|
||||||
|
if err != nil || string(response) != "pong" {
|
||||||
|
return E.New("daemon not running")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startService() error {
|
||||||
|
if err := ping(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
configContent, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read config")
|
||||||
|
}
|
||||||
|
return common.Error(doRequest("POST", "/run", nil, io.NopCloser(bytes.NewReader(configContent))))
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopService() error {
|
||||||
|
if err := ping(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return common.Error(doRequest("GET", "/stop", nil, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkService() error {
|
||||||
|
if err := ping(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
response, err := doRequest("GET", "/status", nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var statusResponse daemon.StatusResponse
|
||||||
|
err = json.Unmarshal(response, &statusResponse)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if statusResponse.Running {
|
||||||
|
log.Info("service running")
|
||||||
|
} else {
|
||||||
|
log.Info("service stopped")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -38,7 +38,7 @@ func printVersion(cmd *cobra.Command, args []string) {
|
|||||||
version += runtime.Version()
|
version += runtime.Version()
|
||||||
version += ", "
|
version += ", "
|
||||||
version += runtime.GOOS
|
version += runtime.GOOS
|
||||||
version += "/"
|
version += ", "
|
||||||
version += runtime.GOARCH
|
version += runtime.GOARCH
|
||||||
version += ", "
|
version += ", "
|
||||||
version += "CGO "
|
version += "CGO "
|
||||||
|
|||||||
@@ -113,10 +113,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
}
|
}
|
||||||
var bindUDPAddr string
|
var bindUDPAddr string
|
||||||
udpDialer := dialer
|
udpDialer := dialer
|
||||||
var bindAddress netip.Addr
|
bindAddress := netip.Addr(options.BindAddress)
|
||||||
if options.BindAddress != nil {
|
|
||||||
bindAddress = options.BindAddress.Build()
|
|
||||||
}
|
|
||||||
if bindAddress.IsValid() {
|
if bindAddress.IsValid() {
|
||||||
dialer.LocalAddr = &net.TCPAddr{
|
dialer.LocalAddr = &net.TCPAddr{
|
||||||
IP: bindAddress.AsSlice(),
|
IP: bindAddress.AsSlice(),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if length == 0 {
|
if length > 512 {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
_buffer := buf.StackNewSize(int(length))
|
_buffer := buf.StackNewSize(int(length))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Version = "1.0-beta1"
|
Version = "1.0"
|
||||||
Commit = ""
|
Commit = ""
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,22 +1,4 @@
|
|||||||
#### 1.0-beta1
|
#### 2022/08/24
|
||||||
|
|
||||||
* Initial release
|
|
||||||
|
|
||||||
##### 2022/08/26
|
|
||||||
|
|
||||||
* Fix ipv6 route on linux
|
|
||||||
* Fix read DNS message
|
|
||||||
|
|
||||||
##### 2022/08/25
|
|
||||||
|
|
||||||
* Let vmess use zero instead of auto if TLS enabled
|
|
||||||
* Add trojan fallback for ALPN
|
|
||||||
* Improve ip_cidr rule
|
|
||||||
* Fix format bind_address
|
|
||||||
* Fix http proxy with compressed response
|
|
||||||
* Fix route connections
|
|
||||||
|
|
||||||
##### 2022/08/24
|
|
||||||
|
|
||||||
* Fix naive padding
|
* Fix naive padding
|
||||||
* Fix unix search path
|
* Fix unix search path
|
||||||
@@ -25,7 +7,7 @@
|
|||||||
* Fix early close on windows and catch any
|
* Fix early close on windows and catch any
|
||||||
* Initial zh-CN document translation
|
* Initial zh-CN document translation
|
||||||
|
|
||||||
##### 2022/08/23
|
#### 2022/08/23
|
||||||
|
|
||||||
* Add [V2Ray Transport](/configuration/shared/v2ray-transport) support for VMess and Trojan
|
* Add [V2Ray Transport](/configuration/shared/v2ray-transport) support for VMess and Trojan
|
||||||
* Allow plain http request in Naive inbound (It can now be used with nginx)
|
* Allow plain http request in Naive inbound (It can now be used with nginx)
|
||||||
@@ -34,17 +16,17 @@
|
|||||||
* Parse X-Forward-For in HTTP requests
|
* Parse X-Forward-For in HTTP requests
|
||||||
* Handle SIGHUP signal
|
* Handle SIGHUP signal
|
||||||
|
|
||||||
##### 2022/08/22
|
#### 2022/08/22
|
||||||
|
|
||||||
* Add strategy setting for each [DNS server](/configuration/dns/server)
|
* Add strategy setting for each [DNS server](/configuration/dns/server)
|
||||||
* Add bind address to outbound options
|
* Add bind address to outbound options
|
||||||
|
|
||||||
##### 2022/08/21
|
#### 2022/08/21
|
||||||
|
|
||||||
* Add [Tor outbound](/configuration/outbound/tor)
|
* Add [Tor outbound](/configuration/outbound/tor)
|
||||||
* Add [SSH outbound](/configuration/outbound/ssh)
|
* Add [SSH outbound](/configuration/outbound/ssh)
|
||||||
|
|
||||||
##### 2022/08/20
|
#### 2022/08/20
|
||||||
|
|
||||||
* Attempt to unwrap ip-in-fqdn socksaddr
|
* Attempt to unwrap ip-in-fqdn socksaddr
|
||||||
* Fix read packages in android 12
|
* Fix read packages in android 12
|
||||||
@@ -54,52 +36,52 @@
|
|||||||
* Skip bind connection with private destination to interface
|
* Skip bind connection with private destination to interface
|
||||||
* Add [Trojan connection fallback](/configuration/inbound/trojan#fallback)
|
* Add [Trojan connection fallback](/configuration/inbound/trojan#fallback)
|
||||||
|
|
||||||
##### 2022/08/19
|
#### 2022/08/19
|
||||||
|
|
||||||
* Add Hysteria [Inbound](/configuration/inbound/hysteria) and [Outbund](/configuration/outbound/hysteria)
|
* Add Hysteria [Inbound](/configuration/inbound/hysteria) and [Outbund](/configuration/outbound/hysteria)
|
||||||
* Add [ACME TLS certificate issuer](/configuration/shared/tls)
|
* Add [ACME TLS certificate issuer](/configuration/shared/tls)
|
||||||
* Allow read config from stdin (-c stdin)
|
* Allow read config from stdin (-c stdin)
|
||||||
* Update gVisor to 20220815.0
|
* Update gVisor to 20220815.0
|
||||||
|
|
||||||
##### 2022/08/18
|
#### 2022/08/18
|
||||||
|
|
||||||
* Fix find process with lwip stack
|
* Fix find process with lwip stack
|
||||||
* Fix crash on shadowsocks server
|
* Fix crash on shadowsocks server
|
||||||
* Fix crash on darwin tun
|
* Fix crash on darwin tun
|
||||||
* Fix write log to file
|
* Fix write log to file
|
||||||
|
|
||||||
##### 2022/08/17
|
#### 2022/08/17
|
||||||
|
|
||||||
* Improve async dns transports
|
* Improve async dns transports
|
||||||
|
|
||||||
##### 2022/08/16
|
#### 2022/08/16
|
||||||
|
|
||||||
* Add ip_version (route/dns) rule item
|
* Add ip_version (route/dns) rule item
|
||||||
* Add [WireGuard](/configuration/outbound/wireguard) outbound
|
* Add [WireGuard](/configuration/outbound/wireguard) outbound
|
||||||
|
|
||||||
##### 2022/08/15
|
#### 2022/08/15
|
||||||
|
|
||||||
* Add uid, android user and package rules support in [Tun](/configuration/inbound/tun) routing.
|
* Add uid, android user and package rules support in [Tun](/configuration/inbound/tun) routing.
|
||||||
|
|
||||||
##### 2022/08/13
|
#### 2022/08/13
|
||||||
|
|
||||||
* Fix dns concurrent write
|
* Fix dns concurrent write
|
||||||
|
|
||||||
##### 2022/08/12
|
#### 2022/08/12
|
||||||
|
|
||||||
* Performance improvements
|
* Performance improvements
|
||||||
* Add UoT option for [SOCKS](/configuration/outbound/socks) outbound
|
* Add UoT option for [SOCKS](/configuration/outbound/socks) outbound
|
||||||
|
|
||||||
##### 2022/08/11
|
#### 2022/08/11
|
||||||
|
|
||||||
* Add UoT option for [Shadowsocks](/configuration/outbound/shadowsocks) outbound, UoT support for all inbounds
|
* Add UoT option for [Shadowsocks](/configuration/outbound/shadowsocks) outbound, UoT support for all inbounds
|
||||||
|
|
||||||
##### 2022/08/10
|
#### 2022/08/10
|
||||||
|
|
||||||
* Add full-featured [Naive](/configuration/inbound/naive) inbound
|
* Add full-featured [Naive](/configuration/inbound/naive) inbound
|
||||||
* Fix default dns server option [#9] by iKirby
|
* Fix default dns server option [#9] by iKirby
|
||||||
|
|
||||||
##### 2022/08/09
|
#### 2022/08/09
|
||||||
|
|
||||||
No changelog before.
|
No changelog before.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# DNS
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -38,8 +38,7 @@
|
|||||||
"private"
|
"private"
|
||||||
],
|
],
|
||||||
"source_ip_cidr": [
|
"source_ip_cidr": [
|
||||||
"10.0.0.0/24",
|
"10.0.0.0/24"
|
||||||
"192.168.0.1"
|
|
||||||
],
|
],
|
||||||
"source_port": [
|
"source_port": [
|
||||||
12345
|
12345
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ DNS 服务器的地址。
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 QUIC 和 HTTP3 传输层,请参阅 [安装](/zh/#_2)。
|
默认安装不包含 QUIC 和 HTTP3 传输层,请参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
!!! info ""
|
!!! info ""
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Experimental
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
!!! error ""
|
!!! error ""
|
||||||
|
|
||||||
默认安装不包含 Clash API,参阅 [安装](/zh/#_2)。
|
默认安装不包含 Clash API,参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
!!! note ""
|
!!! note ""
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### Hysteria 字段
|
### Hysteria 字段
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Inbound
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 HTTP3 传输层, 参阅 [安装](/zh/#_2)。
|
默认安装不包含 HTTP3 传输层, 参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### Naive 字段
|
### Naive 字段
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,9 @@
|
|||||||
],
|
],
|
||||||
"tls": {},
|
"tls": {},
|
||||||
"fallback": {
|
"fallback": {
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.0.1",
|
||||||
"server_port": 8080
|
"server_port": 8080
|
||||||
},
|
},
|
||||||
"fallback_for_alpn": {
|
|
||||||
"http/1.1": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8081
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transport": {}
|
"transport": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -56,13 +50,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
|||||||
|
|
||||||
There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature.
|
There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature.
|
||||||
|
|
||||||
Fallback server configuration. Disabled if `fallback` and `fallback_for_alpn` are empty.
|
Fallback server configuration. Disabled if empty.
|
||||||
|
|
||||||
#### fallback_for_alpn
|
|
||||||
|
|
||||||
Fallback server configuration for specified ALPN.
|
|
||||||
|
|
||||||
If not empty, TLS fallback requests with ALPN not in this table will be rejected.
|
|
||||||
|
|
||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
{
|
{
|
||||||
"type": "trojan",
|
"type": "trojan",
|
||||||
"tag": "trojan-in",
|
"tag": "trojan-in",
|
||||||
|
|
||||||
"listen": "::",
|
"listen": "::",
|
||||||
"listen_port": 2080,
|
"listen_port": 2080,
|
||||||
"tcp_fast_open": false,
|
"tcp_fast_open": false,
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"sniff_override_destination": false,
|
"sniff_override_destination": false,
|
||||||
"domain_strategy": "prefer_ipv6",
|
"domain_strategy": "prefer_ipv6",
|
||||||
"proxy_protocol": false,
|
"proxy_protocol": false,
|
||||||
|
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"name": "sekai",
|
"name": "sekai",
|
||||||
@@ -21,15 +23,9 @@
|
|||||||
],
|
],
|
||||||
"tls": {},
|
"tls": {},
|
||||||
"fallback": {
|
"fallback": {
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.0.1",
|
||||||
"server_port": 8080
|
"server_port": 8080
|
||||||
},
|
},
|
||||||
"fallback_for_alpn": {
|
|
||||||
"http/1.1": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8081
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transport": {}
|
"transport": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -56,13 +52,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||||||
|
|
||||||
没有证据表明 GFW 基于 HTTP 响应检测并阻止木马服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。
|
没有证据表明 GFW 基于 HTTP 响应检测并阻止木马服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。
|
||||||
|
|
||||||
回退服务器配置。如果 `fallback` 和 `fallback_for_alpn` 为空,则禁用回退。
|
备用服务器配置。默认禁用。
|
||||||
|
|
||||||
#### fallback_for_alpn
|
|
||||||
|
|
||||||
为 ALPN 指定回退服务器配置。
|
|
||||||
|
|
||||||
如果不为空,ALPN 不在此列表中的 TLS 回退请求将被拒绝。
|
|
||||||
|
|
||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ TCP/IP 栈。
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 LWIP 栈,请参阅 [安装](/zh/#_2)。
|
默认安装不包含 LWIP 栈,请参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
#### include_uid
|
#### include_uid
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### Hysteria 字段
|
### Hysteria 字段
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Outbound
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
!!! info ""
|
!!! info ""
|
||||||
|
|
||||||
默认安装不包含嵌入式 Tor, 参阅 [安装](/zh/#_2)。
|
默认安装不包含嵌入式 Tor, 参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### Tor 字段
|
### Tor 字段
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 WireGuard, 参阅 [安装](/zh/#_2)。
|
默认安装不包含 WireGuard, 参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### WireGuard 字段
|
### WireGuard 字段
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Route
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -41,12 +41,10 @@
|
|||||||
"cn"
|
"cn"
|
||||||
],
|
],
|
||||||
"source_ip_cidr": [
|
"source_ip_cidr": [
|
||||||
"10.0.0.0/24",
|
"10.0.0.0/24"
|
||||||
"192.168.0.1"
|
|
||||||
],
|
],
|
||||||
"ip_cidr": [
|
"ip_cidr": [
|
||||||
"10.0.0.0/24",
|
"10.0.0.0/24"
|
||||||
"192.168.0.1"
|
|
||||||
],
|
],
|
||||||
"source_port": [
|
"source_port": [
|
||||||
12345
|
12345
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 ACME,参阅 [安装](/zh/#_2)。
|
默认安装不包含 ACME,参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
### 出站
|
### 出站
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,6 @@ It needs to be consistent with the server.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! warning ""
|
|
||||||
|
|
||||||
QUIC is not included by default, see [Installation](/#installation).
|
|
||||||
|
|
||||||
!!! warning "Difference from v2ray-core"
|
!!! warning "Difference from v2ray-core"
|
||||||
|
|
||||||
No additional encryption support:
|
No additional encryption support:
|
||||||
|
|||||||
@@ -107,10 +107,6 @@ HTTP 请求的额外标头。
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! warning ""
|
|
||||||
|
|
||||||
默认安装不包含 QUIC, 参阅 [安装](/zh/#_2)。
|
|
||||||
|
|
||||||
!!! warning "与 v2ray-core 的区别"
|
!!! warning "与 v2ray-core 的区别"
|
||||||
|
|
||||||
没有额外的加密支持:
|
没有额外的加密支持:
|
||||||
@@ -120,7 +116,7 @@ HTTP 请求的额外标头。
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
默认安装不包含 gRPC, 参阅 [安装](/zh/#_2)。
|
默认安装不包含 gRPC, 参阅 [安装](/zh/#installation)。
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
# Development environment
|
|
||||||
|
|
||||||
#### For the documentation
|
|
||||||
|
|
||||||
##### Setup
|
|
||||||
|
|
||||||
You need to configure python3 and pip first.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip install mkdocs-material mkdocs-static-i18n
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Run the site locally
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdocs serve
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```shell
|
|
||||||
python3 -m mkdocs serve
|
|
||||||
```
|
|
||||||
|
|
||||||
#### For the project
|
|
||||||
|
|
||||||
By default you have the latest Go installed (currently 1.19), and added `GOPATH/bin` to the PATH environment variable.
|
|
||||||
|
|
||||||
##### Setup
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make fmt_insall
|
|
||||||
make lint_install
|
|
||||||
```
|
|
||||||
|
|
||||||
This installs the formatting and lint tools, which can be used via `make fmt` and `make lint`.
|
|
||||||
|
|
||||||
For ProtoBuffer changes, you also need `make proto_install` and `make proto`.
|
|
||||||
|
|
||||||
##### Build binary to the project directory
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Install binary to GOPATH/bin
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make install
|
|
||||||
```
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Contributing to sing-box
|
|
||||||
|
|
||||||
An introduction to contributing to the sing-box project.
|
|
||||||
|
|
||||||
The sing-box project welcomes, and depends, on contributions from developers and users in the open source community.
|
|
||||||
Contributions can be made in a number of ways, a few examples are:
|
|
||||||
|
|
||||||
* Code patches via pull requests
|
|
||||||
* Documentation improvements
|
|
||||||
* Bug reports and patch reviews
|
|
||||||
|
|
||||||
### Reporting an Issue?
|
|
||||||
|
|
||||||
Please follow
|
|
||||||
the [issue template](https://github.com/SagerNet/sing-box/issues/new?assignees=&labels=&template=bug_report.yml) to
|
|
||||||
submit bugs. Always include **FULL** log content, especially if you don't understand the code that generates it.
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
The sing-box uses the following projects which also need to be maintained:
|
|
||||||
|
|
||||||
#### sing
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/sing)
|
|
||||||
|
|
||||||
As a base tool library, there are no dependencies other than `golang.org/x/sys`.
|
|
||||||
|
|
||||||
#### sing-dns
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/sing-dns)
|
|
||||||
|
|
||||||
Handles DNS lookups and caching.
|
|
||||||
|
|
||||||
#### sing-tun
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/sing-tun)
|
|
||||||
|
|
||||||
Handle Tun traffic forwarding, configure routing, monitor network and routing.
|
|
||||||
|
|
||||||
This library needs to periodically update its dependency gVisor (according to tags), including checking for changes to
|
|
||||||
the used parts of the code and updating its usage. If you are involved in maintenance, you also need to check that if it
|
|
||||||
works or contains memory leaks.
|
|
||||||
|
|
||||||
#### sing-shadowsocks
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/sing-shadowsocks)
|
|
||||||
|
|
||||||
Provides Shadowsocks client and server
|
|
||||||
|
|
||||||
#### sing-vmess
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/sing-vmess)
|
|
||||||
|
|
||||||
Provides VMess client and server
|
|
||||||
|
|
||||||
#### netlink
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/netlink)
|
|
||||||
|
|
||||||
Fork of `vishvananda/netlink`, with some rule fixes.
|
|
||||||
|
|
||||||
The library needs to be updated with the upstream.
|
|
||||||
|
|
||||||
#### quic-go
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/quic-go)
|
|
||||||
|
|
||||||
Fork of `lucas-clemente/quic-go` and `HyNetwork/quic-go`, contains quic flow control and other fixes used by Hysteria.
|
|
||||||
|
|
||||||
Since the author of Hysteria does not follow the upstream updates in time, and the provided fork needs to use replace,
|
|
||||||
we need to do this.
|
|
||||||
|
|
||||||
The library needs to be updated with the upstream.
|
|
||||||
|
|
||||||
#### certmagic
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/certmagic)
|
|
||||||
|
|
||||||
Fork of `caddyserver/certmagic`
|
|
||||||
|
|
||||||
Since upstream uses `miekg/dns` and we use `x/net/dnsmessage`, we need to replace its DNS part with our own
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
The library needs to be updated with the upstream.
|
|
||||||
|
|
||||||
#### smux
|
|
||||||
|
|
||||||
Link: [GitHub repository](https://github.com/SagerNet/smux)
|
|
||||||
|
|
||||||
Fork of `xtaci/smux`
|
|
||||||
|
|
||||||
Modify the code to support the writev it uses internally and unify the buffer pool, which prevents it from allocating
|
|
||||||
64k buffers for per connection and improves performance.
|
|
||||||
|
|
||||||
Upstream doesn't seem to be updated anymore, maybe a replacement is needed.
|
|
||||||
|
|
||||||
Note: while yamux is still actively maintained and better known, it seems to be less performant.
|
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
| Feature | clash-premium |
|
| Feature | clash-premium |
|
||||||
|-------------------------------------------|---------------|
|
|-------------------------------------------|---------------|
|
||||||
| Full IPv6 support | X |
|
| Full IPv6 support | X |
|
||||||
| Auto route on Linux/Windows/macOS/Android | ✔ |
|
| Auto route on Linux/Windows/maxOS/Android | ✔ |
|
||||||
| Embed windows driver | X |
|
| Embed windows driver | X |
|
||||||
| Custom address/mtu | X |
|
| Custom address/mtu | X |
|
||||||
| Limit uid (Linux) in routing | X |
|
| Limit uid (Linux) in routing | X |
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
description: Welcome to the wiki page for the sing-box project.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Home
|
# Home
|
||||||
|
|
||||||
Welcome to the wiki page for the sing-box project.
|
Welcome to the wiki page for the sing-box project.
|
||||||
@@ -22,16 +18,16 @@ Install with options:
|
|||||||
go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@latest
|
go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
| Build Tag | Description |
|
| Build Tag | Description |
|
||||||
|------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `with_quic` | Build with QUIC support, see [QUIC and HTTP3 dns transports](./configuration/dns/server), [Naive inbound](./configuration/inbound/naive), [Hysteria Inbound](./configuration/inbound/hysteria), [Hysteria Outbound](./configuration/outbound/hysteria) and [V2Ray Transport#QUIC](./configuration/shared/v2ray-transport#quic). |
|
| `with_quic` | Build with QUIC support, see [QUIC and HTTP3 dns transports](./configuration/dns/server), [Naive inbound](./configuration/inbound/naive), [Hysteria Inbound](./configuration/inbound/hysteria) and [Hysteria Outbound](./configuration/outbound/hysteria). |
|
||||||
| `with_grpc` | Build with gRPC support, see [V2Ray Transport#gRPC](./configuration/shared/v2ray-transport#grpc). |
|
| `with_grpc` | Build with gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
|
||||||
| `with_wireguard` | Build with WireGuard support, see [WireGuard outbound](./configuration/outbound/wireguard). |
|
| `with_wireguard` | Build with WireGuard support, see [WireGuard outbound](./configuration/outbound/wireguard). |
|
||||||
| `with_acme` | Build with ACME TLS certificate issuer support, see [TLS](./configuration/shared/tls). |
|
| `with_acme` | Build with ACME TLS certificate issuer support, see [TLS](./configuration/shared/tls). |
|
||||||
| `with_clash_api` | Build with Clash API support, see [Experimental](./configuration/experimental#clash-api-fields). |
|
| `with_clash_api` | Build with Clash API support, see [Experimental](./configuration/experimental#clash-api-fields). |
|
||||||
| `no_gvisor` | Build without gVisor Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). |
|
| `no_gvisor` | Build without gVisor Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). |
|
||||||
| `with_embedded_tor` (CGO required) | Build with embedded Tor support, see [Tor outbound](./configuration/outbound/tor). |
|
| `with_embedded_tor` (CGO required) | Build with embedded Tor support, see [Tor outbound](./configuration/outbound/tor). |
|
||||||
| `with_lwip` (CGO required) | Build with LWIP Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). |
|
| `with_lwip` (CGO required) | Build with LWIP Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). |
|
||||||
|
|
||||||
The binary is built under $GOPATH/bin
|
The binary is built under $GOPATH/bin
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
description: 欢迎来到该 sing-box 项目的文档页。
|
|
||||||
---
|
|
||||||
|
|
||||||
# 开始
|
# 开始
|
||||||
|
|
||||||
欢迎来到该 sing-box 项目的文档页。
|
欢迎来到该 sing-box 项目的文档页。
|
||||||
@@ -22,16 +18,16 @@ go install -v github.com/sagernet/sing-box/cmd/sing-box@latest
|
|||||||
go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@latest
|
go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
| 构建标志 | 描述 |
|
| 构建标志 | 描述 |
|
||||||
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server),[Naive 入站](./configuration/inbound/naive),[Hysteria 入站](./configuration/inbound/hysteria),[Hysteria 出站](./configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](./configuration/shared/v2ray-transport#quic)。 |
|
| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server),[Naive 入站](./configuration/inbound/naive),[Hysteria 入站](./configuration/inbound/hysteria) 和 [Hysteria 出站](./configuration/outbound/hysteria)。 |
|
||||||
| `with_grpc` | 启用 gRPC 支持,参阅 [V2Ray 传输层#gRPC](./configuration/shared/v2ray-transport#grpc)。 |
|
| `with_grpc` | 启用 gRPC 支持,参阅 [V2Ray 传输层#gRPC](/configuration/shared/v2ray-transport#grpc)。 |
|
||||||
| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](./configuration/outbound/wireguard)。 |
|
| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](./configuration/outbound/wireguard)。 |
|
||||||
| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 |
|
| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 |
|
||||||
| `with_clash_api` | 启用 Clash api 支持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
|
| `with_clash_api` | 启用 Clash api 支持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
|
||||||
| `no_gvisor` | 禁用 gVisor Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
| `no_gvisor` | 禁用 gVisor Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
||||||
| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 |
|
| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 |
|
||||||
| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
||||||
|
|
||||||
二进制文件将被构建在 `$GOPATH/bin` 下。
|
二进制文件将被构建在 `$GOPATH/bin` 下。
|
||||||
|
|
||||||
|
|||||||
165
experimental/daemon/daemon.go
Executable file
165
experimental/daemon/daemon.go
Executable file
@@ -0,0 +1,165 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
|
||||||
|
"github.com/kardianos/service"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultDaemonName = "sing-box-daemon"
|
||||||
|
DefaultDaemonPort = 9091
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultDaemonOptions = Options{
|
||||||
|
Listen: "127.0.0.1",
|
||||||
|
ListenPort: DefaultDaemonPort,
|
||||||
|
WorkingDirectory: workingDirectory(),
|
||||||
|
}
|
||||||
|
|
||||||
|
func workingDirectory() string {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
return filepath.Join("/usr/local/lib", DefaultDaemonName)
|
||||||
|
default:
|
||||||
|
configDir, err := os.UserConfigDir()
|
||||||
|
if err == nil {
|
||||||
|
return filepath.Join(configDir, DefaultDaemonName)
|
||||||
|
} else {
|
||||||
|
return DefaultDaemonName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemdScript = `[Unit]
|
||||||
|
Description=sing-box service
|
||||||
|
Documentation=https://sing-box.sagernet.org
|
||||||
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=root
|
||||||
|
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
||||||
|
WorkingDirectory={{.WorkingDirectory|cmdEscape}}
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
LimitNOFILE=infinity
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target`
|
||||||
|
|
||||||
|
type Daemon struct {
|
||||||
|
service service.Service
|
||||||
|
workingDirectory string
|
||||||
|
executable string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() (*Daemon, error) {
|
||||||
|
daemonInterface := NewInterface(defaultDaemonOptions)
|
||||||
|
executable := filepath.Join(defaultDaemonOptions.WorkingDirectory, "sing-box")
|
||||||
|
if C.IsWindows {
|
||||||
|
executable += ".exe"
|
||||||
|
}
|
||||||
|
daemonService, err := service.New(daemonInterface, &service.Config{
|
||||||
|
Name: DefaultDaemonName,
|
||||||
|
Description: "The universal proxy platform.",
|
||||||
|
Arguments: []string{"daemon", "run"},
|
||||||
|
Executable: executable,
|
||||||
|
Option: service.KeyValue{
|
||||||
|
"SystemdScript": systemdScript,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.New(strings.ToLower(err.Error()))
|
||||||
|
}
|
||||||
|
return &Daemon{
|
||||||
|
service: daemonService,
|
||||||
|
workingDirectory: defaultDaemonOptions.WorkingDirectory,
|
||||||
|
executable: executable,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Install() error {
|
||||||
|
_, err := d.service.Status()
|
||||||
|
if err != service.ErrNotInstalled {
|
||||||
|
d.service.Stop()
|
||||||
|
err = d.service.Uninstall()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executablePath, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !rw.FileExists(d.workingDirectory) {
|
||||||
|
err = os.MkdirAll(d.workingDirectory, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputFile, err := os.OpenFile(d.executable, os.O_CREATE|os.O_WRONLY, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
inputFile, err := os.Open(executablePath)
|
||||||
|
if err != nil {
|
||||||
|
outputFile.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(outputFile, inputFile)
|
||||||
|
inputFile.Close()
|
||||||
|
outputFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = d.service.Install()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return d.service.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Uninstall() error {
|
||||||
|
_, err := d.service.Status()
|
||||||
|
if err != service.ErrNotInstalled {
|
||||||
|
d.service.Stop()
|
||||||
|
err = d.service.Uninstall()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.RemoveAll(d.workingDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Run() error {
|
||||||
|
d.chdir()
|
||||||
|
return d.service.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) chdir() error {
|
||||||
|
executable, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.Chdir(filepath.Dir(executable))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Start() error {
|
||||||
|
return d.service.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Stop() error {
|
||||||
|
return d.service.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Daemon) Restart() error {
|
||||||
|
return d.service.Restart()
|
||||||
|
}
|
||||||
58
experimental/daemon/instance.go
Normal file
58
experimental/daemon/instance.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Instance struct {
|
||||||
|
access sync.Mutex
|
||||||
|
boxInstance *box.Box
|
||||||
|
boxCancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) Running() bool {
|
||||||
|
i.access.Lock()
|
||||||
|
defer i.access.Unlock()
|
||||||
|
return i.boxInstance != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) Start(options option.Options) error {
|
||||||
|
i.access.Lock()
|
||||||
|
defer i.access.Unlock()
|
||||||
|
if i.boxInstance != nil {
|
||||||
|
i.boxCancel()
|
||||||
|
i.boxInstance.Close()
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
instance, err := box.New(ctx, options)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = instance.Start()
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.boxInstance = instance
|
||||||
|
i.boxCancel = cancel
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) Close() error {
|
||||||
|
i.access.Lock()
|
||||||
|
defer i.access.Unlock()
|
||||||
|
if i.boxInstance == nil {
|
||||||
|
return os.ErrClosed
|
||||||
|
}
|
||||||
|
i.boxCancel()
|
||||||
|
err := i.boxInstance.Close()
|
||||||
|
i.boxInstance = nil
|
||||||
|
i.boxCancel = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
20
experimental/daemon/interface.go
Normal file
20
experimental/daemon/interface.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import "github.com/kardianos/service"
|
||||||
|
|
||||||
|
type Interface struct {
|
||||||
|
server *Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInterface(options Options) *Interface {
|
||||||
|
return &Interface{NewServer(options)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Interface) Start(_ service.Service) error {
|
||||||
|
return d.server.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Interface) Stop(_ service.Service) error {
|
||||||
|
d.server.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
147
experimental/daemon/server.go
Normal file
147
experimental/daemon/server.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/json"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/cors"
|
||||||
|
"github.com/go-chi/render"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Listen string `json:"listen"`
|
||||||
|
ListenPort uint16 `json:"listen_port"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
WorkingDirectory string `json:"working_directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
options Options
|
||||||
|
httpServer *http.Server
|
||||||
|
instance Instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(options Options) *Server {
|
||||||
|
return &Server{
|
||||||
|
options: options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() error {
|
||||||
|
tcpConn, err := net.Listen("tcp", net.JoinHostPort(s.options.Listen, F.ToString(s.options.ListenPort)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
router := chi.NewRouter()
|
||||||
|
router.Use(cors.New(cors.Options{
|
||||||
|
AllowedOrigins: []string{"*"},
|
||||||
|
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
|
||||||
|
AllowedHeaders: []string{"Content-Type", "Authorization"},
|
||||||
|
MaxAge: 300,
|
||||||
|
}).Handler)
|
||||||
|
if s.options.Secret != "" {
|
||||||
|
router.Use(s.authentication)
|
||||||
|
}
|
||||||
|
router.Get("/ping", s.ping)
|
||||||
|
router.Get("/status", s.status)
|
||||||
|
router.Post("/run", s.run)
|
||||||
|
router.Get("/stop", s.stop)
|
||||||
|
router.Route("/debug/pprof", func(r chi.Router) {
|
||||||
|
r.HandleFunc("/", pprof.Index)
|
||||||
|
r.HandleFunc("/cmdline", pprof.Cmdline)
|
||||||
|
r.HandleFunc("/profile", pprof.Profile)
|
||||||
|
r.HandleFunc("/symbol", pprof.Symbol)
|
||||||
|
r.HandleFunc("/trace", pprof.Trace)
|
||||||
|
})
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Handler: router,
|
||||||
|
}
|
||||||
|
go httpServer.Serve(tcpConn)
|
||||||
|
s.httpServer = httpServer
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) authentication(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
if websocket.IsWebSocketUpgrade(request) && request.URL.Query().Get("token") != "" {
|
||||||
|
token := request.URL.Query().Get("token")
|
||||||
|
if token != s.options.Secret {
|
||||||
|
render.Status(request, http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(writer, request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header := request.Header.Get("Authorization")
|
||||||
|
bearer, token, found := strings.Cut(header, " ")
|
||||||
|
hasInvalidHeader := bearer != "Bearer"
|
||||||
|
hasInvalidSecret := !found || token != s.options.Secret
|
||||||
|
if hasInvalidHeader || hasInvalidSecret {
|
||||||
|
render.Status(request, http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(writer, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Close() error {
|
||||||
|
return common.Close(
|
||||||
|
common.PtrOrNil(s.httpServer),
|
||||||
|
&s.instance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ping(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
render.PlainText(writer, request, "pong")
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatusResponse struct {
|
||||||
|
Running bool `json:"running"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) status(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
render.JSON(writer, request, StatusResponse{
|
||||||
|
Running: s.instance.Running(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) run(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
err := s.run0(request)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn(err)
|
||||||
|
render.Status(request, http.StatusBadRequest)
|
||||||
|
render.PlainText(writer, request, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writer.WriteHeader(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) run0(request *http.Request) error {
|
||||||
|
configContent, err := io.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read config")
|
||||||
|
}
|
||||||
|
var options option.Options
|
||||||
|
err = json.Unmarshal(configContent, &options)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "decode config")
|
||||||
|
}
|
||||||
|
return s.instance.Start(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) stop(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
s.instance.Close()
|
||||||
|
writer.WriteHeader(http.StatusNoContent)
|
||||||
|
}
|
||||||
11
go.mod
11
go.mod
@@ -14,6 +14,7 @@ require (
|
|||||||
github.com/gofrs/uuid v4.2.0+incompatible
|
github.com/gofrs/uuid v4.2.0+incompatible
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/hashicorp/yamux v0.1.1
|
github.com/hashicorp/yamux v0.1.1
|
||||||
|
github.com/kardianos/service v1.2.1
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
github.com/mholt/acmez v1.0.4
|
github.com/mholt/acmez v1.0.4
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0
|
github.com/oschwald/maxminddb-golang v1.10.0
|
||||||
@@ -21,16 +22,15 @@ require (
|
|||||||
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a
|
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a
|
||||||
github.com/sagernet/netlink v0.0.0-20220820041223-3cd8365d17ac
|
github.com/sagernet/netlink v0.0.0-20220820041223-3cd8365d17ac
|
||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
|
||||||
github.com/sagernet/sing v0.0.0-20220825093630-185d87918290
|
github.com/sagernet/sing v0.0.0-20220824062950-7bfd820739a8
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666
|
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220826042514-409136e64474
|
github.com/sagernet/sing-tun v0.0.0-20220824105617-e5c59fc756a6
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4
|
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4
|
||||||
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939
|
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.5.0
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
go.uber.org/atomic v1.10.0
|
go.uber.org/atomic v1.10.0
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d
|
|
||||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
|
||||||
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
|
golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c
|
||||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6
|
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6
|
||||||
@@ -63,10 +63,11 @@ require (
|
|||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.22.0 // indirect
|
go.uber.org/zap v1.22.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
|||||||
22
go.sum
22
go.sum
@@ -88,6 +88,8 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg
|
|||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/kardianos/service v1.2.1 h1:AYndMsehS+ywIS6RB9KOlcXzteWUzxgMgBymJD7+BYk=
|
||||||
|
github.com/kardianos/service v1.2.1/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||||
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
@@ -142,14 +144,14 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
|
|||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
||||||
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220825093630-185d87918290 h1:OAt6dFNrGOpgaPgM3uvAdQE0NkGC7AAygqpo8MwryY8=
|
github.com/sagernet/sing v0.0.0-20220824062950-7bfd820739a8 h1:kHsinrGrMjEh5KUXC/MPCS+Uy3Z3XO/cMhC8xJtABE8=
|
||||||
github.com/sagernet/sing v0.0.0-20220825093630-185d87918290/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
|
github.com/sagernet/sing v0.0.0-20220824062950-7bfd820739a8/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY=
|
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM=
|
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220826042514-409136e64474 h1:dy9dLOSTDtig/s5se7cRqIypUlqtcp4+Zw0+XMpORPE=
|
github.com/sagernet/sing-tun v0.0.0-20220824105617-e5c59fc756a6 h1:C0uNMDrjYribl4Pu41Au9UeQROIOeMWaDd7eSUIQ9gQ=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220826042514-409136e64474/go.mod h1:zMKRFCEoO6Jp5Yxb2NUTqc+SvAtNVAmzfwArAheJy5g=
|
github.com/sagernet/sing-tun v0.0.0-20220824105617-e5c59fc756a6/go.mod h1:zMKRFCEoO6Jp5Yxb2NUTqc+SvAtNVAmzfwArAheJy5g=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4 h1:2hLETh97+S4WnfMR27XyC7QVU1SH7FTNoCznP229YJU=
|
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4 h1:2hLETh97+S4WnfMR27XyC7QVU1SH7FTNoCznP229YJU=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps=
|
github.com/sagernet/sing-vmess v0.0.0-20220811135656-4f3f07acf9c4/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps=
|
||||||
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 h1:pB1Dh1NbwVrLhQhotr4O4Hs3yhiBzmg3AvnUyYjL4x4=
|
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 h1:pB1Dh1NbwVrLhQhotr4O4Hs3yhiBzmg3AvnUyYjL4x4=
|
||||||
@@ -181,8 +183,6 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
|
|||||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
||||||
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d h1:ggxwEf5eu0l8v+87VhX1czFh8zJul3hK16Gmruxn7hw=
|
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
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=
|
||||||
@@ -201,8 +201,8 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI
|
|||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
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=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -241,6 +241,7 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -276,11 +277,12 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
|||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=
|
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||||
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ func (a *myInboundAdapter) createMetadata(conn net.Conn, metadata adapter.Inboun
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
|
metadata.Network = N.NetworkTCP
|
||||||
if !metadata.Source.IsValid() {
|
if !metadata.Source.IsValid() {
|
||||||
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
|
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
|
||||||
}
|
}
|
||||||
@@ -241,6 +242,7 @@ func (a *myInboundAdapter) loopUDPIn() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr)
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
||||||
@@ -273,6 +275,7 @@ func (a *myInboundAdapter) loopUDPOOBIn() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr)
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
||||||
@@ -299,6 +302,7 @@ func (a *myInboundAdapter) loopUDPInThreadSafe() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr)
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
||||||
@@ -327,6 +331,7 @@ func (a *myInboundAdapter) loopUDPOOBInThreadSafe() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr)
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
|
|||||||
metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port)
|
metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port)
|
||||||
if !request.UDP {
|
if !request.UDP {
|
||||||
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||||
|
metadata.Network = N.NetworkTCP
|
||||||
return h.router.RouteConnection(ctx, hysteria.NewConn(stream, metadata.Destination), metadata)
|
return h.router.RouteConnection(ctx, hysteria.NewConn(stream, metadata.Destination), metadata)
|
||||||
} else {
|
} else {
|
||||||
h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
|
h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
|
||||||
@@ -277,6 +278,7 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
|
|||||||
h.udpSessions[id] = nCh
|
h.udpSessions[id] = nCh
|
||||||
h.udpSessionId += 1
|
h.udpSessionId += 1
|
||||||
h.udpAccess.Unlock()
|
h.udpAccess.Unlock()
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
packetConn := hysteria.NewPacketConn(conn, stream, id, metadata.Destination, nCh, common.Closer(func() error {
|
packetConn := hysteria.NewPacketConn(conn, stream, id, metadata.Destination, nCh, common.Closer(func() error {
|
||||||
h.udpAccess.Lock()
|
h.udpAccess.Lock()
|
||||||
if ch, ok := h.udpSessions[id]; ok {
|
if ch, ok := h.udpSessions[id]; ok {
|
||||||
|
|||||||
@@ -24,12 +24,11 @@ var _ adapter.Inbound = (*Trojan)(nil)
|
|||||||
|
|
||||||
type Trojan struct {
|
type Trojan struct {
|
||||||
myInboundAdapter
|
myInboundAdapter
|
||||||
service *trojan.Service[int]
|
service *trojan.Service[int]
|
||||||
users []option.TrojanUser
|
users []option.TrojanUser
|
||||||
tlsConfig *TLSConfig
|
tlsConfig *TLSConfig
|
||||||
fallbackAddr M.Socksaddr
|
fallbackAddr M.Socksaddr
|
||||||
fallbackAddrTLSNextProto map[string]M.Socksaddr
|
transport adapter.V2RayServerTransport
|
||||||
transport adapter.V2RayServerTransport
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanInboundOptions) (*Trojan, error) {
|
func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanInboundOptions) (*Trojan, error) {
|
||||||
@@ -45,35 +44,9 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
|
|||||||
},
|
},
|
||||||
users: options.Users,
|
users: options.Users,
|
||||||
}
|
}
|
||||||
if options.TLS != nil {
|
|
||||||
tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
inbound.tlsConfig = tlsConfig
|
|
||||||
}
|
|
||||||
var fallbackHandler N.TCPConnectionHandler
|
var fallbackHandler N.TCPConnectionHandler
|
||||||
if options.Fallback != nil && options.Fallback.Server != "" || len(options.FallbackForALPN) > 0 {
|
if options.Fallback != nil && options.Fallback.Server != "" {
|
||||||
if options.Fallback != nil && options.Fallback.Server != "" {
|
inbound.fallbackAddr = options.Fallback.Build()
|
||||||
inbound.fallbackAddr = options.Fallback.Build()
|
|
||||||
if !inbound.fallbackAddr.IsValid() {
|
|
||||||
return nil, E.New("invalid fallback address: ", inbound.fallbackAddr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(options.FallbackForALPN) > 0 {
|
|
||||||
if inbound.tlsConfig == nil {
|
|
||||||
return nil, E.New("fallback for ALPN is not supported without TLS")
|
|
||||||
}
|
|
||||||
fallbackAddrNextProto := make(map[string]M.Socksaddr)
|
|
||||||
for nextProto, destination := range options.FallbackForALPN {
|
|
||||||
fallbackAddr := destination.Build()
|
|
||||||
if !fallbackAddr.IsValid() {
|
|
||||||
return nil, E.New("invalid fallback address for ALPN ", nextProto, ": ", fallbackAddr)
|
|
||||||
}
|
|
||||||
fallbackAddrNextProto[nextProto] = fallbackAddr
|
|
||||||
}
|
|
||||||
inbound.fallbackAddrTLSNextProto = fallbackAddrNextProto
|
|
||||||
}
|
|
||||||
fallbackHandler = adapter.NewUpstreamContextHandler(inbound.fallbackConnection, nil, nil)
|
fallbackHandler = adapter.NewUpstreamContextHandler(inbound.fallbackConnection, nil, nil)
|
||||||
}
|
}
|
||||||
service := trojan.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), fallbackHandler)
|
service := trojan.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), fallbackHandler)
|
||||||
@@ -85,6 +58,13 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if options.TLS != nil {
|
||||||
|
tlsConfig, err := NewTLSConfig(ctx, logger, common.PtrValueOrDefault(options.TLS))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inbound.tlsConfig = tlsConfig
|
||||||
|
}
|
||||||
if options.Transport != nil {
|
if options.Transport != nil {
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if inbound.tlsConfig != nil {
|
if inbound.tlsConfig != nil {
|
||||||
@@ -173,22 +153,8 @@ func (h *Trojan) newConnection(ctx context.Context, conn net.Conn, metadata adap
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Trojan) fallbackConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (h *Trojan) fallbackConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
var fallbackAddr M.Socksaddr
|
h.logger.InfoContext(ctx, "fallback connection to ", h.fallbackAddr)
|
||||||
if len(h.fallbackAddrTLSNextProto) > 0 {
|
metadata.Destination = h.fallbackAddr
|
||||||
if tlsConn, loaded := common.Cast[*tls.Conn](conn); loaded {
|
|
||||||
connectionState := tlsConn.ConnectionState()
|
|
||||||
if connectionState.NegotiatedProtocol != "" {
|
|
||||||
if fallbackAddr, loaded = h.fallbackAddrTLSNextProto[connectionState.NegotiatedProtocol]; !loaded {
|
|
||||||
return E.New("fallback disabled for ALPN: ", connectionState.NegotiatedProtocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !fallbackAddr.IsValid() {
|
|
||||||
fallbackAddr = h.fallbackAddr
|
|
||||||
}
|
|
||||||
h.logger.InfoContext(ctx, "fallback connection to ", fallbackAddr)
|
|
||||||
metadata.Destination = fallbackAddr
|
|
||||||
return h.router.RouteConnection(ctx, conn, metadata)
|
return h.router.RouteConnection(ctx, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata
|
|||||||
var metadata adapter.InboundContext
|
var metadata adapter.InboundContext
|
||||||
metadata.Inbound = t.tag
|
metadata.Inbound = t.tag
|
||||||
metadata.InboundType = C.TypeTun
|
metadata.InboundType = C.TypeTun
|
||||||
|
metadata.Network = N.NetworkTCP
|
||||||
metadata.Source = upstreamMetadata.Source
|
metadata.Source = upstreamMetadata.Source
|
||||||
metadata.Destination = upstreamMetadata.Destination
|
metadata.Destination = upstreamMetadata.Destination
|
||||||
metadata.SniffEnabled = t.inboundOptions.SniffEnabled
|
metadata.SniffEnabled = t.inboundOptions.SniffEnabled
|
||||||
@@ -187,6 +188,7 @@ func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstre
|
|||||||
var metadata adapter.InboundContext
|
var metadata adapter.InboundContext
|
||||||
metadata.Inbound = t.tag
|
metadata.Inbound = t.tag
|
||||||
metadata.InboundType = C.TypeTun
|
metadata.InboundType = C.TypeTun
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Source = upstreamMetadata.Source
|
metadata.Source = upstreamMetadata.Source
|
||||||
metadata.Destination = upstreamMetadata.Destination
|
metadata.Destination = upstreamMetadata.Destination
|
||||||
metadata.SniffEnabled = t.inboundOptions.SniffEnabled
|
metadata.SniffEnabled = t.inboundOptions.SniffEnabled
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ nav:
|
|||||||
- Route Rule: configuration/route/rule.md
|
- Route Rule: configuration/route/rule.md
|
||||||
- Protocol Sniff: configuration/route/sniff.md
|
- Protocol Sniff: configuration/route/sniff.md
|
||||||
- Experimental:
|
- Experimental:
|
||||||
- configuration/experimental/index.md
|
- configuration/experimental/index.md
|
||||||
- Shared:
|
- Shared:
|
||||||
- TLS: configuration/shared/tls.md
|
- TLS: configuration/shared/tls.md
|
||||||
- Multiplex: configuration/shared/multiplex.md
|
- Multiplex: configuration/shared/multiplex.md
|
||||||
@@ -93,11 +93,6 @@ nav:
|
|||||||
- Shadowsocks Client: examples/ss-client.md
|
- Shadowsocks Client: examples/ss-client.md
|
||||||
- Shadowsocks Tun: examples/ss-tun.md
|
- Shadowsocks Tun: examples/ss-tun.md
|
||||||
- DNS Hijack: examples/dns-hijack.md
|
- DNS Hijack: examples/dns-hijack.md
|
||||||
- Contributing:
|
|
||||||
- contributing/index.md
|
|
||||||
- Developing:
|
|
||||||
- Environment: contributing/environment.md
|
|
||||||
- Sub projects: contributing/sub-projects.md
|
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- pymdownx.inlinehilite
|
- pymdownx.inlinehilite
|
||||||
- pymdownx.snippets
|
- pymdownx.snippets
|
||||||
|
|||||||
@@ -100,14 +100,14 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DialerOptions struct {
|
type DialerOptions struct {
|
||||||
Detour string `json:"detour,omitempty"`
|
Detour string `json:"detour,omitempty"`
|
||||||
BindInterface string `json:"bind_interface,omitempty"`
|
BindInterface string `json:"bind_interface,omitempty"`
|
||||||
BindAddress *ListenAddress `json:"bind_address,omitempty"`
|
BindAddress ListenAddress `json:"bind_address,omitempty"`
|
||||||
ProtectPath string `json:"protect_path,omitempty"`
|
ProtectPath string `json:"protect_path,omitempty"`
|
||||||
RoutingMark int `json:"routing_mark,omitempty"`
|
RoutingMark int `json:"routing_mark,omitempty"`
|
||||||
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
||||||
ConnectTimeout Duration `json:"connect_timeout,omitempty"`
|
ConnectTimeout Duration `json:"connect_timeout,omitempty"`
|
||||||
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundDialerOptions struct {
|
type OutboundDialerOptions struct {
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package option
|
|||||||
|
|
||||||
type TrojanInboundOptions struct {
|
type TrojanInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
Users []TrojanUser `json:"users,omitempty"`
|
Users []TrojanUser `json:"users,omitempty"`
|
||||||
TLS *InboundTLSOptions `json:"tls,omitempty"`
|
TLS *InboundTLSOptions `json:"tls,omitempty"`
|
||||||
Fallback *ServerOptions `json:"fallback,omitempty"`
|
Fallback *ServerOptions `json:"fallback,omitempty"`
|
||||||
FallbackForALPN map[string]*ServerOptions `json:"fallback_for_alpn,omitempty"`
|
Transport *V2RayTransportOptions `json:"transport,omitempty"`
|
||||||
Transport *V2RayTransportOptions `json:"transport,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrojanUser struct {
|
type TrojanUser struct {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type ListenAddress netip.Addr
|
|||||||
func (a ListenAddress) MarshalJSON() ([]byte, error) {
|
func (a ListenAddress) MarshalJSON() ([]byte, error) {
|
||||||
addr := netip.Addr(a)
|
addr := netip.Addr(a)
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
return nil, nil
|
return json.Marshal("")
|
||||||
}
|
}
|
||||||
return json.Marshal(addr.String())
|
return json.Marshal(addr.String())
|
||||||
}
|
}
|
||||||
@@ -35,10 +35,6 @@ func (a *ListenAddress) UnmarshalJSON(content []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a ListenAddress) Build() netip.Addr {
|
|
||||||
return (netip.Addr)(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NetworkList string
|
type NetworkList string
|
||||||
|
|
||||||
func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/canceler"
|
"github.com/sagernet/sing-box/common/canceler"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-dns"
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
@@ -47,60 +47,53 @@ func (d *DNS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.Pa
|
|||||||
func (d *DNS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (d *DNS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
for {
|
_buffer := buf.StackNewSize(1024)
|
||||||
err := d.handleConnection(ctx, conn, metadata)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
|
||||||
var queryLength uint16
|
|
||||||
err := binary.Read(conn, binary.BigEndian, &queryLength)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if queryLength == 0 {
|
|
||||||
return dns.RCodeFormatError
|
|
||||||
}
|
|
||||||
_buffer := buf.StackNewSize(int(queryLength))
|
|
||||||
defer common.KeepAlive(_buffer)
|
defer common.KeepAlive(_buffer)
|
||||||
buffer := common.Dup(_buffer)
|
buffer := common.Dup(_buffer)
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
_, err = buffer.ReadFullFrom(conn, int(queryLength))
|
for {
|
||||||
if err != nil {
|
var queryLength uint16
|
||||||
return err
|
err := binary.Read(conn, binary.BigEndian, &queryLength)
|
||||||
}
|
|
||||||
var message dnsmessage.Message
|
|
||||||
err = message.Unpack(buffer.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(message.Questions) > 0 {
|
|
||||||
question := message.Questions[0]
|
|
||||||
metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
|
|
||||||
}
|
|
||||||
go func() error {
|
|
||||||
response, err := d.router.Exchange(ctx, &message)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_responseBuffer := buf.StackNewPacket()
|
if queryLength > 1024 {
|
||||||
defer common.KeepAlive(_responseBuffer)
|
return io.ErrShortBuffer
|
||||||
responseBuffer := common.Dup(_responseBuffer)
|
}
|
||||||
defer responseBuffer.Release()
|
buffer.FullReset()
|
||||||
responseBuffer.Resize(2, 0)
|
_, err = buffer.ReadFullFrom(conn, int(queryLength))
|
||||||
n, err := response.AppendPack(responseBuffer.Index(0))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
responseBuffer.Truncate(len(n))
|
var message dnsmessage.Message
|
||||||
binary.BigEndian.PutUint16(responseBuffer.ExtendHeader(2), uint16(len(n)))
|
err = message.Unpack(buffer.Bytes())
|
||||||
_, err = conn.Write(responseBuffer.Bytes())
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}()
|
}
|
||||||
return nil
|
if len(message.Questions) > 0 {
|
||||||
|
question := message.Questions[0]
|
||||||
|
metadata.Domain = string(question.Name.Data[:question.Name.Length-1])
|
||||||
|
}
|
||||||
|
go func() error {
|
||||||
|
response, err := d.router.Exchange(ctx, &message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_responseBuffer := buf.StackNewPacket()
|
||||||
|
defer common.KeepAlive(_responseBuffer)
|
||||||
|
responseBuffer := common.Dup(_responseBuffer)
|
||||||
|
defer responseBuffer.Release()
|
||||||
|
responseBuffer.Resize(2, 0)
|
||||||
|
n, err := response.AppendPack(responseBuffer.Index(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
responseBuffer.Truncate(len(n))
|
||||||
|
binary.BigEndian.PutUint16(responseBuffer.ExtendHeader(2), uint16(len(n)))
|
||||||
|
_, err = conn.Write(responseBuffer.Bytes())
|
||||||
|
return err
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
@@ -110,7 +103,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(ctx context.Context) error {
|
group.Append0(func(ctx context.Context) error {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
_buffer := buf.StackNewSize(dns.FixedPacketSize)
|
_buffer := buf.StackNewSize(1024)
|
||||||
defer common.KeepAlive(_buffer)
|
defer common.KeepAlive(_buffer)
|
||||||
buffer := common.Dup(_buffer)
|
buffer := common.Dup(_buffer)
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|||||||
@@ -32,6 +32,17 @@ type VMess struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (*VMess, error) {
|
func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (*VMess, error) {
|
||||||
|
var clientOptions []vmess.ClientOption
|
||||||
|
if options.GlobalPadding {
|
||||||
|
clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding())
|
||||||
|
}
|
||||||
|
if options.AuthenticatedLength {
|
||||||
|
clientOptions = append(clientOptions, vmess.ClientWithAuthenticatedLength())
|
||||||
|
}
|
||||||
|
client, err := vmess.NewClient(options.UUID, options.Security, options.AlterId, clientOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
outbound := &VMess{
|
outbound := &VMess{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
myOutboundAdapter: myOutboundAdapter{
|
||||||
protocol: C.TypeVMess,
|
protocol: C.TypeVMess,
|
||||||
@@ -41,9 +52,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||||||
tag: tag,
|
tag: tag,
|
||||||
},
|
},
|
||||||
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions),
|
dialer: dialer.NewOutbound(router, options.OutboundDialerOptions),
|
||||||
|
client: client,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
}
|
}
|
||||||
var err error
|
|
||||||
if options.TLS != nil {
|
if options.TLS != nil {
|
||||||
outbound.tlsConfig, err = dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS))
|
outbound.tlsConfig, err = dialer.TLSConfig(options.Server, common.PtrValueOrDefault(options.TLS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,25 +71,6 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var clientOptions []vmess.ClientOption
|
|
||||||
if options.GlobalPadding {
|
|
||||||
clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding())
|
|
||||||
}
|
|
||||||
if options.AuthenticatedLength {
|
|
||||||
clientOptions = append(clientOptions, vmess.ClientWithAuthenticatedLength())
|
|
||||||
}
|
|
||||||
security := options.Security
|
|
||||||
if security == "" {
|
|
||||||
security = "auto"
|
|
||||||
}
|
|
||||||
if security == "auto" && outbound.tlsConfig != nil {
|
|
||||||
security = "zero"
|
|
||||||
}
|
|
||||||
client, err := vmess.NewClient(options.UUID, security, options.AlterId, clientOptions...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
outbound.client = client
|
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -498,13 +498,13 @@ func (r *Router) DefaultOutbound(network string) adapter.Outbound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
metadata.Network = N.NetworkTCP
|
|
||||||
switch metadata.Destination.Fqdn {
|
switch metadata.Destination.Fqdn {
|
||||||
case mux.Destination.Fqdn:
|
case mux.Destination.Fqdn:
|
||||||
r.logger.InfoContext(ctx, "inbound multiplex connection")
|
r.logger.InfoContext(ctx, "inbound multiplex connection")
|
||||||
return mux.NewConnection(ctx, r, r, r.logger, conn, metadata)
|
return mux.NewConnection(ctx, r, r, r.logger, conn, metadata)
|
||||||
case uot.UOTMagicAddress:
|
case uot.UOTMagicAddress:
|
||||||
r.logger.InfoContext(ctx, "inbound UoT connection")
|
r.logger.InfoContext(ctx, "inbound UoT connection")
|
||||||
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Destination = M.Socksaddr{}
|
metadata.Destination = M.Socksaddr{}
|
||||||
return r.RoutePacketConnection(ctx, uot.NewClientConn(conn), metadata)
|
return r.RoutePacketConnection(ctx, uot.NewClientConn(conn), metadata)
|
||||||
}
|
}
|
||||||
@@ -552,7 +552,6 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
metadata.Network = N.NetworkUDP
|
|
||||||
if metadata.SniffEnabled {
|
if metadata.SniffEnabled {
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
buffer.FullReset()
|
buffer.FullReset()
|
||||||
|
|||||||
@@ -6,67 +6,51 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
"go4.org/netipx"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ RuleItem = (*IPCIDRItem)(nil)
|
var _ RuleItem = (*IPCIDRItem)(nil)
|
||||||
|
|
||||||
type IPCIDRItem struct {
|
type IPCIDRItem struct {
|
||||||
ipSet *netipx.IPSet
|
prefixes []netip.Prefix
|
||||||
isSource bool
|
isSource bool
|
||||||
description string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
||||||
var builder netipx.IPSetBuilder
|
prefixes := make([]netip.Prefix, 0, len(prefixStrings))
|
||||||
for i, prefixString := range prefixStrings {
|
for i, prefixString := range prefixStrings {
|
||||||
prefix, err := netip.ParsePrefix(prefixString)
|
prefix, err := netip.ParsePrefix(prefixString)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
builder.AddPrefix(prefix)
|
return nil, E.Cause(err, "parse prefix [", i, "]")
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
addr, addrErr := netip.ParseAddr(prefixString)
|
prefixes = append(prefixes, prefix)
|
||||||
if addrErr == nil {
|
|
||||||
builder.Add(addr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, E.Cause(err, "parse ip_cidr [", i, "]")
|
|
||||||
}
|
|
||||||
var description string
|
|
||||||
if isSource {
|
|
||||||
description = "source_ipcidr="
|
|
||||||
} else {
|
|
||||||
description = "ipcidr="
|
|
||||||
}
|
|
||||||
if dLen := len(prefixStrings); dLen == 1 {
|
|
||||||
description += prefixStrings[0]
|
|
||||||
} else if dLen > 3 {
|
|
||||||
description += "[" + strings.Join(prefixStrings[:3], " ") + "...]"
|
|
||||||
} else {
|
|
||||||
description += "[" + strings.Join(prefixStrings, " ") + "]"
|
|
||||||
}
|
|
||||||
ipSet, err := builder.IPSet()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return &IPCIDRItem{
|
return &IPCIDRItem{
|
||||||
ipSet: ipSet,
|
prefixes: prefixes,
|
||||||
isSource: isSource,
|
isSource: isSource,
|
||||||
description: description,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
if r.isSource {
|
if r.isSource {
|
||||||
return r.ipSet.Contains(metadata.Source.Addr)
|
for _, prefix := range r.prefixes {
|
||||||
|
if prefix.Contains(metadata.Source.Addr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if metadata.Destination.IsIP() {
|
if metadata.Destination.IsIP() {
|
||||||
return r.ipSet.Contains(metadata.Destination.Addr)
|
for _, prefix := range r.prefixes {
|
||||||
|
if prefix.Contains(metadata.Destination.Addr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, address := range metadata.DestinationAddresses {
|
for _, address := range metadata.DestinationAddresses {
|
||||||
if r.ipSet.Contains(address) {
|
for _, prefix := range r.prefixes {
|
||||||
return true
|
if prefix.Contains(address) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,5 +59,17 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPCIDRItem) String() string {
|
func (r *IPCIDRItem) String() string {
|
||||||
return r.description
|
var description string
|
||||||
|
if r.isSource {
|
||||||
|
description = "source_ipcidr="
|
||||||
|
} else {
|
||||||
|
description = "ipcidr="
|
||||||
|
}
|
||||||
|
pLen := len(r.prefixes)
|
||||||
|
if pLen == 1 {
|
||||||
|
description += r.prefixes[0].String()
|
||||||
|
} else {
|
||||||
|
description += "[" + strings.Join(F.MapToString(r.prefixes), " ") + "]"
|
||||||
|
}
|
||||||
|
return description
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,13 +74,13 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
|
|||||||
|
|
||||||
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
||||||
if !c.http2 {
|
if !c.http2 {
|
||||||
return c.dialHTTP(ctx)
|
return c.dialHTTP()
|
||||||
} else {
|
} else {
|
||||||
return c.dialHTTP2(ctx)
|
return c.dialHTTP2()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
|
func (c *Client) dialHTTP() (net.Conn, error) {
|
||||||
conn, err := c.dialer.DialContext(c.ctx, N.NetworkTCP, c.serverAddr)
|
conn, err := c.dialer.DialContext(c.ctx, N.NetworkTCP, c.serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -92,7 +92,6 @@ func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
|
|||||||
Proto: "HTTP/1.1",
|
Proto: "HTTP/1.1",
|
||||||
Header: c.headers.Clone(),
|
Header: c.headers.Clone(),
|
||||||
}
|
}
|
||||||
request = request.WithContext(ctx)
|
|
||||||
switch hostLen := len(c.host); hostLen {
|
switch hostLen := len(c.host); hostLen {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
@@ -115,7 +114,7 @@ func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
|
|||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) {
|
func (c *Client) dialHTTP2() (net.Conn, error) {
|
||||||
pipeInReader, pipeInWriter := io.Pipe()
|
pipeInReader, pipeInWriter := io.Pipe()
|
||||||
request := &http.Request{
|
request := &http.Request{
|
||||||
Method: c.method,
|
Method: c.method,
|
||||||
@@ -125,7 +124,6 @@ func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) {
|
|||||||
Proto: "HTTP/2",
|
Proto: "HTTP/2",
|
||||||
Header: c.headers.Clone(),
|
Header: c.headers.Clone(),
|
||||||
}
|
}
|
||||||
request = request.WithContext(ctx)
|
|
||||||
switch hostLen := len(c.host); hostLen {
|
switch hostLen := len(c.host); hostLen {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
@@ -90,8 +90,9 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.(http.Flusher).Flush()
|
if f, ok := writer.(http.Flusher); ok {
|
||||||
|
f.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 {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
return nil, wrapDialError(response, err)
|
return nil, wrapDialError(response, err)
|
||||||
} else {
|
} else {
|
||||||
return &EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}, nil
|
return &EarlyWebsocketConn{Client: c, create: make(chan struct{})}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package v2raywebsocket
|
package v2raywebsocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -69,7 +68,6 @@ func (c *WebsocketConn) SetDeadline(t time.Time) error {
|
|||||||
|
|
||||||
type EarlyWebsocketConn struct {
|
type EarlyWebsocketConn struct {
|
||||||
*Client
|
*Client
|
||||||
ctx context.Context
|
|
||||||
conn *WebsocketConn
|
conn *WebsocketConn
|
||||||
create chan struct{}
|
create chan struct{}
|
||||||
}
|
}
|
||||||
@@ -100,14 +98,14 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
if len(earlyData) > 0 {
|
if len(earlyData) > 0 {
|
||||||
earlyDataString := base64.RawURLEncoding.EncodeToString(earlyData)
|
earlyDataString := base64.RawURLEncoding.EncodeToString(earlyData)
|
||||||
if c.earlyDataHeaderName == "" {
|
if c.earlyDataHeaderName == "" {
|
||||||
conn, response, err = c.dialer.DialContext(c.ctx, c.uri+earlyDataString, c.headers)
|
conn, response, err = c.dialer.Dial(c.uri+earlyDataString, c.headers)
|
||||||
} else {
|
} else {
|
||||||
headers := c.headers.Clone()
|
headers := c.headers.Clone()
|
||||||
headers.Set(c.earlyDataHeaderName, earlyDataString)
|
headers.Set(c.earlyDataHeaderName, earlyDataString)
|
||||||
conn, response, err = c.dialer.DialContext(c.ctx, c.uri, headers)
|
conn, response, err = c.dialer.Dial(c.uri, headers)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn, response, err = c.dialer.DialContext(c.ctx, c.uri, c.headers)
|
conn, response, err = c.dialer.Dial(c.uri, c.headers)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, wrapDialError(response, err)
|
return 0, wrapDialError(response, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user