Compare commits

...

14 Commits

Author SHA1 Message Date
世界
8953ddc6e0 Update workflow 2022-12-03 17:03:04 +08:00
世界
7ebbd58b00 Update documentation 2022-12-03 14:38:52 +08:00
世界
d0095fd0f4 Fix close clash cache 2022-12-03 13:29:37 +08:00
世界
66d8d563eb Add WorkingDirectory for systemd service 2022-11-28 18:30:50 +08:00
世界
4bf96c7eb5 Fix quic stub 2022-11-28 16:06:54 +08:00
世界
f687c25fa9 Update documentation 2022-11-28 13:11:07 +08:00
世界
a92412ecac Fix router 2022-11-28 13:11:07 +08:00
世界
8dcafa5b33 Add trojan-go multiplex support for trojan inbound 2022-11-28 12:51:23 +08:00
世界
7a02cb83a7 Revert "Fix listen packet on address"
This reverts commit d1fe17a4db.
2022-11-28 12:51:23 +08:00
世界
51ce672076 Fix crash when input bad method in shadowsocks multi-user inbound 2022-11-28 12:51:23 +08:00
世界
7734afc40c Update dependencies 2022-11-28 12:51:23 +08:00
世界
ee3cd49aa5 Fix tls config for h2 server 2022-11-26 14:55:51 +08:00
世界
bf20ff84b5 Fix lint 2022-11-26 11:21:24 +08:00
世界
c58302554c Fix documentation 2022-11-26 11:06:57 +08:00
38 changed files with 888 additions and 223 deletions

View File

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

View File

@@ -1,8 +1,5 @@
name: Build Docker Images
on:
push:
tags:
- v*
workflow_dispatch:
inputs:
tag:

View File

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

3
box.go
View File

@@ -97,8 +97,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
router, err := route.NewRouter(
ctx,
logFactory.NewLogger("router"),
logFactory.NewLogger("dns"),
logFactory,
common.PtrValueOrDefault(options.Route),
common.PtrValueOrDefault(options.DNS),
options.Inbounds,

View File

@@ -175,13 +175,9 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
}
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
var destinationString string
if destination.IsValid() && !destination.Addr.IsUnspecified() {
destinationString = destination.String()
} else if !destination.IsIPv6() {
destinationString = d.udpAddr4
if !destination.IsIPv6() {
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
} else {
destinationString = d.udpAddr6
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
}
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, destinationString)
}

View File

@@ -1,3 +1,3 @@
package constant
var Version = "1.1-beta18"
var Version = "1.1"

View File

@@ -1,6 +1,42 @@
#### 1.1
* Fix close clash cache
Important changes since 1.0:
* Add support for use with android VPNService
* Add tun support for WireGuard outbound
* Add system tun stack
* Add comment filter for config
* Add option for allow optional proxy protocol header
* Add Clash mode and persistence support
* Add TLS ECH and uTLS support for outbound TLS options
* Add internal simple-obfs and v2ray-plugin
* Add ShadowsocksR outbound
* Add VLESS outbound and XUDP
* Skip wait for hysteria tcp handshake response
* Add v2ray mux support for all inbound
* Add XUDP support for VMess
* Improve websocket writer
* Refine tproxy write back
* Fix DNS leak caused by
Windows' ordinary multihomed DNS resolution behavior
* Add sniff_timeout listen option
* Add custom route support for tun
* Add option for custom wireguard reserved bytes
* Split bind_address into ipv4 and ipv6
* Add ShadowTLS v1 and v2 support
#### 1.1-rc1
* Fix TLS config for h2 server
* Fix crash when input bad method in shadowsocks multi-user inbound
* Fix listen UDP
* Fix check invalid packet on macOS
#### 1.1-beta18
* Enhance defense against active probe **1**
* Enhance defense against active probe for shadowtls server **1**
**1**:

View File

@@ -0,0 +1,52 @@
```json
{
"dns": {
"rules": [
{
"domain": [
"clash.razord.top",
"yacd.haishan.me"
],
"server": "local"
},
{
"clash_mode": "direct",
"server": "local"
}
]
},
"outbounds": [
{
"type": "selector",
"tag": "default",
"outbounds": [
"proxy-a",
"proxy-b"
]
}
],
"route": {
"rules": [
{
"clash_mode": "direct",
"outbound": "direct"
},
{
"domain": [
"clash.razord.top",
"yacd.haishan.me"
],
"outbound": "direct"
}
],
"final": "default"
},
"experimental": {
"clash_api": {
"external_controller": "127.0.0.1:9090",
"store_selected": true
}
}
}
```

View File

@@ -3,7 +3,8 @@
Configuration examples for sing-box.
* [Linux Server Installation](./linux-server-installation)
* [Shadowsocks Server](./ss-server)
* [Shadowsocks Client](./ss-client)
* [Shadowsocks Tun](./ss-tun)
* [DNS Hijack](./dns-hijack.md)
* [Tun](./tun)
* [DNS Hijack](./dns-hijack.md)
* [Shadowsocks](./shadowsocks)
* [ShadowTLS](./shadowtls)
* [Clash API](./clash-api)

