mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-07 08:52:09 +03:00
Compare commits
9 Commits
1.1-beta17
...
v1.1-beta1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05ed88aba8 | ||
|
|
9f5cc0442b | ||
|
|
2641a43ad8 | ||
|
|
4a6ab5e9fd | ||
|
|
d1fe17a4db | ||
|
|
7c910165ef | ||
|
|
8c1fddcf8d | ||
|
|
01b4769852 | ||
|
|
a401828ed5 |
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
name: Test build
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- dev
|
|
||||||
- dev-next
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Debug build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Get latest go version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
|
||||||
- name: Cache go module
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: go-${{ hashFiles('**/go.sum') }}
|
|
||||||
- name: Run Test
|
|
||||||
run: make test
|
|
||||||
@@ -14,7 +14,6 @@ RUN set -ex \
|
|||||||
./cmd/sing-box
|
./cmd/sing-box
|
||||||
FROM alpine AS dist
|
FROM alpine AS dist
|
||||||
LABEL maintainer="nekohasekai <contact-git@sekai.icu>"
|
LABEL maintainer="nekohasekai <contact-git@sekai.icu>"
|
||||||
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf
|
|
||||||
RUN set -ex \
|
RUN set -ex \
|
||||||
&& apk upgrade \
|
&& apk upgrade \
|
||||||
&& apk add bash tzdata ca-certificates \
|
&& apk add bash tzdata ca-certificates \
|
||||||
|
|||||||
@@ -69,6 +69,20 @@ func create() (*box.Box, context.CancelFunc, error) {
|
|||||||
cancel()
|
cancel()
|
||||||
return nil, nil, E.Cause(err, "create service")
|
return nil, nil, E.Cause(err, "create service")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osSignals := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
|
defer func() {
|
||||||
|
signal.Stop(osSignals)
|
||||||
|
close(osSignals)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_, loaded := <-osSignals
|
||||||
|
if loaded {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
err = instance.Start()
|
err = instance.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
@@ -80,6 +94,7 @@ func create() (*box.Box, context.CancelFunc, error) {
|
|||||||
func run() error {
|
func run() error {
|
||||||
osSignals := make(chan os.Signal, 1)
|
osSignals := make(chan os.Signal, 1)
|
||||||
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
|
defer signal.Stop(osSignals)
|
||||||
for {
|
for {
|
||||||
instance, cancel, err := create()
|
instance, cancel, err := create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -175,9 +175,13 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if !destination.IsIPv6() {
|
var destinationString string
|
||||||
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
|
if destination.IsValid() && !destination.Addr.IsUnspecified() {
|
||||||
|
destinationString = destination.String()
|
||||||
|
} else if !destination.IsIPv6() {
|
||||||
|
destinationString = d.udpAddr4
|
||||||
} else {
|
} else {
|
||||||
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
|
destinationString = d.udpAddr6
|
||||||
}
|
}
|
||||||
|
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, destinationString)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
var Version = "1.1-beta17"
|
var Version = "1.1-beta18"
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
|
#### 1.1-beta18
|
||||||
|
|
||||||
|
* Enhance defense against active probe **1**
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
The `fallback_after` option has been removed.
|
||||||
|
|
||||||
#### 1.1-beta17
|
#### 1.1-beta17
|
||||||
|
|
||||||
* Fix shadowtls server **1**
|
* Fix shadowtls server **1**
|
||||||
|
|
||||||
*1*:
|
*1*:
|
||||||
|
|
||||||
Added [fallback_after](/configuration/inbound/shadowtls#fallback_after) options.
|
Added [fallback_after](/configuration/inbound/shadowtls#fallback_after) option.
|
||||||
|
|
||||||
#### 1.0.7
|
#### 1.0.7
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"password": "fuck me till the daylight",
|
"password": "fuck me till the daylight",
|
||||||
"fallback_after": 2,
|
|
||||||
"handshake": {
|
"handshake": {
|
||||||
"server": "google.com",
|
"server": "google.com",
|
||||||
"server_port": 443,
|
"server_port": 443,
|
||||||
@@ -40,15 +39,6 @@ Set password.
|
|||||||
|
|
||||||
Only available in the ShadowTLS v2 protocol.
|
Only available in the ShadowTLS v2 protocol.
|
||||||
|
|
||||||
|
|
||||||
#### fallback_after
|
|
||||||
|
|
||||||
Packet count before perform fallback.
|
|
||||||
|
|
||||||
Default is 2.
|
|
||||||
|
|
||||||
Lowering this may prevent TLS 1.3 connections, but reduces the risk of being actively probed.
|
|
||||||
|
|
||||||
#### handshake
|
#### handshake
|
||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"password": "fuck me till the daylight",
|
"password": "fuck me till the daylight",
|
||||||
"fallback_after": 2,
|
|
||||||
"handshake": {
|
"handshake": {
|
||||||
"server": "google.com",
|
"server": "google.com",
|
||||||
"server_port": 443,
|
"server_port": 443,
|
||||||
@@ -40,14 +39,6 @@ ShadowTLS 协议版本。
|
|||||||
|
|
||||||
仅在 ShadowTLS v2 协议中可用。
|
仅在 ShadowTLS v2 协议中可用。
|
||||||
|
|
||||||
#### fallback_after
|
|
||||||
|
|
||||||
在执行回退之前的包计数。
|
|
||||||
|
|
||||||
默认值为 2。
|
|
||||||
|
|
||||||
降低此值可能会阻止 TLS 1.3 连接,但会降低被主动探测的风险。
|
|
||||||
|
|
||||||
#### handshake
|
#### handshake
|
||||||
|
|
||||||
==必填==
|
==必填==
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ type Server struct {
|
|||||||
trafficManager *trafficontrol.Manager
|
trafficManager *trafficontrol.Manager
|
||||||
urlTestHistory *urltest.HistoryStorage
|
urlTestHistory *urltest.HistoryStorage
|
||||||
tcpListener net.Listener
|
tcpListener net.Listener
|
||||||
directIO bool
|
|
||||||
mode string
|
mode string
|
||||||
storeSelected bool
|
storeSelected bool
|
||||||
cacheFile adapter.ClashCacheFile
|
cacheFile adapter.ClashCacheFile
|
||||||
@@ -61,7 +60,6 @@ func NewServer(router adapter.Router, logFactory log.ObservableFactory, options
|
|||||||
},
|
},
|
||||||
trafficManager: trafficManager,
|
trafficManager: trafficManager,
|
||||||
urlTestHistory: urltest.NewHistoryStorage(),
|
urlTestHistory: urltest.NewHistoryStorage(),
|
||||||
directIO: options.DirectIO,
|
|
||||||
mode: strings.ToLower(options.DefaultMode),
|
mode: strings.ToLower(options.DefaultMode),
|
||||||
}
|
}
|
||||||
if server.mode == "" {
|
if server.mode == "" {
|
||||||
@@ -156,7 +154,7 @@ func (s *Server) HistoryStorage() *urltest.HistoryStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule) (net.Conn, adapter.Tracker) {
|
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule) (net.Conn, adapter.Tracker) {
|
||||||
tracker := trafficontrol.NewTCPTracker(conn, s.trafficManager, castMetadata(metadata), s.router, matchedRule, s.directIO)
|
tracker := trafficontrol.NewTCPTracker(conn, s.trafficManager, castMetadata(metadata), s.router, matchedRule)
|
||||||
return tracker, tracker
|
return tracker, tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (tt *tcpTracker) WriterReplaceable() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule, directIO bool) *tcpTracker {
|
func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule) *tcpTracker {
|
||||||
uuid, _ := uuid.NewV4()
|
uuid, _ := uuid.NewV4()
|
||||||
|
|
||||||
var chain []string
|
var chain []string
|
||||||
@@ -107,7 +107,7 @@ func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router ad
|
|||||||
}, func(n int64) {
|
}, func(n int64) {
|
||||||
download.Add(n)
|
download.Add(n)
|
||||||
manager.PushDownloaded(n)
|
manager.PushDownloaded(n)
|
||||||
}, directIO),
|
}),
|
||||||
manager: manager,
|
manager: manager,
|
||||||
trackerInfo: &trackerInfo{
|
trackerInfo: &trackerInfo{
|
||||||
UUID: uuid,
|
UUID: uuid,
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(conn net.Conn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64, direct bool) *Conn {
|
func New(conn net.Conn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64) *Conn {
|
||||||
return &Conn{bufio.NewExtendedConn(conn), readCounter, writeCounter}
|
return &Conn{bufio.NewExtendedConn(conn), readCounter, writeCounter}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHook(conn net.Conn, readCounter func(n int64), writeCounter func(n int64), direct bool) *HookConn {
|
func NewHook(conn net.Conn, readCounter func(n int64), writeCounter func(n int64)) *HookConn {
|
||||||
return &HookConn{bufio.NewExtendedConn(conn), readCounter, writeCounter}
|
return &HookConn{bufio.NewExtendedConn(conn), readCounter, writeCounter}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ var (
|
|||||||
|
|
||||||
type StatsService struct {
|
type StatsService struct {
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
directIO bool
|
|
||||||
inbounds map[string]bool
|
inbounds map[string]bool
|
||||||
outbounds map[string]bool
|
outbounds map[string]bool
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
@@ -50,7 +49,6 @@ func NewStatsService(options option.V2RayStatsServiceOptions) *StatsService {
|
|||||||
}
|
}
|
||||||
return &StatsService{
|
return &StatsService{
|
||||||
createdAt: time.Now(),
|
createdAt: time.Now(),
|
||||||
directIO: options.DirectIO,
|
|
||||||
inbounds: inbounds,
|
inbounds: inbounds,
|
||||||
outbounds: outbounds,
|
outbounds: outbounds,
|
||||||
counters: make(map[string]*atomic.Int64),
|
counters: make(map[string]*atomic.Int64),
|
||||||
@@ -75,7 +73,7 @@ func (s *StatsService) RoutedConnection(inbound string, outbound string, conn ne
|
|||||||
writeCounter = append(writeCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>downlink"))
|
writeCounter = append(writeCounter, s.loadOrCreateCounter("outbound>>>"+outbound+">>>traffic>>>downlink"))
|
||||||
}
|
}
|
||||||
s.access.Unlock()
|
s.access.Unlock()
|
||||||
return trackerconn.New(conn, readCounter, writeCounter, s.directIO)
|
return trackerconn.New(conn, readCounter, writeCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatsService) RoutedPacketConnection(inbound string, outbound string, conn N.PacketConn) N.PacketConn {
|
func (s *StatsService) RoutedPacketConnection(inbound string, outbound string, conn N.PacketConn) N.PacketConn {
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -25,7 +25,7 @@ require (
|
|||||||
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15
|
github.com/sagernet/quic-go v0.0.0-20221108053023-645bcc4f9b15
|
||||||
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4
|
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4
|
||||||
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10
|
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
github.com/sagernet/sing-shadowsocks v0.0.0-20221115140728-028358027bfa
|
||||||
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f
|
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0
|
github.com/sagernet/sing-vmess v0.0.0-20221109021549-b446d5bdddf0
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -136,8 +136,8 @@ github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4 h1:LO7xMvMGhYmjQg2vj
|
|||||||
github.com/sagernet/sing v0.0.0-20221008120626-60a9910eefe4/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4=
|
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 h1:K84AY2TxNX37ePYXVO6QTD/kgn9kDo4oGpTIn9PF5bo=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10/go.mod h1:VAvOT1pyryBIthTGRryFLXAsR1VRQZ05wolMYeQrr/E=
|
github.com/sagernet/sing-dns v0.0.0-20221113031420-c6aaf2ea4b10/go.mod h1:VAvOT1pyryBIthTGRryFLXAsR1VRQZ05wolMYeQrr/E=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20221115140728-028358027bfa h1:L8x5xAykEs9jcEYVLDAOYSkERLfKOkU8TCKlWBOF91c=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
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 h1:CXF+nErOb9f7qiHingSgTa2/lJAgmEFtAQ47oVwdRGU=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20221104121441-66c48a57776f/go.mod h1:1u3pjXA9HmH7kRiBJqM3C/zPxrxnCLd3svmqtub/RFU=
|
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 h1:z3kuD3hPNdEq7/wVy5lwE21f+8ZTazBtR81qswxJoCc=
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (s *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata a
|
|||||||
hashConn := shadowtls.NewHashWriteConn(conn, s.password)
|
hashConn := shadowtls.NewHashWriteConn(conn, s.password)
|
||||||
go bufio.Copy(hashConn, handshakeConn)
|
go bufio.Copy(hashConn, handshakeConn)
|
||||||
var request *buf.Buffer
|
var request *buf.Buffer
|
||||||
request, err = s.copyUntilHandshakeFinishedV2(handshakeConn, conn, hashConn, s.fallbackAfter)
|
request, err = s.copyUntilHandshakeFinishedV2(ctx, handshakeConn, conn, hashConn, s.fallbackAfter)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handshakeConn.Close()
|
handshakeConn.Close()
|
||||||
return s.newConnection(ctx, bufio.NewCachedConn(shadowtls.NewConn(conn), request), metadata)
|
return s.newConnection(ctx, bufio.NewCachedConn(shadowtls.NewConn(conn), request), metadata)
|
||||||
@@ -135,7 +135,7 @@ func (s *ShadowTLS) copyUntilHandshakeFinished(dst io.Writer, src io.Reader) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShadowTLS) copyUntilHandshakeFinishedV2(dst net.Conn, src io.Reader, hash *shadowtls.HashWriteConn, fallbackAfter int) (*buf.Buffer, error) {
|
func (s *ShadowTLS) copyUntilHandshakeFinishedV2(ctx context.Context, dst net.Conn, src io.Reader, hash *shadowtls.HashWriteConn, fallbackAfter int) (*buf.Buffer, error) {
|
||||||
const applicationData = 0x17
|
const applicationData = 0x17
|
||||||
var tlsHdr [5]byte
|
var tlsHdr [5]byte
|
||||||
var applicationDataCount int
|
var applicationDataCount int
|
||||||
@@ -152,9 +152,17 @@ func (s *ShadowTLS) copyUntilHandshakeFinishedV2(dst net.Conn, src io.Reader, ha
|
|||||||
data.Release()
|
data.Release()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if length >= 8 && bytes.Equal(data.To(8), hash.Sum()) {
|
if hash.HasContent() && length >= 8 {
|
||||||
|
checksum := hash.Sum()
|
||||||
|
if bytes.Equal(data.To(8), checksum) {
|
||||||
|
s.logger.TraceContext(ctx, "match current hashcode")
|
||||||
data.Advance(8)
|
data.Advance(8)
|
||||||
return data, nil
|
return data, nil
|
||||||
|
} else if hash.LastSum() != nil && bytes.Equal(data.To(8), hash.LastSum()) {
|
||||||
|
s.logger.TraceContext(ctx, "match last hashcode")
|
||||||
|
data.Advance(8)
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_, err = io.Copy(dst, io.MultiReader(bytes.NewReader(tlsHdr[:]), data))
|
_, err = io.Copy(dst, io.MultiReader(bytes.NewReader(tlsHdr[:]), data))
|
||||||
data.Release()
|
data.Release()
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ type ClashAPIOptions struct {
|
|||||||
ExternalController string `json:"external_controller,omitempty"`
|
ExternalController string `json:"external_controller,omitempty"`
|
||||||
ExternalUI string `json:"external_ui,omitempty"`
|
ExternalUI string `json:"external_ui,omitempty"`
|
||||||
Secret string `json:"secret,omitempty"`
|
Secret string `json:"secret,omitempty"`
|
||||||
DirectIO bool `json:"direct_io,omitempty"`
|
|
||||||
DefaultMode string `json:"default_mode,omitempty"`
|
DefaultMode string `json:"default_mode,omitempty"`
|
||||||
StoreSelected bool `json:"store_selected,omitempty"`
|
StoreSelected bool `json:"store_selected,omitempty"`
|
||||||
CacheFile string `json:"cache_file,omitempty"`
|
CacheFile string `json:"cache_file,omitempty"`
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ type ShadowsocksInboundOptions struct {
|
|||||||
Network NetworkList `json:"network,omitempty"`
|
Network NetworkList `json:"network,omitempty"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
ControlPassword string `json:"control_password,omitempty"`
|
|
||||||
Users []ShadowsocksUser `json:"users,omitempty"`
|
Users []ShadowsocksUser `json:"users,omitempty"`
|
||||||
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
Destinations []ShadowsocksDestination `json:"destinations,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ type V2RayAPIOptions struct {
|
|||||||
|
|
||||||
type V2RayStatsServiceOptions struct {
|
type V2RayStatsServiceOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
DirectIO bool `json:"direct_io,omitempty"`
|
|
||||||
Inbounds []string `json:"inbounds,omitempty"`
|
Inbounds []string `json:"inbounds,omitempty"`
|
||||||
Outbounds []string `json:"outbounds,omitempty"`
|
Outbounds []string `json:"outbounds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,12 +78,6 @@ func NewEarlyConnection(ctx context.Context, this N.Dialer, conn net.Conn, metad
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
switch metadata.Protocol {
|
|
||||||
case C.ProtocolQUIC, C.ProtocolDNS:
|
|
||||||
if !metadata.Destination.Addr.IsUnspecified() {
|
|
||||||
return connectPacketConnection(ctx, this, conn, metadata)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
var outConn net.PacketConn
|
var outConn net.PacketConn
|
||||||
var err error
|
var err error
|
||||||
@@ -98,29 +92,12 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn,
|
|||||||
switch metadata.Protocol {
|
switch metadata.Protocol {
|
||||||
case C.ProtocolSTUN:
|
case C.ProtocolSTUN:
|
||||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
|
ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
|
||||||
}
|
|
||||||
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
|
|
||||||
}
|
|
||||||
|
|
||||||
func connectPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
|
||||||
var outConn net.Conn
|
|
||||||
var err error
|
|
||||||
if len(metadata.DestinationAddresses) > 0 {
|
|
||||||
outConn, err = N.DialSerial(ctx, this, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses)
|
|
||||||
} else {
|
|
||||||
outConn, err = this.DialContext(ctx, N.NetworkUDP, metadata.Destination)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return N.HandshakeFailure(conn, err)
|
|
||||||
}
|
|
||||||
switch metadata.Protocol {
|
|
||||||
case C.ProtocolQUIC:
|
case C.ProtocolQUIC:
|
||||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout)
|
ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout)
|
||||||
case C.ProtocolDNS:
|
case C.ProtocolDNS:
|
||||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout)
|
ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout)
|
||||||
}
|
}
|
||||||
return bufio.CopyPacketConn(ctx, conn, bufio.NewUnbindPacketConn(outConn))
|
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error {
|
func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error {
|
||||||
|
|||||||
@@ -35,18 +35,24 @@ func (c *HashReadConn) Sum() []byte {
|
|||||||
type HashWriteConn struct {
|
type HashWriteConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
hmac hash.Hash
|
hmac hash.Hash
|
||||||
|
hasContent bool
|
||||||
|
lastSum []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHashWriteConn(conn net.Conn, password string) *HashWriteConn {
|
func NewHashWriteConn(conn net.Conn, password string) *HashWriteConn {
|
||||||
return &HashWriteConn{
|
return &HashWriteConn{
|
||||||
conn,
|
Conn: conn,
|
||||||
hmac.New(sha1.New, []byte(password)),
|
hmac: hmac.New(sha1.New, []byte(password)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HashWriteConn) Write(p []byte) (n int, err error) {
|
func (c *HashWriteConn) Write(p []byte) (n int, err error) {
|
||||||
if c.hmac != nil {
|
if c.hmac != nil {
|
||||||
|
if c.hasContent {
|
||||||
|
c.lastSum = c.Sum()
|
||||||
|
}
|
||||||
c.hmac.Write(p)
|
c.hmac.Write(p)
|
||||||
|
c.hasContent = true
|
||||||
}
|
}
|
||||||
return c.Conn.Write(p)
|
return c.Conn.Write(p)
|
||||||
}
|
}
|
||||||
@@ -55,6 +61,14 @@ func (c *HashWriteConn) Sum() []byte {
|
|||||||
return c.hmac.Sum(nil)[:8]
|
return c.hmac.Sum(nil)[:8]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *HashWriteConn) LastSum() []byte {
|
||||||
|
return c.lastSum
|
||||||
|
}
|
||||||
|
|
||||||
func (c *HashWriteConn) Fallback() {
|
func (c *HashWriteConn) Fallback() {
|
||||||
c.hmac = nil
|
c.hmac = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *HashWriteConn) HasContent() bool {
|
||||||
|
return c.hasContent
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,31 +106,22 @@ func (c *GunConn) Write(b []byte) (n int, err error) {
|
|||||||
_, err = bufio.Copy(c.writer, io.MultiReader(bytes.NewReader(grpcHeader), bytes.NewReader(protobufHeader[:varuintLen+1]), bytes.NewReader(b)))
|
_, err = bufio.Copy(c.writer, io.MultiReader(bytes.NewReader(grpcHeader), bytes.NewReader(protobufHeader[:varuintLen+1]), bytes.NewReader(b)))
|
||||||
c.writeAccess.Unlock()
|
c.writeAccess.Unlock()
|
||||||
buf.Put(grpcHeader)
|
buf.Put(grpcHeader)
|
||||||
if c.flusher != nil {
|
if err == nil && c.flusher != nil {
|
||||||
c.flusher.Flush()
|
c.flusher.Flush()
|
||||||
}
|
}
|
||||||
return len(b), baderror.WrapH2(err)
|
return len(b), baderror.WrapH2(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uLen(x uint64) int {
|
|
||||||
i := 0
|
|
||||||
for x >= 0x80 {
|
|
||||||
x >>= 7
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
|
func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
dataLen := buffer.Len()
|
dataLen := buffer.Len()
|
||||||
varLen := uLen(uint64(dataLen))
|
varLen := rw.UVariantLen(uint64(dataLen))
|
||||||
header := buffer.ExtendHeader(6 + varLen)
|
header := buffer.ExtendHeader(6 + varLen)
|
||||||
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
|
||||||
header[5] = 0x0A
|
header[5] = 0x0A
|
||||||
binary.PutUvarint(header[6:], uint64(dataLen))
|
binary.PutUvarint(header[6:], uint64(dataLen))
|
||||||
err := rw.WriteBytes(c.writer, buffer.Bytes())
|
err := rw.WriteBytes(c.writer, buffer.Bytes())
|
||||||
if c.flusher != nil {
|
if err == nil && c.flusher != nil {
|
||||||
c.flusher.Flush()
|
c.flusher.Flush()
|
||||||
}
|
}
|
||||||
return baderror.WrapH2(err)
|
return baderror.WrapH2(err)
|
||||||
@@ -153,31 +144,28 @@ func (c *GunConn) RemoteAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *GunConn) SetDeadline(t time.Time) error {
|
func (c *GunConn) SetDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetWriteDeadline(time.Time) error
|
SetWriteDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetWriteDeadline(t)
|
return responseWriter.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GunConn) SetReadDeadline(t time.Time) error {
|
func (c *GunConn) SetReadDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetReadDeadline(time.Time) error
|
SetReadDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetReadDeadline(t)
|
return responseWriter.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GunConn) SetWriteDeadline(t time.Time) error {
|
func (c *GunConn) SetWriteDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetWriteDeadline(time.Time) error
|
SetWriteDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetWriteDeadline(t)
|
return responseWriter.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,33 +67,30 @@ func (c *HTTPConn) RemoteAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTTPConn) SetDeadline(t time.Time) error {
|
func (c *HTTPConn) SetDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetWriteDeadline(time.Time) error
|
SetWriteDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetWriteDeadline(t)
|
return responseWriter.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTTPConn) SetReadDeadline(t time.Time) error {
|
func (c *HTTPConn) SetReadDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetReadDeadline(time.Time) error
|
SetReadDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetReadDeadline(t)
|
return responseWriter.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HTTPConn) SetWriteDeadline(t time.Time) error {
|
func (c *HTTPConn) SetWriteDeadline(t time.Time) error {
|
||||||
responseWriter, loaded := c.writer.(interface {
|
if responseWriter, loaded := c.writer.(interface {
|
||||||
SetWriteDeadline(time.Time) error
|
SetWriteDeadline(time.Time) error
|
||||||
})
|
}); loaded {
|
||||||
if !loaded {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return responseWriter.SetWriteDeadline(t)
|
return responseWriter.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerHTTPConn struct {
|
type ServerHTTPConn struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user