mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-08 19:45:18 +03:00
Compare commits
7 Commits
v1.13.16-e
...
v1.13.16-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da4c532efb | ||
|
|
97c981764d | ||
|
|
3310474137 | ||
|
|
6c81ddd00f | ||
|
|
da50e2969d | ||
|
|
1e35987658 | ||
|
|
44c9c36c65 |
@@ -42,7 +42,7 @@ Sing-box with extended features.
|
|||||||
### Transports
|
### Transports
|
||||||
- **mKCP** — Reliable UDP-based transport
|
- **mKCP** — Reliable UDP-based transport
|
||||||
- **XHTTP** — Modern XRAY transport
|
- **XHTTP** — Modern XRAY transport
|
||||||
- **rmux** — Improved smux multiplex protocol
|
- **Rmux** — Improved smux multiplexer
|
||||||
|
|
||||||
### Services
|
### Services
|
||||||
- **Admin Panel** — Web-based management interface
|
- **Admin Panel** — Web-based management interface
|
||||||
|
|||||||
@@ -44,10 +44,13 @@
|
|||||||
"i3": "<b 0xc70000000108...",
|
"i3": "<b 0xc70000000108...",
|
||||||
"i4": "<b 0xc70000000108...",
|
"i4": "<b 0xc70000000108...",
|
||||||
"i5": "<b 0xc70000000108...",
|
"i5": "<b 0xc70000000108...",
|
||||||
"j1": "<b 0xc70000000108...",
|
"header_protection_key": "QGg8AFRn6qKfTB7cT3FWH1WGx3np+OKzlNuQUrqIBmI=",
|
||||||
"j2": "<b 0xc70000000108...",
|
"content_padding_addition": "50-100",
|
||||||
"j3": "<b 0xc70000000108...",
|
"rekey_after_time": 120,
|
||||||
"itime": 50,
|
"rekey_timeout": 5,
|
||||||
|
"reject_after_time": 180,
|
||||||
|
"keepalive_timeout": 10,
|
||||||
|
"max_handshake_attempts": 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -19,11 +19,7 @@
|
|||||||
"amnezia": {
|
"amnezia": {
|
||||||
"jc": 120,
|
"jc": 120,
|
||||||
"jmin": 23,
|
"jmin": 23,
|
||||||
"jmax": 911,
|
"jmax": 911
|
||||||
"h1": 1,
|
|
||||||
"h2": 2,
|
|
||||||
"h3": 3,
|
|
||||||
"h4": 4
|
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"detour": "direct"
|
"detour": "direct"
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"level": "error"
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"tag": "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"type": "vpn-client",
|
||||||
|
"tag": "vpn",
|
||||||
|
"address": "10.0.0.2",
|
||||||
|
"key": "1c9b2ccf-b0c0-4c26-868d-a55a4edad3fe",
|
||||||
|
"outbound": {
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "vless-out",
|
||||||
|
"server": "0.0.0.0",
|
||||||
|
"server_port": 8000,
|
||||||
|
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"type": "mixed",
|
||||||
|
"tag": "mixed-in",
|
||||||
|
"listen_port": 7897
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"type": "direct",
|
||||||
|
"tag": "direct-out"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"domain_suffix": ".internal",
|
||||||
|
"outbound": "vpn",
|
||||||
|
"override_gateway": "10.0.0.3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"final": "direct-out",
|
||||||
|
"auto_detect_interface": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"level": "error"
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"tag": "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"type": "vpn-client",
|
||||||
|
"tag": "vpn",
|
||||||
|
"address": "10.0.0.3",
|
||||||
|
"key": "3d74d616-2502-4c17-9cc3-92c366550f4f",
|
||||||
|
"outbound": {
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "vless-out",
|
||||||
|
"server": "0.0.0.0",
|
||||||
|
"server_port": 8000,
|
||||||
|
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937",
|
||||||
|
"network": "tcp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"type": "direct",
|
||||||
|
"tag": "direct-out"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": {
|
||||||
|
"final": "direct-out",
|
||||||
|
"default_domain_resolver": "default",
|
||||||
|
"auto_detect_interface": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"level": "error"
|
||||||
|
},
|
||||||
|
"dns": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"tag": "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"type": "vpn-server",
|
||||||
|
"tag": "vpn",
|
||||||
|
"address": "10.0.0.1",
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"address": "10.0.0.2",
|
||||||
|
"key": "1c9b2ccf-b0c0-4c26-868d-a55a4edad3fe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "10.0.0.3",
|
||||||
|
"key": "3d74d616-2502-4c17-9cc3-92c366550f4f"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"type": "vless",
|
||||||
|
"tag": "vless-in",
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"listen_port": 8000,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "vless",
|
||||||
|
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"type": "direct",
|
||||||
|
"tag": "direct-out"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"source_ip_cidr": "10.0.0.0/24",
|
||||||
|
"outbound": "vpn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"final": "direct-out",
|
||||||
|
"default_domain_resolver": "default",
|
||||||
|
"auto_detect_interface": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"tag": "vpn",
|
"tag": "vpn",
|
||||||
"address": "10.0.0.2",
|
"address": "10.0.0.2",
|
||||||
"key": "1c9b2ccf-b0c0-4c26-868d-a55a4edad3fe",
|
"key": "1c9b2ccf-b0c0-4c26-868d-a55a4edad3fe",
|
||||||
|
"default_gateway": "10.0.0.3",
|
||||||
"outbound": {
|
"outbound": {
|
||||||
"type": "vless",
|
"type": "vless",
|
||||||
"tag": "vless-out",
|
"tag": "vless-out",
|
||||||
@@ -40,13 +41,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"route": {
|
"route": {
|
||||||
"rules": [
|
"final": "vpn",
|
||||||
{
|
|
||||||
"outbound": "vpn",
|
|
||||||
"override_gateway": "10.0.0.3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"final": "direct-out",
|
|
||||||
"auto_detect_interface": true
|
"auto_detect_interface": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"type": "vpn-server",
|
"type": "vpn-server",
|
||||||
"tag": "vpn",
|
"tag": "vpn",
|
||||||
"address": "10.0.0.1",
|
"address": "10.0.0.1",
|
||||||
|
"default_gateway": "10.0.0.2",
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"address": "10.0.0.2",
|
"address": "10.0.0.2",
|
||||||
@@ -47,8 +48,7 @@
|
|||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"inbound": "vless-in",
|
"inbound": "vless-in",
|
||||||
"outbound": "vpn",
|
"outbound": "vpn"
|
||||||
"override_gateway": "10.0.0.2"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"final": "direct-out",
|
"final": "direct-out",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"type": "vpn-server",
|
"type": "vpn-server",
|
||||||
"tag": "vpn",
|
"tag": "vpn",
|
||||||
"address": "10.0.0.1",
|
"address": "10.0.0.1",
|
||||||
|
"default_gateway": "10.0.0.2",
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"address": "10.0.0.2",
|
"address": "10.0.0.2",
|
||||||
@@ -51,13 +52,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"route": {
|
"route": {
|
||||||
"rules": [
|
"final": "vpn",
|
||||||
{
|
|
||||||
"outbound": "vpn",
|
|
||||||
"override_gateway": "10.0.0.2"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"final": "direct-out",
|
|
||||||
"default_domain_resolver": "default",
|
"default_domain_resolver": "default",
|
||||||
"auto_detect_interface": true
|
"auto_detect_interface": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,23 +26,17 @@
|
|||||||
"jc": 120,
|
"jc": 120,
|
||||||
"jmin": 23,
|
"jmin": 23,
|
||||||
"jmax": 911,
|
"jmax": 911,
|
||||||
"s1": 1,
|
|
||||||
"s2": 2,
|
|
||||||
"s3": 3,
|
|
||||||
"s4": 4,
|
|
||||||
"h1": 1,
|
|
||||||
"h2": 2,
|
|
||||||
"h3": 3,
|
|
||||||
"h4": 4,
|
|
||||||
"i1": "<b 0xc70000000108...",
|
"i1": "<b 0xc70000000108...",
|
||||||
"i2": "<b 0xc70000000108...",
|
"i2": "<b 0xc70000000108...",
|
||||||
"i3": "<b 0xc70000000108...",
|
"i3": "<b 0xc70000000108...",
|
||||||
"i4": "<b 0xc70000000108...",
|
"i4": "<b 0xc70000000108...",
|
||||||
"i5": "<b 0xc70000000108...",
|
"i5": "<b 0xc70000000108...",
|
||||||
"j1": "<b 0xc70000000108...",
|
"content_padding_addition": "50-100",
|
||||||
"j2": "<b 0xc70000000108...",
|
"rekey_after_time": 120,
|
||||||
"j3": "<b 0xc70000000108...",
|
"rekey_timeout": 5,
|
||||||
"itime": 50
|
"reject_after_time": 180,
|
||||||
|
"keepalive_timeout": 10,
|
||||||
|
"max_handshake_attempts": 20
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"detour": "direct",
|
"detour": "direct",
|
||||||
|
|||||||
@@ -11,7 +11,24 @@ type WARPEndpointOptions struct {
|
|||||||
Workers int `json:"workers,omitempty"`
|
Workers int `json:"workers,omitempty"`
|
||||||
PreallocatedBuffersPerPool uint32 `json:"preallocated_buffers_per_pool,omitempty"`
|
PreallocatedBuffersPerPool uint32 `json:"preallocated_buffers_per_pool,omitempty"`
|
||||||
DisablePauses bool `json:"disable_pauses,omitempty"`
|
DisablePauses bool `json:"disable_pauses,omitempty"`
|
||||||
Amnezia *WireGuardAmnezia `json:"amnezia,omitempty"`
|
Amnezia *WARPAmnezia `json:"amnezia,omitempty"`
|
||||||
Profile CloudflareProfile `json:"profile,omitempty"`
|
Profile CloudflareProfile `json:"profile,omitempty"`
|
||||||
DialerOptions
|
DialerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WARPAmnezia struct {
|
||||||
|
JC int `json:"jc,omitempty"`
|
||||||
|
JMin int `json:"jmin,omitempty"`
|
||||||
|
JMax int `json:"jmax,omitempty"`
|
||||||
|
I1 string `json:"i1,omitempty"`
|
||||||
|
I2 string `json:"i2,omitempty"`
|
||||||
|
I3 string `json:"i3,omitempty"`
|
||||||
|
I4 string `json:"i4,omitempty"`
|
||||||
|
I5 string `json:"i5,omitempty"`
|
||||||
|
ContentPaddingAddition *badoption.Range[uint32] `json:"content_padding_addition,omitempty"`
|
||||||
|
RekeyAfterTime *badoption.Range[uint32] `json:"rekey_after_time,omitempty"`
|
||||||
|
RekeyTimeout *badoption.Range[uint32] `json:"rekey_timeout,omitempty"`
|
||||||
|
RejectAfterTime *badoption.Range[uint32] `json:"reject_after_time,omitempty"`
|
||||||
|
KeepaliveTimeout *badoption.Range[uint32] `json:"keepalive_timeout,omitempty"`
|
||||||
|
MaxHandshakeAttempts *badoption.Range[uint32] `json:"max_handshake_attempts,omitempty"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,24 +32,27 @@ type WireGuardPeer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WireGuardAmnezia struct {
|
type WireGuardAmnezia struct {
|
||||||
JC int `json:"jc,omitempty"`
|
JC int `json:"jc,omitempty"`
|
||||||
JMin int `json:"jmin,omitempty"`
|
JMin int `json:"jmin,omitempty"`
|
||||||
JMax int `json:"jmax,omitempty"`
|
JMax int `json:"jmax,omitempty"`
|
||||||
S1 int `json:"s1,omitempty"`
|
S1 int `json:"s1,omitempty"`
|
||||||
S2 int `json:"s2,omitempty"`
|
S2 int `json:"s2,omitempty"`
|
||||||
S3 int `json:"s3,omitempty"`
|
S3 int `json:"s3,omitempty"`
|
||||||
S4 int `json:"s4,omitempty"`
|
S4 int `json:"s4,omitempty"`
|
||||||
H1 *badoption.Range[uint32] `json:"h1,omitempty"`
|
H1 *badoption.Range[uint32] `json:"h1,omitempty"`
|
||||||
H2 *badoption.Range[uint32] `json:"h2,omitempty"`
|
H2 *badoption.Range[uint32] `json:"h2,omitempty"`
|
||||||
H3 *badoption.Range[uint32] `json:"h3,omitempty"`
|
H3 *badoption.Range[uint32] `json:"h3,omitempty"`
|
||||||
H4 *badoption.Range[uint32] `json:"h4,omitempty"`
|
H4 *badoption.Range[uint32] `json:"h4,omitempty"`
|
||||||
I1 string `json:"i1,omitempty"`
|
I1 string `json:"i1,omitempty"`
|
||||||
I2 string `json:"i2,omitempty"`
|
I2 string `json:"i2,omitempty"`
|
||||||
I3 string `json:"i3,omitempty"`
|
I3 string `json:"i3,omitempty"`
|
||||||
I4 string `json:"i4,omitempty"`
|
I4 string `json:"i4,omitempty"`
|
||||||
I5 string `json:"i5,omitempty"`
|
I5 string `json:"i5,omitempty"`
|
||||||
J1 string `json:"j1,omitempty"`
|
HeaderProtectionKey string `json:"header_protection_key,omitempty"`
|
||||||
J2 string `json:"j2,omitempty"`
|
ContentPaddingAddition *badoption.Range[uint32] `json:"content_padding_addition,omitempty"`
|
||||||
J3 string `json:"j3,omitempty"`
|
RekeyAfterTime *badoption.Range[uint32] `json:"rekey_after_time,omitempty"`
|
||||||
ITime int64 `json:"itime,omitempty"`
|
RekeyTimeout *badoption.Range[uint32] `json:"rekey_timeout,omitempty"`
|
||||||
|
RejectAfterTime *badoption.Range[uint32] `json:"reject_after_time,omitempty"`
|
||||||
|
KeepaliveTimeout *badoption.Range[uint32] `json:"keepalive_timeout,omitempty"`
|
||||||
|
MaxHandshakeAttempts *badoption.Range[uint32] `json:"max_handshake_attempts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,12 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return h.strategy.wrapConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
wrappedConn, err := h.strategy.wrapConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wrappedConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
@@ -114,12 +119,17 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return h.strategy.wrapPacketConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
wrappedConn, err := h.strategy.wrapPacketConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wrappedConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
conn, err := h.strategy.wrapConn(ctx, conn, &metadata, false)
|
wrappedConn, err := h.strategy.wrapConn(ctx, conn, &metadata, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.ErrorContext(ctx, err)
|
h.logger.ErrorContext(ctx, err)
|
||||||
N.CloseOnHandshakeFailure(conn, onClose, err)
|
N.CloseOnHandshakeFailure(conn, onClose, err)
|
||||||
@@ -127,7 +137,7 @@ func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata
|
|||||||
}
|
}
|
||||||
metadata.Inbound = h.Tag()
|
metadata.Inbound = h.Tag()
|
||||||
metadata.InboundType = h.Type()
|
metadata.InboundType = h.Type()
|
||||||
h.router.RouteConnectionEx(ctx, conn, metadata, onClose)
|
h.router.RouteConnectionEx(ctx, wrappedConn, metadata, onClose)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package bandwidth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -191,7 +192,7 @@ func (s *UsersBandwidthStrategy) getStrategy(ctx context.Context, metadata *adap
|
|||||||
}
|
}
|
||||||
|
|
||||||
type bwConnEntry struct {
|
type bwConnEntry struct {
|
||||||
conn net.Conn
|
conn io.Closer
|
||||||
}
|
}
|
||||||
|
|
||||||
type ManagerBandwidthStrategy struct {
|
type ManagerBandwidthStrategy struct {
|
||||||
@@ -251,7 +252,25 @@ func (s *ManagerBandwidthStrategy) wrapPacketConn(ctx context.Context, conn net.
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, E.New("user strategy not found: ", user)
|
return nil, E.New("user strategy not found: ", user)
|
||||||
}
|
}
|
||||||
return strategy.wrapPacketConn(ctx, conn, metadata, reverse)
|
wrapped, err := strategy.wrapPacketConn(ctx, conn, metadata, reverse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entry := &bwConnEntry{conn: conn}
|
||||||
|
s.mtx.Lock()
|
||||||
|
s.conns[user] = append(s.conns[user], entry)
|
||||||
|
s.mtx.Unlock()
|
||||||
|
return onclose.NewPacketConn(wrapped, func() {
|
||||||
|
s.mtx.Lock()
|
||||||
|
entries := s.conns[user]
|
||||||
|
for i, e := range entries {
|
||||||
|
if e == entry {
|
||||||
|
s.conns[user] = append(entries[:i], entries[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mtx.Unlock()
|
||||||
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ManagerBandwidthStrategy) UpdateStrategies(strategies map[string]BandwidthStrategy) {
|
func (s *ManagerBandwidthStrategy) UpdateStrategies(strategies map[string]BandwidthStrategy) {
|
||||||
|
|||||||
@@ -82,7 +82,12 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return h.strategy.wrapConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
wrappedConn, err := h.strategy.wrapConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wrappedConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
@@ -90,11 +95,16 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return h.strategy.wrapPacketConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
wrappedConn, err := h.strategy.wrapPacketConn(ctx, conn, adapter.ContextFrom(ctx), true)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wrappedConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||||
conn, err := h.strategy.wrapConn(ctx, conn, &metadata, false)
|
wrappedConn, err := h.strategy.wrapConn(ctx, conn, &metadata, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != "traffic limit exceeded" {
|
if err.Error() != "traffic limit exceeded" {
|
||||||
h.logger.ErrorContext(ctx, err)
|
h.logger.ErrorContext(ctx, err)
|
||||||
@@ -104,7 +114,7 @@ func (h *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata
|
|||||||
}
|
}
|
||||||
metadata.Inbound = h.Tag()
|
metadata.Inbound = h.Tag()
|
||||||
metadata.InboundType = h.Type()
|
metadata.InboundType = h.Type()
|
||||||
h.router.RouteConnectionEx(ctx, conn, metadata, onClose)
|
h.router.RouteConnectionEx(ctx, wrappedConn, metadata, onClose)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
func (h *Outbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package traffic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -37,11 +38,11 @@ func NewDefaultWrapStrategy(limiterStrategy TrafficLimiterStrategy, connWrapper
|
|||||||
func (s *DefaultWrapStrategy) wrapConn(ctx context.Context, conn net.Conn, metadata *adapter.InboundContext, reverse bool) (net.Conn, error) {
|
func (s *DefaultWrapStrategy) wrapConn(ctx context.Context, conn net.Conn, metadata *adapter.InboundContext, reverse bool) (net.Conn, error) {
|
||||||
limiter, err := s.limiterStrategy.getLimiter(ctx, metadata)
|
limiter, err := s.limiterStrategy.getLimiter(ctx, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = limiter.Reserve(0)
|
_, err = limiter.Reserve(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.connWrapper(ctx, conn, limiter, reverse), nil
|
return s.connWrapper(ctx, conn, limiter, reverse), nil
|
||||||
}
|
}
|
||||||
@@ -49,11 +50,11 @@ func (s *DefaultWrapStrategy) wrapConn(ctx context.Context, conn net.Conn, metad
|
|||||||
func (s *DefaultWrapStrategy) wrapPacketConn(ctx context.Context, conn net.PacketConn, metadata *adapter.InboundContext, reverse bool) (net.PacketConn, error) {
|
func (s *DefaultWrapStrategy) wrapPacketConn(ctx context.Context, conn net.PacketConn, metadata *adapter.InboundContext, reverse bool) (net.PacketConn, error) {
|
||||||
limiter, err := s.limiterStrategy.getLimiter(ctx, metadata)
|
limiter, err := s.limiterStrategy.getLimiter(ctx, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = limiter.Reserve(0)
|
_, err = limiter.Reserve(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.packetConnWrapper(ctx, conn, limiter, reverse), nil
|
return s.packetConnWrapper(ctx, conn, limiter, reverse), nil
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ func (s *GlobalTrafficStrategy) getLimiter(ctx context.Context, metadata *adapte
|
|||||||
}
|
}
|
||||||
|
|
||||||
type connEntry struct {
|
type connEntry struct {
|
||||||
conn net.Conn
|
conn io.Closer
|
||||||
}
|
}
|
||||||
|
|
||||||
type ManagerTrafficStrategy struct {
|
type ManagerTrafficStrategy struct {
|
||||||
@@ -94,7 +95,7 @@ func (s *ManagerTrafficStrategy) wrapConn(ctx context.Context, conn net.Conn, me
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
wrapped, err := strategy.wrapConn(ctx, conn, metadata, reverse)
|
wrappedConn, err := strategy.wrapConn(ctx, conn, metadata, reverse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -102,7 +103,7 @@ func (s *ManagerTrafficStrategy) wrapConn(ctx context.Context, conn net.Conn, me
|
|||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
s.conns[user] = append(s.conns[user], entry)
|
s.conns[user] = append(s.conns[user], entry)
|
||||||
s.mtx.Unlock()
|
s.mtx.Unlock()
|
||||||
return onclose.NewConn(wrapped, func() {
|
return onclose.NewConn(wrappedConn, func() {
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
entries := s.conns[user]
|
entries := s.conns[user]
|
||||||
for i, e := range entries {
|
for i, e := range entries {
|
||||||
@@ -116,11 +117,29 @@ func (s *ManagerTrafficStrategy) wrapConn(ctx context.Context, conn net.Conn, me
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ManagerTrafficStrategy) wrapPacketConn(ctx context.Context, conn net.PacketConn, metadata *adapter.InboundContext, reverse bool) (net.PacketConn, error) {
|
func (s *ManagerTrafficStrategy) wrapPacketConn(ctx context.Context, conn net.PacketConn, metadata *adapter.InboundContext, reverse bool) (net.PacketConn, error) {
|
||||||
strategy, _, err := s.getStrategy(ctx, metadata)
|
strategy, user, err := s.getStrategy(ctx, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return strategy.wrapPacketConn(ctx, conn, metadata, reverse)
|
wrappedConn, err := strategy.wrapPacketConn(ctx, conn, metadata, reverse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entry := &connEntry{conn: conn}
|
||||||
|
s.mtx.Lock()
|
||||||
|
s.conns[user] = append(s.conns[user], entry)
|
||||||
|
s.mtx.Unlock()
|
||||||
|
return onclose.NewPacketConn(wrappedConn, func() {
|
||||||
|
s.mtx.Lock()
|
||||||
|
entries := s.conns[user]
|
||||||
|
for i, e := range entries {
|
||||||
|
if e == entry {
|
||||||
|
s.conns[user] = append(entries[:i], entries[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mtx.Unlock()
|
||||||
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ManagerTrafficStrategy) getStrategy(ctx context.Context, metadata *adapter.InboundContext) (TrafficStrategy, string, error) {
|
func (s *ManagerTrafficStrategy) getStrategy(ctx context.Context, metadata *adapter.InboundContext) (TrafficStrategy, string, error) {
|
||||||
|
|||||||
@@ -29,13 +29,14 @@ func RegisterClientEndpoint(registry *endpoint.Registry) {
|
|||||||
|
|
||||||
type ClientEndpoint struct {
|
type ClientEndpoint struct {
|
||||||
outbound.Adapter
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
outbound adapter.Outbound
|
outbound adapter.Outbound
|
||||||
router adapter.ConnectionRouterEx
|
router adapter.ConnectionRouterEx
|
||||||
logger logger.ContextLogger
|
logger logger.ContextLogger
|
||||||
address IPv4
|
address IPv4
|
||||||
key uuid.UUID
|
key uuid.UUID
|
||||||
uotClient *uot.Client
|
defaultGateway IPv4
|
||||||
|
uotClient *uot.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VPNClientEndpointOptions) (adapter.Endpoint, error) {
|
func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VPNClientEndpointOptions) (adapter.Endpoint, error) {
|
||||||
@@ -47,13 +48,21 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defaultGateway := Loopback.As4()
|
||||||
|
if options.DefaultGateway.IsValid() {
|
||||||
|
if !options.DefaultGateway.Is4() {
|
||||||
|
return nil, E.New("invalid default_gateway: ", options.DefaultGateway)
|
||||||
|
}
|
||||||
|
defaultGateway = options.DefaultGateway.As4()
|
||||||
|
}
|
||||||
client := &ClientEndpoint{
|
client := &ClientEndpoint{
|
||||||
Adapter: outbound.NewAdapter(C.TypeVPNClient, tag, []string{N.NetworkTCP, N.NetworkUDP}, []string{}),
|
Adapter: outbound.NewAdapter(C.TypeVPNClient, tag, []string{N.NetworkTCP, N.NetworkUDP}, []string{}),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
router: sbUot.NewRouter(router, logger),
|
router: sbUot.NewRouter(router, logger),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
address: address.As4(),
|
address: address.As4(),
|
||||||
key: key,
|
key: key,
|
||||||
|
defaultGateway: defaultGateway,
|
||||||
}
|
}
|
||||||
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
||||||
outbound, err := outboundRegistry.CreateOutbound(ctx, router, logger, options.Outbound.Tag, options.Outbound.Type, options.Outbound.Options)
|
outbound, err := outboundRegistry.CreateOutbound(ctx, router, logger, options.Outbound.Tag, options.Outbound.Type, options.Outbound.Options)
|
||||||
@@ -102,7 +111,7 @@ func (c *ClientEndpoint) DialContext(ctx context.Context, network string, destin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
gateway := Loopback.As4()
|
gateway := c.defaultGateway
|
||||||
if metadata := adapter.ContextFrom(ctx); metadata != nil {
|
if metadata := adapter.ContextFrom(ctx); metadata != nil {
|
||||||
if metadata.Gateway != nil {
|
if metadata.Gateway != nil {
|
||||||
gateway = metadata.Gateway.As4()
|
gateway = metadata.Gateway.As4()
|
||||||
|
|||||||
@@ -29,15 +29,16 @@ func RegisterServerEndpoint(registry *endpoint.Registry) {
|
|||||||
|
|
||||||
type ServerEndpoint struct {
|
type ServerEndpoint struct {
|
||||||
outbound.Adapter
|
outbound.Adapter
|
||||||
logger logger.ContextLogger
|
logger logger.ContextLogger
|
||||||
inbounds []adapter.Inbound
|
inbounds []adapter.Inbound
|
||||||
router adapter.ConnectionRouterEx
|
router adapter.ConnectionRouterEx
|
||||||
address IPv4
|
address IPv4
|
||||||
addresses map[uuid.UUID]IPv4
|
addresses map[uuid.UUID]IPv4
|
||||||
keys map[IPv4]uuid.UUID
|
keys map[IPv4]uuid.UUID
|
||||||
conns map[IPv4]chan net.Conn
|
conns map[IPv4]chan net.Conn
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
uotClient *uot.Client
|
defaultGateway *netip.Addr
|
||||||
|
uotClient *uot.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VPNServerEndpointOptions) (adapter.Endpoint, error) {
|
func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VPNServerEndpointOptions) (adapter.Endpoint, error) {
|
||||||
@@ -51,6 +52,13 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
|||||||
router: sbUot.NewRouter(router, logger),
|
router: sbUot.NewRouter(router, logger),
|
||||||
address: address.As4(),
|
address: address.As4(),
|
||||||
}
|
}
|
||||||
|
if options.DefaultGateway.IsValid() {
|
||||||
|
if !options.DefaultGateway.Is4() {
|
||||||
|
return nil, E.New("invalid default_gateway: ", options.DefaultGateway)
|
||||||
|
}
|
||||||
|
defaultGateway := options.DefaultGateway
|
||||||
|
server.defaultGateway = &defaultGateway
|
||||||
|
}
|
||||||
router = NewRouter(router, logger, server.connHandler)
|
router = NewRouter(router, logger, server.connHandler)
|
||||||
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
||||||
inbounds := make([]adapter.Inbound, len(options.Inbounds))
|
inbounds := make([]adapter.Inbound, len(options.Inbounds))
|
||||||
@@ -124,6 +132,8 @@ func (s *ServerEndpoint) DialContext(ctx context.Context, network string, destin
|
|||||||
Addr: Loopback,
|
Addr: Loopback,
|
||||||
Port: destination.Port,
|
Port: destination.Port,
|
||||||
}
|
}
|
||||||
|
} else if s.defaultGateway != nil {
|
||||||
|
gateway = s.defaultGateway
|
||||||
} else {
|
} else {
|
||||||
return nil, E.New("missing gateway")
|
return nil, E.New("missing gateway")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,25 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
}
|
}
|
||||||
peer := config.Peers[0]
|
peer := config.Peers[0]
|
||||||
hostParts := strings.Split(peer.Endpoint.Host, ":")
|
hostParts := strings.Split(peer.Endpoint.Host, ":")
|
||||||
|
var amnezia *option.WireGuardAmnezia
|
||||||
|
if options.Amnezia != nil {
|
||||||
|
amnezia = &option.WireGuardAmnezia{
|
||||||
|
JC: options.Amnezia.JC,
|
||||||
|
JMin: options.Amnezia.JMin,
|
||||||
|
JMax: options.Amnezia.JMax,
|
||||||
|
I1: options.Amnezia.I1,
|
||||||
|
I2: options.Amnezia.I2,
|
||||||
|
I3: options.Amnezia.I3,
|
||||||
|
I4: options.Amnezia.I4,
|
||||||
|
I5: options.Amnezia.I5,
|
||||||
|
ContentPaddingAddition: options.Amnezia.ContentPaddingAddition,
|
||||||
|
RekeyAfterTime: options.Amnezia.RekeyAfterTime,
|
||||||
|
RekeyTimeout: options.Amnezia.RekeyTimeout,
|
||||||
|
RejectAfterTime: options.Amnezia.RejectAfterTime,
|
||||||
|
KeepaliveTimeout: options.Amnezia.KeepaliveTimeout,
|
||||||
|
MaxHandshakeAttempts: options.Amnezia.MaxHandshakeAttempts,
|
||||||
|
}
|
||||||
|
}
|
||||||
endpoint.endpoint, err = wireguard.NewEndpoint(
|
endpoint.endpoint, err = wireguard.NewEndpoint(
|
||||||
ctx,
|
ctx,
|
||||||
router,
|
router,
|
||||||
@@ -101,7 +120,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
Workers: options.Workers,
|
Workers: options.Workers,
|
||||||
PreallocatedBuffersPerPool: options.PreallocatedBuffersPerPool,
|
PreallocatedBuffersPerPool: options.PreallocatedBuffersPerPool,
|
||||||
DisablePauses: options.DisablePauses,
|
DisablePauses: options.DisablePauses,
|
||||||
Amnezia: options.Amnezia,
|
Amnezia: amnezia,
|
||||||
DialerOptions: options.DialerOptions,
|
DialerOptions: options.DialerOptions,
|
||||||
|
|
||||||
Address: badoption.Listable[netip.Prefix]{
|
Address: badoption.Listable[netip.Prefix]{
|
||||||
|
|||||||
@@ -77,26 +77,29 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
var amnezia *wireguard.AmneziaOptions
|
var amnezia *wireguard.AmneziaOptions
|
||||||
if options.Amnezia != nil {
|
if options.Amnezia != nil {
|
||||||
amnezia = &wireguard.AmneziaOptions{
|
amnezia = &wireguard.AmneziaOptions{
|
||||||
JC: options.Amnezia.JC,
|
JC: options.Amnezia.JC,
|
||||||
JMin: options.Amnezia.JMin,
|
JMin: options.Amnezia.JMin,
|
||||||
JMax: options.Amnezia.JMax,
|
JMax: options.Amnezia.JMax,
|
||||||
S1: options.Amnezia.S1,
|
S1: options.Amnezia.S1,
|
||||||
S2: options.Amnezia.S2,
|
S2: options.Amnezia.S2,
|
||||||
S3: options.Amnezia.S3,
|
S3: options.Amnezia.S3,
|
||||||
S4: options.Amnezia.S4,
|
S4: options.Amnezia.S4,
|
||||||
H1: options.Amnezia.H1,
|
H1: options.Amnezia.H1,
|
||||||
H2: options.Amnezia.H2,
|
H2: options.Amnezia.H2,
|
||||||
H3: options.Amnezia.H3,
|
H3: options.Amnezia.H3,
|
||||||
H4: options.Amnezia.H4,
|
H4: options.Amnezia.H4,
|
||||||
I1: options.Amnezia.I1,
|
I1: options.Amnezia.I1,
|
||||||
I2: options.Amnezia.I2,
|
I2: options.Amnezia.I2,
|
||||||
I3: options.Amnezia.I3,
|
I3: options.Amnezia.I3,
|
||||||
I4: options.Amnezia.I4,
|
I4: options.Amnezia.I4,
|
||||||
I5: options.Amnezia.I5,
|
I5: options.Amnezia.I5,
|
||||||
J1: options.Amnezia.J1,
|
HeaderProtectionKey: options.Amnezia.HeaderProtectionKey,
|
||||||
J2: options.Amnezia.J2,
|
ContentPaddingAddition: options.Amnezia.ContentPaddingAddition,
|
||||||
J3: options.Amnezia.J3,
|
RekeyAfterTime: options.Amnezia.RekeyAfterTime,
|
||||||
ITime: options.Amnezia.ITime,
|
RekeyTimeout: options.Amnezia.RekeyTimeout,
|
||||||
|
RejectAfterTime: options.Amnezia.RejectAfterTime,
|
||||||
|
KeepaliveTimeout: options.Amnezia.KeepaliveTimeout,
|
||||||
|
MaxHandshakeAttempts: options.Amnezia.MaxHandshakeAttempts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package xhttp
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -110,15 +111,17 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
|
|||||||
if body != nil {
|
if body != nil {
|
||||||
method = c.options.GetNormalizedUplinkHTTPMethod() // stream-up/one
|
method = c.options.GetNormalizedUplinkHTTPMethod() // stream-up/one
|
||||||
}
|
}
|
||||||
req, _ := http.NewRequestWithContext(context.WithoutCancel(ctx), method, url, body)
|
reqCtx, cancel := context.WithCancel(context.WithoutCancel(ctx))
|
||||||
|
req, _ := http.NewRequestWithContext(reqCtx, method, url, body)
|
||||||
FillStreamRequest(req, sessionId, "", c.options)
|
FillStreamRequest(req, sessionId, "", c.options)
|
||||||
wrc = &WaitReadCloser{Wait: make(chan struct{})}
|
wrc = &WaitReadCloser{Wait: make(chan struct{}), Cancel: cancel}
|
||||||
go func() {
|
go func() {
|
||||||
resp, err := c.client.Do(req)
|
resp, err := c.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !uploadOnly { // stream-down is enough
|
if !uploadOnly && !errors.Is(err, context.Canceled) { // stream-down is enough
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
|
cancel()
|
||||||
gotConn.Close()
|
gotConn.Close()
|
||||||
common.Close(body)
|
common.Close(body)
|
||||||
wrc.Close()
|
wrc.Close()
|
||||||
@@ -128,6 +131,7 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio
|
|||||||
io.Copy(io.Discard, resp.Body)
|
io.Copy(io.Discard, resp.Body)
|
||||||
resp.Body.Close() // if it is called immediately, the upload will be interrupted also
|
resp.Body.Close() // if it is called immediately, the upload will be interrupted also
|
||||||
common.Close(body)
|
common.Close(body)
|
||||||
|
cancel()
|
||||||
wrc.Close()
|
wrc.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -210,7 +214,8 @@ func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WaitReadCloser struct {
|
type WaitReadCloser struct {
|
||||||
Wait chan struct{}
|
Wait chan struct{}
|
||||||
|
Cancel context.CancelFunc
|
||||||
io.ReadCloser
|
io.ReadCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +238,9 @@ func (w *WaitReadCloser) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WaitReadCloser) Close() error {
|
func (w *WaitReadCloser) Close() error {
|
||||||
|
if w.Cancel != nil {
|
||||||
|
w.Cancel()
|
||||||
|
}
|
||||||
if w.ReadCloser != nil {
|
if w.ReadCloser != nil {
|
||||||
return w.ReadCloser.Close()
|
return w.ReadCloser.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,17 +235,30 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
if e.options.Amnezia.I5 != "" {
|
if e.options.Amnezia.I5 != "" {
|
||||||
ipcConf.WriteString("\ni5=" + e.options.Amnezia.I5)
|
ipcConf.WriteString("\ni5=" + e.options.Amnezia.I5)
|
||||||
}
|
}
|
||||||
if e.options.Amnezia.J1 != "" {
|
if e.options.Amnezia.HeaderProtectionKey != "" {
|
||||||
ipcConf.WriteString("\nj1=" + e.options.Amnezia.J1)
|
headerProtectionKeyBytes, err := base64.StdEncoding.DecodeString(e.options.Amnezia.HeaderProtectionKey)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "decode header protection key")
|
||||||
|
}
|
||||||
|
ipcConf.WriteString("\nheader_protection_key=" + hex.EncodeToString(headerProtectionKeyBytes))
|
||||||
}
|
}
|
||||||
if e.options.Amnezia.J2 != "" {
|
if e.options.Amnezia.ContentPaddingAddition != nil {
|
||||||
ipcConf.WriteString("\nj2=" + e.options.Amnezia.J2)
|
ipcConf.WriteString("\ncontent_padding_addition=" + e.options.Amnezia.ContentPaddingAddition.String())
|
||||||
}
|
}
|
||||||
if e.options.Amnezia.J3 != "" {
|
if e.options.Amnezia.RekeyAfterTime != nil {
|
||||||
ipcConf.WriteString("\nj3=" + e.options.Amnezia.J3)
|
ipcConf.WriteString("\nrekey_after_time=" + e.options.Amnezia.RekeyAfterTime.String())
|
||||||
}
|
}
|
||||||
if e.options.Amnezia.ITime > 0 {
|
if e.options.Amnezia.RekeyTimeout != nil {
|
||||||
ipcConf.WriteString("\nitime=" + strconv.FormatInt(e.options.Amnezia.ITime, 10))
|
ipcConf.WriteString("\nrekey_timeout=" + e.options.Amnezia.RekeyTimeout.String())
|
||||||
|
}
|
||||||
|
if e.options.Amnezia.RejectAfterTime != nil {
|
||||||
|
ipcConf.WriteString("\nreject_after_time=" + e.options.Amnezia.RejectAfterTime.String())
|
||||||
|
}
|
||||||
|
if e.options.Amnezia.KeepaliveTimeout != nil {
|
||||||
|
ipcConf.WriteString("\nkeepalive_timeout=" + e.options.Amnezia.KeepaliveTimeout.String())
|
||||||
|
}
|
||||||
|
if e.options.Amnezia.MaxHandshakeAttempts != nil {
|
||||||
|
ipcConf.WriteString("\nmax_handshake_attempts=" + e.options.Amnezia.MaxHandshakeAttempts.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, peer := range e.peers {
|
for _, peer := range e.peers {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/json/badoption"
|
|
||||||
tun "github.com/sagernet/sing-tun"
|
tun "github.com/sagernet/sing-tun"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
@@ -43,24 +43,27 @@ type PeerOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AmneziaOptions struct {
|
type AmneziaOptions struct {
|
||||||
JC int
|
JC int
|
||||||
JMin int
|
JMin int
|
||||||
JMax int
|
JMax int
|
||||||
S1 int
|
S1 int
|
||||||
S2 int
|
S2 int
|
||||||
S3 int
|
S3 int
|
||||||
S4 int
|
S4 int
|
||||||
H1 *badoption.Range[uint32]
|
H1 *badoption.Range[uint32]
|
||||||
H2 *badoption.Range[uint32]
|
H2 *badoption.Range[uint32]
|
||||||
H3 *badoption.Range[uint32]
|
H3 *badoption.Range[uint32]
|
||||||
H4 *badoption.Range[uint32]
|
H4 *badoption.Range[uint32]
|
||||||
I1 string
|
I1 string
|
||||||
I2 string
|
I2 string
|
||||||
I3 string
|
I3 string
|
||||||
I4 string
|
I4 string
|
||||||
I5 string
|
I5 string
|
||||||
J1 string
|
HeaderProtectionKey string
|
||||||
J2 string
|
ContentPaddingAddition *badoption.Range[uint32]
|
||||||
J3 string
|
RekeyAfterTime *badoption.Range[uint32]
|
||||||
ITime int64
|
RekeyTimeout *badoption.Range[uint32]
|
||||||
|
RejectAfterTime *badoption.Range[uint32]
|
||||||
|
KeepaliveTimeout *badoption.Range[uint32]
|
||||||
|
MaxHandshakeAttempts *badoption.Range[uint32]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user