View File

@@ -3,7 +3,8 @@
sing-box 的配置示例。
* [Linux 服务器安装](./linux-server-installation)
* [Shadowsocks 服务器](./ss-server)
* [Shadowsocks 客户端](./ss-client)
* [Shadowsocks Tun](./ss-tun)
* [DNS 劫持](./dns-hijack.md)
* [Tun](./tun)
* [DNS 劫持](./dns-hijack.md)
* [Shadowsocks](./shadowsocks)
* [ShadowTLS](./shadowtls)
* [Clash API](./clash-api)

View File

@@ -0,0 +1,157 @@
# Shadowsocks
## Single User
#### Server
```json
{
"inbounds": [
{
"type": "shadowsocks",
"listen": "::",
"listen_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```
#### Client
```json
{
"inbounds": [
{
"type": "mixed",
"listen": "::",
"listen_port": 2080
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "127.0.0.1",
"server_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```
## Multiple Users
#### Server
```json
{
"inbounds": [
{
"type": "shadowsocks",
"listen": "::",
"listen_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==",
"users": [
{
"name": "sekai",
"password": "BXYxVUXJ9NgF7c7KPLQjkg=="
}
]
}
]
}
```
#### Client
```json
{
"inbounds": [
{
"type": "mixed",
"listen": "::",
"listen_port": 2080
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "127.0.0.1",
"server_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==:BXYxVUXJ9NgF7c7KPLQjkg=="
}
]
}
```
## Relay
#### Server
```json
{
"inbounds": [
{
"type": "shadowsocks",
"listen": "::",
"listen_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```
#### Relay
```json
{
"inbounds": [
{
"type": "shadowsocks",
"listen": "::",
"listen_port": 8081,
"method": "2022-blake3-aes-128-gcm",
"password": "BXYxVUXJ9NgF7c7KPLQjkg==",
"destinations": [
{
"name": "my_server",
"password": "8JCsPssfgS8tiRwiMlhARg==",
"server": "127.0.0.1",
"server_port": 8080
}
]
}
]
}
```
#### Client
```json
{
"inbounds": [
{
"type": "mixed",
"listen": "::",
"listen_port": 2080
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "127.0.0.1",
"server_port": 8081,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==:BXYxVUXJ9NgF7c7KPLQjkg=="
}
]
}
```

View File

@@ -7,6 +7,8 @@
"type": "shadowtls",
"listen": "::",
"listen_port": 4443,
"version": 2,
"password": "fuck me till the daylight",
"handshake": {
"server": "google.com",
"server_port": 443
@@ -45,6 +47,8 @@
"tag": "shadowtls-out",
"server": "127.0.0.1",
"server_port": 4443,
"version": 2,
"password": "fuck me till the daylight",
"tls": {
"enabled": true,
"server_name": "google.com"

View File

@@ -1,21 +0,0 @@
```json
{
"inbounds": [
{
"type": "mixed",
"listen": "::",
"listen_port": 2080
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "::",
"server_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```

View File

@@ -1,13 +0,0 @@
```json
{
"inbounds": [
{
"type": "shadowsocks",
"listen": "::",
"listen_port": 8080,
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```

View File

@@ -10,9 +10,18 @@
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
},
{
"domain": "mydomain.com",
"geosite": "cn",
@@ -26,6 +35,7 @@
"type": "tun",
"inet4_address": "172.19.0.1/30",
"auto_route": true,
"strict_route": false,
"sniff": true
}
],
@@ -58,13 +68,16 @@
"outbound": "dns-out"
},
{
"geosite": "category-ads-all",
"outbound": "block"
"geosite": "cn",
"geoip": [
"private",
"cn"
],
"outbound": "direct"
},
{
"geosite": "cn",
"geoip": "cn",
"outbound": "direct"
"geosite": "category-ads-all",
"outbound": "block"
}
],
"auto_detect_interface": true

View File

@@ -7,11 +7,11 @@ the public internet.
##### on Android
`auto-route` cannot automatically hijack DNS requests when Android's `Private DNS` is enabled.
`auto-route` cannot automatically hijack DNS requests when Android's `Private DNS` enabled or `strict_route` disabled.
##### on Linux
`auto-route` cannot automatically hijack DNS requests with `systemd-resolved` enabled, you can switch to NetworkManager.
`auto-route` cannot automatically hijack DNS requests with `systemd-resolved` enabled and `strict_route` disabled.
#### System proxy

View File

@@ -6,11 +6,11 @@
##### Android
`auto-route` 无法自动劫持 DNS 请求如果 `私人 DNS` 开启.
`auto-route` 无法自动劫持 DNS 请求如果 `私人 DNS` 开启`strict_route` 禁用。
##### Linux
`auto-route` 无法自动劫持 DNS 请求如果 `systemd-resolved` 开启, 您可以切换到 NetworkManager.
`auto-route` 无法自动劫持 DNS 请求如果 `systemd-resolved` 开启`strict_route` 禁用。
#### 系统代理

View File

@@ -59,3 +59,7 @@ func (c *CacheFile) StoreSelected(group, selected string) error {
return bucket.Put([]byte(group), []byte(selected))
})
}
func (c *CacheFile) Close() error {
return c.DB.Close()
}

21
go.mod
View File

@@ -4,7 +4,7 @@ go 1.18
require (
berty.tech/go-libtor v1.0.385
github.com/Dreamacro/clash v1.11.12
github.com/Dreamacro/clash v1.12.0
github.com/caddyserver/certmagic v0.17.2
github.com/cretz/bine v0.2.0
github.com/database64128/tfo-go/v2 v2.0.2
@@ -23,11 +23,11 @@ require (
github.com/refraction-networking/utls v1.2.0
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10
github.com/sagernet/sing-shadowsocks v0.0.0-20221115140728-028358027bfa
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0
github.com/sagernet/sing v0.1.0
github.com/sagernet/sing-dns v0.1.0
github.com/sagernet/sing-shadowsocks v0.1.0
github.com/sagernet/sing-tun v0.1.1-0.20221128044455-b22d9eb41b74
github.com/sagernet/sing-vmess v0.1.0
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
@@ -36,10 +36,10 @@ require (
go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.10.0
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab
golang.org/x/crypto v0.3.0
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
golang.org/x/net v0.2.0
golang.org/x/sys v0.2.0
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e
golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669
google.golang.org/grpc v1.51.0
google.golang.org/protobuf v1.28.1
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
@@ -57,10 +57,12 @@ require (
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/klauspost/compress v1.15.12 // indirect
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/marten-seemann/qpack v0.3.0 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
@@ -74,6 +76,7 @@ require (
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.2.0 // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)

44
go.sum
View File

@@ -3,8 +3,8 @@ berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+f
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Dreamacro/clash v1.11.12 h1:zJ+FUWPHWxhfNl5MK64oezFAPPyGth+SDhjuWEJ/jwM=
github.com/Dreamacro/clash v1.11.12/go.mod h1:WiRGFHBrOUYP89GXJ9k4KCyZq5i485LWzc4FPsEPlMI=
github.com/Dreamacro/clash v1.12.0 h1:Fv10zwTtEo4jN1V+fLK+WEOulFAxlZFPfFQGWmbMDrk=
github.com/Dreamacro/clash v1.12.0/go.mod h1:KXZNe2ZS9Z7zZYCFENEW8J9OgyrYrwlr/Gj9ZpzcDVU=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -22,6 +22,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
@@ -86,11 +87,11 @@ github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
@@ -105,6 +106,8 @@ github.com/mholt/acmez v1.0.4 h1:N3cE4Pek+dSolbsofIkAYz6H1d3pE+2G0os7QHslf80=
github.com/mholt/acmez v1.0.4/go.mod h1:qFGLZ4u+ehWINeJZjzPlsnjJBCPAADWTcIqE/7DAYQY=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.3.0 h1:kUMoxMoQG3ogk/QWyKh3zibV7BKZ+xBpWil1cTylVqc=
github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
@@ -132,16 +135,16 @@ github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15 h1:l8RQTjz5LlGEFO
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15/go.mod h1:oWFbojDMm85/Jbm/fyWoo8Pux6dIssxGi3q1r+5642A=
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-20221008120626-60a9910eefe4 h1:LO7xMvMGhYmjQg2vjhTzsODyzs9/WLYu5Per+/8jIeo=
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4=
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10 h1:K84AY2TxNX37ePYXVO6QTD/kgn9kDo4oGpTIn9PF5bo=
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10/go.mod h1:VAvOT1pyryBIthTGRryFLXAsR1VRQZ05wolMYeQrr/E=
github.com/sagernet/sing-shadowsocks v0.0.0-20221115140728-028358027bfa h1:L8x5xAykEs9jcEYVLDAOYSkERLfKOkU8TCKlWBOF91c=
github.com/sagernet/sing-shadowsocks v0.0.0-20221115140728-028358027bfa/go.mod h1:16sNARQbsFbYIzAuPySszQA6Wfgzk7GWSzh1a6kDrUU=
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f h1:CXF+nErOb9f7qiHingSgTa2/lJAgmEFtAQ47oVwdRGU=
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f/go.mod h1:1u3pjXA9HmH7kRiBJqM3C/zPxrxnCLd3svmqtub/RFU=
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0 h1:z3kuD3hPNdEq7/wVy5lwE21f+8ZTazBtR81qswxJoCc=
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
github.com/sagernet/sing v0.1.0 h1:FGmaP2BVPYO2IyC/3R1DaQa/zr+kOKHRgWqrmOF+Gu8=
github.com/sagernet/sing v0.1.0/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4=
github.com/sagernet/sing-dns v0.1.0 h1:mV8y86KDIXCALTbUxQp/n/eSiSzCDuYaf+EbPndI06U=
github.com/sagernet/sing-dns v0.1.0/go.mod h1:IXw6t1F25YvzmgCgV2kKySf4XCEKkUJnmLvKCd7jFEc=
github.com/sagernet/sing-shadowsocks v0.1.0 h1:cDmmOkA11fzVdhyCZQEeI3ozQz+59rj8+rqPb91xux4=
github.com/sagernet/sing-shadowsocks v0.1.0/go.mod h1:O5LtOs8Ivw686FqLpO0Zu+A0ROVE15VeqEK3yDRRAms=
github.com/sagernet/sing-tun v0.1.1-0.20221128044455-b22d9eb41b74 h1:T6U4VNWwxQjr80I6RcQA1lTrWgwQ0vMq1UsnlzeqgxI=
github.com/sagernet/sing-tun v0.1.1-0.20221128044455-b22d9eb41b74/go.mod h1:btUIxuI5vfzUcEDFVrG48aHM2stzg4jcI7mFQeEsei4=
github.com/sagernet/sing-vmess v0.1.0 h1:x0tYBJRbVi7zVXpMEW45eApGpXIDs9ub3raglouAKMo=
github.com/sagernet/sing-vmess v0.1.0/go.mod h1:4lwj6EHrUlgRnKhbmtboGbt+wtl5+tHMv96Ez8LZArw=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
@@ -185,8 +188,8 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc=
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
@@ -212,8 +215,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg=
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -239,8 +242,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk=
golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
@@ -300,8 +303,9 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -70,7 +70,7 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
case common.Contains(shadowaead_2022.List, options.Method):
inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler())
default:
err = E.New("shadowsocks: unsupported method: ", options.Method)
err = E.New("unsupported method: ", options.Method)
}
inbound.packetUpstream = inbound.service
return inbound, err

View File

@@ -13,6 +13,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
N "github.com/sagernet/sing/common/network"
)
@@ -48,12 +49,18 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
} else {
udpTimeout = int64(C.UDPTimeout.Seconds())
}
if !common.Contains(shadowaead_2022.List, options.Method) {
return nil, E.New("unsupported method: " + options.Method)
}
service, err := shadowaead_2022.NewMultiServiceWithPassword[int](
options.Method,
options.Password,
udpTimeout,
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound),
)
if err != nil {
return nil, err
}
err = service.UpdateUsersWithPasswords(common.MapIndexed(options.Users, func(index int, user option.ShadowsocksUser) int {
return index
}), common.Map(options.Users, func(user option.ShadowsocksUser) string {

View File

@@ -10,6 +10,7 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/trojan"
"github.com/sagernet/sing-box/transport/v2ray"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
@@ -17,7 +18,6 @@ import (
F "github.com/sagernet/sing/common/format"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/protocol/trojan"
)
var (
@@ -157,7 +157,7 @@ func (h *Trojan) NewConnection(ctx context.Context, conn net.Conn, metadata adap
return err
}
}
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
return h.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, adapter.UpstreamMetadata(metadata))
}
func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {

View File

@@ -12,6 +12,7 @@ import (
"github.com/sagernet/sing-box/transport/v2ray"
"github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
@@ -19,7 +20,7 @@ import (
const WithQUIC = false
func init() {
dns.RegisterTransport([]string{"quic", "h3"}, func(ctx context.Context, dialer N.Dialer, link string) (dns.Transport, error) {
dns.RegisterTransport([]string{"quic", "h3"}, func(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
return nil, C.ErrQUICNotIncluded
})
v2ray.RegisterQUICConstructor(

View File

@@ -97,11 +97,11 @@ nav:
- Examples:
- examples/index.md
- Linux Server Installation: examples/linux-server-installation.md
- Shadowsocks Server: examples/ss-server.md
- Shadowsocks Client: examples/ss-client.md
- Shadowsocks Tun: examples/ss-tun.md
- ShadowTLS: examples/shadowtls.md
- Tun: examples/tun.md
- DNS Hijack: examples/dns-hijack.md
- Shadowsocks: examples/shadowsocks.md
- ShadowTLS: examples/shadowtls.md
- Clash API: examples/clash-api.md
- Contributing:
- contributing/index.md
- Developing:
@@ -168,7 +168,4 @@ plugins:
Known Issues: 已知问题
Examples: 示例
Linux Server Installation: Linux 服务器安装
Shadowsocks Server: Shadowsocks 服务器
Shadowsocks Client: Shadowsocks 客户端
Shadowsocks Tun: Shadowsocks Tun
DNS Hijack: DNS 劫持

View File

@@ -11,13 +11,13 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/trojan"
"github.com/sagernet/sing-box/transport/v2ray"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/protocol/trojan"
)
var _ adapter.Outbound = (*Trojan)(nil)

View File

@@ -4,6 +4,7 @@ Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target
[Service]
WorkingDirectory=/var/lib/sing-box
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
ExecStart=/usr/bin/sing-box run -c /etc/sing-box/config.json

View File

@@ -4,6 +4,7 @@ Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target
[Service]
WorkingDirectory=/var/lib/sing-box-%i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
ExecStart=/usr/bin/sing-box run -c /etc/sing-box/%i.json

View File

@@ -4,6 +4,7 @@ Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target
[Service]
WorkingDirectory=/var/lib/sing-box
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
ExecStart=/usr/local/bin/sing-box run -c /usr/local/etc/sing-box/config.json

View File

@@ -99,7 +99,7 @@ type Router struct {
v2rayServer adapter.V2RayServer
}
func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.ContextLogger, options option.RouteOptions, dnsOptions option.DNSOptions, inbounds []option.Inbound) (*Router, error) {
func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions, inbounds []option.Inbound) (*Router, error) {
if options.DefaultInterface != "" {
warnDefaultInterfaceOnUnsupportedPlatform.Check()
}
@@ -112,8 +112,8 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
router := &Router{
ctx: ctx,
logger: logger,
dnsLogger: dnsLogger,
logger: logFactory.NewLogger("router"),
dnsLogger: logFactory.NewLogger("dns"),
outboundByTag: make(map[string]adapter.Outbound),
rules: make([]adapter.Rule, 0, len(options.Rules)),
dnsRules: make([]adapter.DNSRule, 0, len(dnsOptions.Rules)),
@@ -130,14 +130,14 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
defaultMark: options.DefaultMark,
}
for i, ruleOptions := range options.Rules {
routeRule, err := NewRule(router, logger, ruleOptions)
routeRule, err := NewRule(router, router.logger, ruleOptions)
if err != nil {
return nil, E.Cause(err, "parse rule[", i, "]")
}
router.rules = append(router.rules, routeRule)
}
for i, dnsRuleOptions := range dnsOptions.Rules {
dnsRule, err := NewDNSRule(router, logger, dnsRuleOptions)
dnsRule, err := NewDNSRule(router, router.logger, dnsRuleOptions)
if err != nil {
return nil, E.Cause(err, "parse dns rule[", i, "]")
}
@@ -197,7 +197,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
return nil, E.New("parse dns server[", tag, "]: missing address_resolver")
}
}
transport, err := dns.CreateTransport(ctx, detour, server.Address)
transport, err := dns.CreateTransport(ctx, logFactory.NewLogger(F.ToString("dns/transport[", i, "]")), detour, server.Address)
if err != nil {
return nil, E.Cause(err, "parse dns server[", tag, "]")
}
@@ -279,12 +279,12 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
}
if needFindProcess {
searcher, err := process.NewSearcher(process.Config{
Logger: logger,
Logger: logFactory.NewLogger("router/process"),
PackageManager: router.packageManager,
})
if err != nil {
if err != os.ErrInvalid {
logger.Warn(E.Cause(err, "create process searcher"))
router.logger.Warn(E.Cause(err, "create process searcher"))
}
} else {
router.processSearcher = searcher

View File

@@ -1,11 +0,0 @@
package tools
import (
"bytes"
"crypto/rand"
"io"
)
func AppendRandBytes(b *bytes.Buffer, length int) {
b.ReadFrom(io.LimitReader(rand.Reader, int64(length)))
}

View File

@@ -1,33 +0,0 @@
package tools
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
)
const HmacSHA1Len = 10
func HmacMD5(key, data []byte) []byte {
hmacMD5 := hmac.New(md5.New, key)
hmacMD5.Write(data)
return hmacMD5.Sum(nil)
}
func HmacSHA1(key, data []byte) []byte {
hmacSHA1 := hmac.New(sha1.New, key)
hmacSHA1.Write(data)
return hmacSHA1.Sum(nil)
}
func MD5Sum(b []byte) []byte {
h := md5.New()
h.Write(b)
return h.Sum(nil)
}
func SHA1Sum(b []byte) []byte {
h := sha1.New()
h.Write(b)
return h.Sum(nil)
}

View File

@@ -1,57 +0,0 @@
package tools
import (
"encoding/binary"
"github.com/Dreamacro/clash/common/pool"
)
// XorShift128Plus - a pseudorandom number generator
type XorShift128Plus struct {
s [2]uint64
}
func (r *XorShift128Plus) Next() uint64 {
x := r.s[0]
y := r.s[1]
r.s[0] = y
x ^= x << 23
x ^= y ^ (x >> 17) ^ (y >> 26)
r.s[1] = x
return x + y
}
func (r *XorShift128Plus) InitFromBin(bin []byte) {
var full []byte
if len(bin) < 16 {
full := pool.Get(16)[:0]
defer pool.Put(full)
full = append(full, bin...)
for len(full) < 16 {
full = append(full, 0)
}
} else {
full = bin
}
r.s[0] = binary.LittleEndian.Uint64(full[:8])
r.s[1] = binary.LittleEndian.Uint64(full[8:16])
}
func (r *XorShift128Plus) InitFromBinAndLength(bin []byte, length int) {
var full []byte
if len(bin) < 16 {
full := pool.Get(16)[:0]
defer pool.Put(full)
full = append(full, bin...)
for len(full) < 16 {
full = append(full, 0)
}
}
full = bin
binary.LittleEndian.PutUint16(full, uint16(length))
r.s[0] = binary.LittleEndian.Uint64(full[:8])
r.s[1] = binary.LittleEndian.Uint64(full[8:16])
for i := 0; i < 4; i++ {
r.Next()
}
}

66
transport/trojan/mux.go Normal file
View File

@@ -0,0 +1,66 @@
package trojan
import (
"context"
"net"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/common/task"
"github.com/sagernet/smux"
)
func HandleMuxConnection(ctx context.Context, conn net.Conn, metadata M.Metadata, handler Handler) error {
session, err := smux.Server(conn, smuxConfig())
if err != nil {
return err
}
var group task.Group
group.Append0(func(ctx context.Context) error {
var stream net.Conn
for {
stream, err = session.AcceptStream()
if err != nil {
return err
}
go newMuxConnection(ctx, stream, metadata, handler)
}
})
group.Cleanup(func() {
session.Close()
})
return group.Run(ctx)
}
func newMuxConnection(ctx context.Context, stream net.Conn, metadata M.Metadata, handler Handler) {
err := newMuxConnection0(ctx, stream, metadata, handler)
if err != nil {
handler.NewError(ctx, E.Cause(err, "process trojan-go multiplex connection"))
}
}
func newMuxConnection0(ctx context.Context, stream net.Conn, metadata M.Metadata, handler Handler) error {
command, err := rw.ReadByte(stream)
if err != nil {
return E.Cause(err, "read command")
}
metadata.Destination, err = M.SocksaddrSerializer.ReadAddrPort(stream)
if err != nil {
return E.Cause(err, "read destination")
}
switch command {
case CommandTCP:
return handler.NewConnection(ctx, stream, metadata)
case CommandUDP:
return handler.NewPacketConnection(ctx, &PacketConn{stream}, metadata)
default:
return E.New("unknown command ", command)
}
}
func smuxConfig() *smux.Config {
config := smux.DefaultConfig()
config.KeepAliveDisabled = true
return config
}

View File

@@ -0,0 +1,313 @@
package trojan
import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"io"
"net"
"os"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
)
const (
KeyLength = 56
CommandTCP = 1
CommandUDP = 3
CommandMux = 0x7f
)
var CRLF = []byte{'\r', '\n'}
type ClientConn struct {
N.ExtendedConn
key [KeyLength]byte
destination M.Socksaddr
headerWritten bool
}
func NewClientConn(conn net.Conn, key [KeyLength]byte, destination M.Socksaddr) *ClientConn {
return &ClientConn{
ExtendedConn: bufio.NewExtendedConn(conn),
key: key,
destination: destination,
}
}
func (c *ClientConn) Write(p []byte) (n int, err error) {
if c.headerWritten {
return c.ExtendedConn.Write(p)
}
err = ClientHandshake(c.ExtendedConn, c.key, c.destination, p)
if err != nil {
return
}
n = len(p)
c.headerWritten = true
return
}
func (c *ClientConn) WriteBuffer(buffer *buf.Buffer) error {
if c.headerWritten {
return c.ExtendedConn.WriteBuffer(buffer)
}
err := ClientHandshakeBuffer(c.ExtendedConn, c.key, c.destination, buffer)
if err != nil {
return err
}
c.headerWritten = true
return nil
}
func (c *ClientConn) ReadFrom(r io.Reader) (n int64, err error) {
if !c.headerWritten {
return bufio.ReadFrom0(c, r)
}
return bufio.Copy(c.ExtendedConn, r)
}
func (c *ClientConn) WriteTo(w io.Writer) (n int64, err error) {
return bufio.Copy(w, c.ExtendedConn)
}
func (c *ClientConn) FrontHeadroom() int {
if !c.headerWritten {
return KeyLength + 5 + M.MaxSocksaddrLength
}
return 0
}
func (c *ClientConn) Upstream() any {
return c.ExtendedConn
}
type ClientPacketConn struct {
net.Conn
key [KeyLength]byte
headerWritten bool
}
func NewClientPacketConn(conn net.Conn, key [KeyLength]byte) *ClientPacketConn {
return &ClientPacketConn{
Conn: conn,
key: key,
}
}
func (c *ClientPacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
return ReadPacket(c.Conn, buffer)
}
func (c *ClientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
if !c.headerWritten {
err := ClientHandshakePacket(c.Conn, c.key, destination, buffer)
c.headerWritten = true
return err
}
return WritePacket(c.Conn, buffer, destination)
}
func (c *ClientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
buffer := buf.With(p)
destination, err := c.ReadPacket(buffer)
if err != nil {
return
}
n = buffer.Len()
addr = destination.UDPAddr()
return
}
func (c *ClientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return bufio.WritePacket(c, p, addr)
}
func (c *ClientPacketConn) Read(p []byte) (n int, err error) {
n, _, err = c.ReadFrom(p)
return
}
func (c *ClientPacketConn) Write(p []byte) (n int, err error) {
return 0, os.ErrInvalid
}
func (c *ClientPacketConn) FrontHeadroom() int {
if !c.headerWritten {
return KeyLength + 2*M.MaxSocksaddrLength + 9
}
return M.MaxSocksaddrLength + 4
}
func (c *ClientPacketConn) Upstream() any {
return c.Conn
}
func Key(password string) [KeyLength]byte {
var key [KeyLength]byte
hash := sha256.New224()
common.Must1(hash.Write([]byte(password)))
hex.Encode(key[:], hash.Sum(nil))
return key
}
func ClientHandshakeRaw(conn net.Conn, key [KeyLength]byte, command byte, destination M.Socksaddr, payload []byte) error {
_, err := conn.Write(key[:])
if err != nil {
return err
}
_, err = conn.Write(CRLF)
if err != nil {
return err
}
_, err = conn.Write([]byte{command})
if err != nil {
return err
}
err = M.SocksaddrSerializer.WriteAddrPort(conn, destination)
if err != nil {
return err
}
_, err = conn.Write(CRLF)
if err != nil {
return err
}
if len(payload) > 0 {
_, err = conn.Write(payload)
if err != nil {
return err
}
}
return nil
}
func ClientHandshake(conn net.Conn, key [KeyLength]byte, destination M.Socksaddr, payload []byte) error {
headerLen := KeyLength + M.SocksaddrSerializer.AddrPortLen(destination) + 5
var header *buf.Buffer
defer header.Release()
var writeHeader bool
if len(payload) > 0 && headerLen+len(payload) < 65535 {
buffer := buf.StackNewSize(headerLen + len(payload))
defer common.KeepAlive(buffer)
header = common.Dup(buffer)
} else {
buffer := buf.StackNewSize(headerLen)
defer common.KeepAlive(buffer)
header = common.Dup(buffer)
writeHeader = true
}
common.Must1(header.Write(key[:]))
common.Must1(header.Write(CRLF))
common.Must(header.WriteByte(CommandTCP))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
common.Must1(header.Write(CRLF))
if !writeHeader {
common.Must1(header.Write(payload))
}
_, err := conn.Write(header.Bytes())
if err != nil {
return E.Cause(err, "write request")
}
if writeHeader {
_, err = conn.Write(payload)
if err != nil {
return E.Cause(err, "write payload")
}
}
return nil
}
func ClientHandshakeBuffer(conn net.Conn, key [KeyLength]byte, destination M.Socksaddr, payload *buf.Buffer) error {
header := buf.With(payload.ExtendHeader(KeyLength + M.SocksaddrSerializer.AddrPortLen(destination) + 5))
common.Must1(header.Write(key[:]))
common.Must1(header.Write(CRLF))
common.Must(header.WriteByte(CommandTCP))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
common.Must1(header.Write(CRLF))
_, err := conn.Write(payload.Bytes())
if err != nil {
return E.Cause(err, "write request")
}
return nil
}
func ClientHandshakePacket(conn net.Conn, key [KeyLength]byte, destination M.Socksaddr, payload *buf.Buffer) error {
headerLen := KeyLength + 2*M.SocksaddrSerializer.AddrPortLen(destination) + 9
payloadLen := payload.Len()
var header *buf.Buffer
defer header.Release()
var writeHeader bool
if payload.Start() >= headerLen {
header = buf.With(payload.ExtendHeader(headerLen))
} else {
buffer := buf.StackNewSize(headerLen)
defer common.KeepAlive(buffer)
header = common.Dup(buffer)
writeHeader = true
}
common.Must1(header.Write(key[:]))
common.Must1(header.Write(CRLF))
common.Must(header.WriteByte(CommandUDP))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
common.Must1(header.Write(CRLF))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
common.Must(binary.Write(header, binary.BigEndian, uint16(payloadLen)))
common.Must1(header.Write(CRLF))
if writeHeader {
_, err := conn.Write(header.Bytes())
if err != nil {
return E.Cause(err, "write request")
}
}
_, err := conn.Write(payload.Bytes())
if err != nil {
return E.Cause(err, "write payload")
}
return nil
}
func ReadPacket(conn net.Conn, buffer *buf.Buffer) (M.Socksaddr, error) {
destination, err := M.SocksaddrSerializer.ReadAddrPort(conn)
if err != nil {
return M.Socksaddr{}, E.Cause(err, "read destination")
}
var length uint16
err = binary.Read(conn, binary.BigEndian, &length)
if err != nil {
return M.Socksaddr{}, E.Cause(err, "read chunk length")
}
err = rw.SkipN(conn, 2)
if err != nil {
return M.Socksaddr{}, E.Cause(err, "skip crlf")
}
_, err = buffer.ReadFullFrom(conn, int(length))
return destination, err
}
func WritePacket(conn net.Conn, buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
bufferLen := buffer.Len()
header := buf.With(buffer.ExtendHeader(M.SocksaddrSerializer.AddrPortLen(destination) + 4))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
common.Must(binary.Write(header, binary.BigEndian, uint16(bufferLen)))
common.Must1(header.Write(CRLF))
_, err := conn.Write(buffer.Bytes())
if err != nil {
return E.Cause(err, "write packet")
}
return nil
}

138
transport/trojan/service.go Normal file
View File

@@ -0,0 +1,138 @@
package trojan
import (
"context"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
)
type Handler interface {
N.TCPConnectionHandler
N.UDPConnectionHandler
E.Handler
}
type Service[K comparable] struct {
users map[K][56]byte
keys map[[56]byte]K
handler Handler
fallbackHandler N.TCPConnectionHandler
}
func NewService[K comparable](handler Handler, fallbackHandler N.TCPConnectionHandler) *Service[K] {
return &Service[K]{
users: make(map[K][56]byte),
keys: make(map[[56]byte]K),
handler: handler,
fallbackHandler: fallbackHandler,
}
}
var ErrUserExists = E.New("user already exists")
func (s *Service[K]) UpdateUsers(userList []K, passwordList []string) error {
users := make(map[K][56]byte)
keys := make(map[[56]byte]K)
for i, user := range userList {
if _, loaded := users[user]; loaded {
return ErrUserExists
}
key := Key(passwordList[i])
if oldUser, loaded := keys[key]; loaded {
return E.Extend(ErrUserExists, "password used by ", oldUser)
}
users[user] = key
keys[key] = user
}
s.users = users
s.keys = keys
return nil
}
func (s *Service[K]) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
var key [KeyLength]byte
n, err := conn.Read(common.Dup(key[:]))
if err != nil {
return err
} else if n != KeyLength {
return s.fallback(ctx, conn, metadata, key[:n], E.New("bad request size"))
}
if user, loaded := s.keys[key]; loaded {
ctx = auth.ContextWithUser(ctx, user)
} else {
return s.fallback(ctx, conn, metadata, key[:], E.New("bad request"))
}
err = rw.SkipN(conn, 2)
if err != nil {
return E.Cause(err, "skip crlf")
}
command, err := rw.ReadByte(conn)
if err != nil {
return E.Cause(err, "read command")
}
switch command {
case CommandTCP, CommandUDP, CommandMux:
default:
return E.New("unknown command ", command)
}
// var destination M.Socksaddr
destination, err := M.SocksaddrSerializer.ReadAddrPort(conn)
if err != nil {
return E.Cause(err, "read destination")
}
err = rw.SkipN(conn, 2)
if err != nil {
return E.Cause(err, "skip crlf")
}
metadata.Protocol = "trojan"
metadata.Destination = destination
switch command {
case CommandTCP:
return s.handler.NewConnection(ctx, conn, metadata)
case CommandUDP:
return s.handler.NewPacketConnection(ctx, &PacketConn{conn}, metadata)
// case CommandMux:
default:
return HandleMuxConnection(ctx, conn, metadata, s.handler)
}
}
func (s *Service[K]) fallback(ctx context.Context, conn net.Conn, metadata M.Metadata, header []byte, err error) error {
if s.fallbackHandler == nil {
return E.Extend(err, "fallback disabled")
}
conn = bufio.NewCachedConn(conn, buf.As(header).ToOwned())
return s.fallbackHandler.NewConnection(ctx, conn, metadata)
}
type PacketConn struct {
net.Conn
}
func (c *PacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
return ReadPacket(c.Conn, buffer)
}
func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
return WritePacket(c.Conn, buffer, destination)
}
func (c *PacketConn) FrontHeadroom() int {
return M.MaxSocksaddrLength + 4
}

View File

@@ -53,8 +53,8 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
if err != nil {
return nil, err
}
if !common.Contains(stdConfig.NextProtos, "h2") {
stdConfig.NextProtos = append(stdConfig.NextProtos, "h2")
if len(stdConfig.NextProtos) == 0 {
stdConfig.NextProtos = []string{http2.NextProtoTLS}
}
server.httpServer.TLSConfig = stdConfig
}
@@ -96,10 +96,14 @@ func (s *Server) badRequest(request *http.Request, err error) {
}
func (s *Server) Serve(listener net.Listener) error {
fixTLSConfig := s.httpServer.TLSConfig == nil
err := http2.ConfigureServer(s.httpServer, s.h2Server)
if err != nil {
return err
}
if fixTLSConfig {
s.httpServer.TLSConfig = nil
}
if s.httpServer.TLSConfig == nil {
return s.httpServer.Serve(listener)
} else {

View File

@@ -133,10 +133,14 @@ func (s *Server) badRequest(request *http.Request, err error) {
}
func (s *Server) Serve(listener net.Listener) error {
fixTLSConfig := s.httpServer.TLSConfig == nil
err := http2.ConfigureServer(s.httpServer, s.h2Server)
if err != nil {
return err
}
if fixTLSConfig {
s.httpServer.TLSConfig = nil
}
if s.httpServer.TLSConfig == nil {
return s.httpServer.Serve(listener)
} else {