mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-24 23:57:59 +03:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b92aa0358a | ||
|
|
316bcd6343 | ||
|
|
1bdb488c9e | ||
|
|
d38ba9d507 | ||
|
|
9d9eaf399f | ||
|
|
eb32d166af | ||
|
|
1dbafe629a | ||
|
|
c42deab55c | ||
|
|
906d49a271 | ||
|
|
4192ca0827 | ||
|
|
228f1e13aa | ||
|
|
15968585f3 | ||
|
|
4951994ebe | ||
|
|
756a2d1327 | ||
|
|
b279076ba1 | ||
|
|
e61eeae258 | ||
|
|
958eb9ea8f | ||
|
|
8381a5a8a6 | ||
|
|
1ead940a71 | ||
|
|
bdff2fa72e | ||
|
|
1d62941bd2 | ||
|
|
52cf9ef5d6 | ||
|
|
16568314d8 | ||
|
|
1fc6850dc4 | ||
|
|
4e87f59628 | ||
|
|
7ab0a3ccb7 | ||
|
|
2fff03720d | ||
|
|
7f7fc5a829 | ||
|
|
ff6c060168 | ||
|
|
5b552db781 | ||
|
|
108bf7ff82 |
@@ -32,9 +32,12 @@ RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
|||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/07_stats.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/08_fakedns.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/09_metrics.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/10_observatory.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/11_geodata.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/99_version.json
|
||||||
|
|
||||||
# Create log files
|
# Create log files
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||||
|
|||||||
@@ -32,9 +32,12 @@ RUN echo '{}' >/tmp/usr/local/etc/xray/03_routing.json
|
|||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/04_policy.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/05_inbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/06_outbounds.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/07_transport.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/07_stats.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/08_stats.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/08_fakedns.json
|
||||||
RUN echo '{}' >/tmp/usr/local/etc/xray/09_reverse.json
|
RUN echo '{}' >/tmp/usr/local/etc/xray/09_metrics.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/10_observatory.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/11_geodata.json
|
||||||
|
RUN echo '{}' >/tmp/usr/local/etc/xray/99_version.json
|
||||||
|
|
||||||
# Create log files
|
# Create log files
|
||||||
RUN mkdir -p /tmp/var/log/xray && touch \
|
RUN mkdir -p /tmp/var/log/xray && touch \
|
||||||
|
|||||||
@@ -73,7 +73,6 @@
|
|||||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
||||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||||
- Magisk
|
- Magisk
|
||||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
|
||||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
||||||
- Homebrew
|
- Homebrew
|
||||||
@@ -111,6 +110,8 @@
|
|||||||
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
- [Invisible Man - Xray](https://github.com/InvisibleManVPN/InvisibleMan-XRayClient)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
||||||
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
|
- [XrayUI-dev](https://github.com/PhoenixNil/XrayUI-dev)
|
||||||
- Android
|
- Android
|
||||||
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
- [v2rayNG](https://github.com/2dust/v2rayNG)
|
||||||
- [X-flutter](https://github.com/XTLS/X-flutter)
|
- [X-flutter](https://github.com/XTLS/X-flutter)
|
||||||
@@ -118,7 +119,7 @@
|
|||||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||||
- [XrayFA](https://github.com/Q7DF1/XrayFA)
|
- [XrayFA](https://github.com/Q7DF1/XrayFA)
|
||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64 & tvOS
|
||||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973) | [Happ tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274)
|
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973) | [Happ tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274)
|
||||||
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
- [Streisand](https://apps.apple.com/app/streisand/id6450534064)
|
||||||
@@ -143,10 +144,12 @@
|
|||||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||||
- [v2rayN](https://github.com/2dust/v2rayN)
|
- [v2rayN](https://github.com/2dust/v2rayN)
|
||||||
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
- [GenyConnect](https://github.com/genyleap/GenyConnect)
|
||||||
|
- [OneXray](https://github.com/OneXray/OneXray)
|
||||||
|
|
||||||
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
## Others that support VLESS, XTLS, REALITY, XUDP, PLUX...
|
||||||
|
|
||||||
- iOS & macOS arm64 & tvOS
|
- iOS & macOS arm64 & tvOS
|
||||||
|
- [Anywhere](https://github.com/NodePassProject/Anywhere)
|
||||||
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)
|
||||||
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
- [Loon](https://apps.apple.com/us/app/loon/id1373567447)
|
||||||
- [Egern](https://apps.apple.com/us/app/egern/id1616105820)
|
- [Egern](https://apps.apple.com/us/app/egern/id1616105820)
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/signal/done"
|
"github.com/xtls/xray-core/common/signal/done"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/outbound"
|
"github.com/xtls/xray-core/features/outbound"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,14 +75,27 @@ func (c *Commander) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if len(c.listen) > 0 {
|
if len(c.listen) > 0 {
|
||||||
if l, err := net.Listen("tcp", c.listen); err != nil {
|
var addr net.Addr
|
||||||
|
|
||||||
|
if strings.HasPrefix(c.listen, "/") || strings.HasPrefix(c.listen, "@") {
|
||||||
|
addr = &net.UnixAddr{Name: c.listen, Net: "unix"}
|
||||||
|
} else {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", c.listen)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "API server failed to parse listen address ", c.listen)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addr = tcpAddr
|
||||||
|
}
|
||||||
|
l, err := internet.ListenSystem(context.Background(), addr, nil)
|
||||||
|
if err != nil {
|
||||||
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
|
errors.LogErrorInner(context.Background(), err, "API server failed to listen on ", c.listen)
|
||||||
return err
|
return err
|
||||||
} else {
|
|
||||||
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
|
|
||||||
go listen(l)
|
|
||||||
}
|
}
|
||||||
|
errors.LogInfo(context.Background(), "API server listening on ", l.Addr())
|
||||||
|
go listen(l)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-68
@@ -5,18 +5,16 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
go_errors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
"github.com/xtls/xray-core/common/geodata"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/utils"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -223,7 +221,7 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.checkSystem {
|
if s.checkSystem {
|
||||||
supportIPv4, supportIPv6 := checkRoutes()
|
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
@@ -539,67 +537,3 @@ func init() {
|
|||||||
return New(ctx, config.(*Config))
|
return New(ctx, config.(*Config))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func probeRoutes() (ipv4 bool, ipv6 bool) {
|
|
||||||
if conn, err := net.Dial("udp4", "192.33.4.12:53"); err == nil {
|
|
||||||
ipv4 = true
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
if conn, err := net.Dial("udp6", "[2001:500:2::c]:53"); err == nil {
|
|
||||||
ipv6 = true
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var routeCache struct {
|
|
||||||
sync.Once
|
|
||||||
sync.RWMutex
|
|
||||||
expire time.Time
|
|
||||||
ipv4, ipv6 bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRoutes() (bool, bool) {
|
|
||||||
if !isGUIPlatform {
|
|
||||||
routeCache.Once.Do(func() {
|
|
||||||
routeCache.ipv4, routeCache.ipv6 = probeRoutes()
|
|
||||||
})
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
|
|
||||||
routeCache.RWMutex.RLock()
|
|
||||||
now := time.Now()
|
|
||||||
if routeCache.expire.After(now) {
|
|
||||||
routeCache.RWMutex.RUnlock()
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
routeCache.RWMutex.RUnlock()
|
|
||||||
|
|
||||||
routeCache.RWMutex.Lock()
|
|
||||||
defer routeCache.RWMutex.Unlock()
|
|
||||||
|
|
||||||
now = time.Now()
|
|
||||||
if routeCache.expire.After(now) { // double-check
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
routeCache.ipv4, routeCache.ipv6 = probeRoutes() // ~2ms
|
|
||||||
routeCache.expire = now.Add(100 * time.Millisecond) // ttl
|
|
||||||
return routeCache.ipv4, routeCache.ipv6
|
|
||||||
}
|
|
||||||
|
|
||||||
var isGUIPlatform = detectGUIPlatform()
|
|
||||||
|
|
||||||
func detectGUIPlatform() bool {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "android", "ios", "windows", "darwin":
|
|
||||||
return true
|
|
||||||
case "linux", "freebsd", "openbsd":
|
|
||||||
if t := os.Getenv("XDG_SESSION_TYPE"); t == "wayland" || t == "x11" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
+8
-8
@@ -148,7 +148,7 @@ func TestUDPServerSubnet(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -210,7 +210,7 @@ func TestUDPServer(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -350,7 +350,7 @@ func TestPrioritizedDomain(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -421,7 +421,7 @@ func TestUDPServerIPv6(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -490,7 +490,7 @@ func TestStaticHostDomain(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -577,7 +577,7 @@ func TestIPMatch(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -696,7 +696,7 @@ func TestLocalDomain(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -953,7 +953,7 @@ func TestMultiMatchPrioritizedDomain(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+8
-12
@@ -17,7 +17,7 @@ import (
|
|||||||
type Holder struct {
|
type Holder struct {
|
||||||
domainToIP cache.Lru
|
domainToIP cache.Lru
|
||||||
ipRange *net.IPNet
|
ipRange *net.IPNet
|
||||||
mu *sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
config *FakeDnsPool
|
config *FakeDnsPool
|
||||||
}
|
}
|
||||||
@@ -49,9 +49,7 @@ func (fkdns *Holder) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) Close() error {
|
func (fkdns *Holder) Close() error {
|
||||||
fkdns.domainToIP = nil
|
// nothing to do for now, just wait GC
|
||||||
fkdns.ipRange = nil
|
|
||||||
fkdns.mu = nil
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +68,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
||||||
return &Holder{nil, nil, nil, conf}, nil
|
return &Holder{config: conf}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fkdns *Holder) initializeFromConfig() error {
|
func (fkdns *Holder) initializeFromConfig() error {
|
||||||
@@ -92,7 +90,6 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
|||||||
}
|
}
|
||||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||||
fkdns.ipRange = ipRange
|
fkdns.ipRange = ipRange
|
||||||
fkdns.mu = new(sync.Mutex)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +100,7 @@ func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
|||||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||||
return []net.Address{v.(net.Address)}
|
return []net.Address{v.(net.Address)}
|
||||||
}
|
}
|
||||||
currentTimeMillis := uint64(time.Now().UnixNano() / 1e6)
|
currentTimeMillis := uint64(time.Now().UnixMilli())
|
||||||
ones, bits := fkdns.ipRange.Mask.Size()
|
ones, bits := fkdns.ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if rooms < 64 {
|
if rooms < 64 {
|
||||||
@@ -202,12 +199,11 @@ func (h *HolderMulti) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *HolderMulti) Close() error {
|
func (h *HolderMulti) Close() error {
|
||||||
|
var errs []error
|
||||||
for _, v := range h.holders {
|
for _, v := range h.holders {
|
||||||
if err := v.Close(); err != nil {
|
errs = append(errs, v.Close())
|
||||||
return errors.New("Cannot close all fake dns pools").Base(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return errors.Combine(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HolderMulti) createHolderGroups() error {
|
func (h *HolderMulti) createHolderGroups() error {
|
||||||
@@ -222,7 +218,7 @@ func (h *HolderMulti) createHolderGroups() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
|
||||||
holderMulti := &HolderMulti{nil, conf}
|
holderMulti := &HolderMulti{config: conf}
|
||||||
if err := holderMulti.createHolderGroups(); err != nil {
|
if err := holderMulti.createHolderGroups(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/geodata"
|
"github.com/xtls/xray-core/common/geodata"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/utils"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/dns"
|
"github.com/xtls/xray-core/features/dns"
|
||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
@@ -166,7 +167,7 @@ func (c *Client) Name() string {
|
|||||||
// QueryIP sends DNS query to the name server with the client's IP.
|
// QueryIP sends DNS query to the name server with the client's IP.
|
||||||
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
func (c *Client) QueryIP(ctx context.Context, domain string, option dns.IPOption) ([]net.IP, uint32, error) {
|
||||||
if c.checkSystem {
|
if c.checkSystem {
|
||||||
supportIPv4, supportIPv6 := checkRoutes()
|
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
||||||
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
option.IPv4Enable = option.IPv4Enable && supportIPv4
|
||||||
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
option.IPv6Enable = option.IPv6Enable && supportIPv6
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/routing"
|
"github.com/xtls/xray-core/features/routing"
|
||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/proxy/hysteria/account"
|
hysteria_proxy "github.com/xtls/xray-core/proxy/hysteria"
|
||||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
"github.com/xtls/xray-core/transport/internet/tcp"
|
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/udp"
|
"github.com/xtls/xray-core/transport/internet/udp"
|
||||||
@@ -134,10 +134,8 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
|
|||||||
func (w *tcpWorker) Start() error {
|
func (w *tcpWorker) Start() error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
type HysteriaInboundValidator interface{ HysteriaInboundValidator() *account.Validator }
|
if v, ok := w.proxy.(*hysteria_proxy.Server); ok {
|
||||||
if v, ok := w.proxy.(HysteriaInboundValidator); ok {
|
ctx = hysteria.ContextWithValidator(ctx, v.HysteriaInboundValidator())
|
||||||
ctx = hyCtx.ContextWithRequireDatagram(ctx, true)
|
|
||||||
ctx = hyCtx.ContextWithValidator(ctx, v.HysteriaInboundValidator())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn stat.Connection) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
|
|||||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
Tag: "tag",
|
Tag: "tag",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
})
|
})
|
||||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||||
_, ok := conn.(*stat.CounterConnection)
|
_, ok := conn.(*stat.CounterConnection)
|
||||||
@@ -78,7 +78,7 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
|||||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
Tag: "tag",
|
Tag: "tag",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
})
|
})
|
||||||
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
conn, _ := h.(*Handler).Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), 13146))
|
||||||
_, ok := conn.(*stat.CounterConnection)
|
_, ok := conn.(*stat.CounterConnection)
|
||||||
@@ -118,7 +118,7 @@ func TestTagsCache(t *testing.T) {
|
|||||||
tag := fmt.Sprintf("%s%d", tags_prefix, idx)
|
tag := fmt.Sprintf("%s%d", tags_prefix, idx)
|
||||||
cfg := &core.OutboundHandlerConfig{
|
cfg := &core.OutboundHandlerConfig{
|
||||||
Tag: tag,
|
Tag: tag,
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
}
|
}
|
||||||
if h, err := NewHandler(ctx, cfg); err == nil {
|
if h, err := NewHandler(ctx, cfg); err == nil {
|
||||||
if err := ohm.AddHandler(ctx, h); err == nil {
|
if err := ohm.AddHandler(ctx, h); err == nil {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
UseFreedomSplice = "xray.buf.splice"
|
UseFreedomSplice = "xray.buf.splice"
|
||||||
UseVmessPadding = "xray.vmess.padding"
|
UseVmessPadding = "xray.vmess.padding"
|
||||||
UseCone = "xray.cone.disabled"
|
UseCone = "xray.cone.disabled"
|
||||||
|
UseStrictJSON = "xray.json.strict"
|
||||||
|
|
||||||
BufferSize = "xray.ray.buffer.size"
|
BufferSize = "xray.ray.buffer.size"
|
||||||
BrowserDialerAddress = "xray.browser.dialer"
|
BrowserDialerAddress = "xray.browser.dialer"
|
||||||
|
|||||||
+28
-45
@@ -3,11 +3,7 @@ package signal
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ActivityUpdater interface {
|
type ActivityUpdater interface {
|
||||||
@@ -15,45 +11,35 @@ type ActivityUpdater interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ActivityTimer struct {
|
type ActivityTimer struct {
|
||||||
mu sync.RWMutex
|
mu sync.Mutex
|
||||||
updated chan struct{}
|
// timer will be nil if this timer is already finished
|
||||||
checkTask *task.Periodic
|
timer *time.Timer
|
||||||
|
timeout time.Duration
|
||||||
onTimeout func()
|
onTimeout func()
|
||||||
consumed atomic.Bool
|
|
||||||
once sync.Once
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ActivityTimer) Update() {
|
func (t *ActivityTimer) Update() {
|
||||||
select {
|
// someone already called Update or closing, just return
|
||||||
case t.updated <- struct{}{}:
|
if !t.mu.TryLock() {
|
||||||
default:
|
return
|
||||||
}
|
}
|
||||||
}
|
defer t.mu.Unlock()
|
||||||
|
if t.timer != nil {
|
||||||
func (t *ActivityTimer) check() error {
|
t.timer.Reset(t.timeout)
|
||||||
select {
|
|
||||||
case <-t.updated:
|
|
||||||
default:
|
|
||||||
t.finish()
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ActivityTimer) finish() {
|
func (t *ActivityTimer) finish() {
|
||||||
t.once.Do(func() {
|
t.mu.Lock()
|
||||||
t.consumed.Store(true)
|
defer t.mu.Unlock()
|
||||||
t.mu.Lock()
|
if t.timer != nil {
|
||||||
defer t.mu.Unlock()
|
t.timer.Stop()
|
||||||
|
|
||||||
common.CloseIfExists(t.checkTask)
|
|
||||||
t.onTimeout()
|
t.onTimeout()
|
||||||
})
|
t.timer = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
||||||
if t.consumed.Load() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
t.finish()
|
t.finish()
|
||||||
return
|
return
|
||||||
@@ -61,25 +47,22 @@ func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
|
|||||||
|
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
// double check, just in case
|
if t.timer != nil {
|
||||||
if t.consumed.Load() {
|
t.timeout = timeout
|
||||||
return
|
t.timer.Reset(timeout)
|
||||||
}
|
}
|
||||||
newCheckTask := &task.Periodic{
|
|
||||||
Interval: timeout,
|
|
||||||
Execute: t.check,
|
|
||||||
}
|
|
||||||
common.CloseIfExists(t.checkTask)
|
|
||||||
t.checkTask = newCheckTask
|
|
||||||
t.Update()
|
|
||||||
common.Must(newCheckTask.Start())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
|
||||||
timer := &ActivityTimer{
|
activityTimer := &ActivityTimer{
|
||||||
updated: make(chan struct{}, 1),
|
timeout: timeout,
|
||||||
onTimeout: cancel,
|
onTimeout: cancel,
|
||||||
}
|
}
|
||||||
timer.SetTimeout(timeout)
|
// strange situation
|
||||||
return timer
|
if timeout == 0 {
|
||||||
|
cancel()
|
||||||
|
return activityTimer
|
||||||
|
}
|
||||||
|
activityTimer.timer = time.AfterFunc(timeout, activityTimer.finish)
|
||||||
|
return activityTimer
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParallelForN runs fn(0..n-1) in parallel across runtime.GOMAXPROCS(0) worker
|
||||||
|
// goroutines. Indices are partitioned into contiguous chunks so the number of
|
||||||
|
// spawned goroutines stays bounded regardless of n.
|
||||||
|
//
|
||||||
|
// fn must be safe to call concurrently from different goroutines (each call
|
||||||
|
// receives its own unique index). Output collected by writing to indexed slots
|
||||||
|
// in a pre-allocated slice is a common safe pattern.
|
||||||
|
//
|
||||||
|
// Returns the first non-nil error reported by fn; other workers may still be
|
||||||
|
// finishing briefly afterwards.
|
||||||
|
func ParallelForN(n int, fn func(i int) error) error {
|
||||||
|
if n <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
workers := max(runtime.GOMAXPROCS(0), 1)
|
||||||
|
workers = min(workers, n)
|
||||||
|
chunk := (n + workers - 1) / workers
|
||||||
|
var eg errgroup.Group
|
||||||
|
for w := range workers {
|
||||||
|
start := w * chunk
|
||||||
|
end := min(start+chunk, n)
|
||||||
|
if start >= end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
eg.Go(func() error {
|
||||||
|
for i := start; i < end; i++ {
|
||||||
|
if err := fn(i); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return eg.Wait()
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package task_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
. "github.com/xtls/xray-core/common/task"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParallelForN_Empty(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
err := ParallelForN(0, func(i int) error {
|
||||||
|
called = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
if called {
|
||||||
|
t.Fatal("fn should not be called when n=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParallelForN_AllIndicesCovered(t *testing.T) {
|
||||||
|
const N = 10000
|
||||||
|
var seen [N]int32
|
||||||
|
err := ParallelForN(N, func(i int) error {
|
||||||
|
atomic.AddInt32(&seen[i], 1)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
common.Must(err)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
if seen[i] != 1 {
|
||||||
|
t.Fatalf("index %d called %d times, expected 1", i, seen[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParallelForN_Error(t *testing.T) {
|
||||||
|
boom := errors.New("boom")
|
||||||
|
err := ParallelForN(1000, func(i int) error {
|
||||||
|
if i == 42 {
|
||||||
|
return boom
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != boom {
|
||||||
|
t.Fatalf("expected %v, got %v", boom, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func probeRoutes() (ipv4 bool, ipv6 bool) {
|
||||||
|
if conn, err := net.Dial("udp4", "192.33.4.12:53"); err == nil {
|
||||||
|
ipv4 = true
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
if conn, err := net.Dial("udp6", "[2001:500:2::c]:53"); err == nil {
|
||||||
|
ipv6 = true
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var routeCache struct {
|
||||||
|
sync.Once
|
||||||
|
sync.RWMutex
|
||||||
|
expire time.Time
|
||||||
|
ipv4, ipv6 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckRoutes() (bool, bool) {
|
||||||
|
if !isGUIPlatform {
|
||||||
|
routeCache.Once.Do(func() {
|
||||||
|
routeCache.ipv4, routeCache.ipv6 = probeRoutes()
|
||||||
|
})
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
|
||||||
|
routeCache.RWMutex.RLock()
|
||||||
|
now := time.Now()
|
||||||
|
if routeCache.expire.After(now) {
|
||||||
|
routeCache.RWMutex.RUnlock()
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
routeCache.RWMutex.RUnlock()
|
||||||
|
|
||||||
|
routeCache.RWMutex.Lock()
|
||||||
|
defer routeCache.RWMutex.Unlock()
|
||||||
|
|
||||||
|
now = time.Now()
|
||||||
|
if routeCache.expire.After(now) { // double-check
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
routeCache.ipv4, routeCache.ipv6 = probeRoutes() // ~2ms
|
||||||
|
routeCache.expire = now.Add(100 * time.Millisecond) // ttl
|
||||||
|
return routeCache.ipv4, routeCache.ipv6
|
||||||
|
}
|
||||||
|
|
||||||
|
var isGUIPlatform = detectGUIPlatform()
|
||||||
|
|
||||||
|
func detectGUIPlatform() bool {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "android", "ios", "windows", "darwin":
|
||||||
|
return true
|
||||||
|
case "linux", "freebsd", "openbsd":
|
||||||
|
if t := os.Getenv("XDG_SESSION_TYPE"); t == "wayland" || t == "x11" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
+2
-2
@@ -19,8 +19,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Version_x byte = 26
|
Version_x byte = 26
|
||||||
Version_y byte = 4
|
Version_y byte = 5
|
||||||
Version_z byte = 25
|
Version_z byte = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func TestXrayDial(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -105,7 +105,7 @@ func TestXrayDialUDPConn(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -174,7 +174,7 @@ func TestXrayDialUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+4
-4
@@ -54,9 +54,9 @@ func TestXrayClose(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(0),
|
RewritePort: uint32(0),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -66,7 +66,7 @@ func TestXrayClose(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(0),
|
Port: uint32(0),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module github.com/xtls/xray-core
|
|||||||
go 1.26
|
go 1.26
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apernet/quic-go v0.59.1-0.20260330051153-c402ee641eb6
|
github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716
|
||||||
github.com/cloudflare/circl v1.6.3
|
github.com/cloudflare/circl v1.6.3
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||||
github.com/golang/mock v1.7.0-rc.1
|
github.com/golang/mock v1.7.0-rc.1
|
||||||
@@ -14,12 +14,12 @@ require (
|
|||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/pires/go-proxyproto v0.12.0
|
github.com/pires/go-proxyproto v0.12.0
|
||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af
|
||||||
github.com/robfig/cron/v3 v3.0.0
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/sagernet/sing v0.5.1
|
github.com/sagernet/sing v0.5.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d
|
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.50.0
|
golang.org/x/crypto v0.50.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
@@ -29,7 +29,7 @@ require (
|
|||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||||
golang.zx2c4.com/wireguard/windows v1.0.1
|
golang.zx2c4.com/wireguard/windows v1.0.1
|
||||||
google.golang.org/grpc v1.80.0
|
google.golang.org/grpc v1.81.0
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
@@ -50,7 +50,7 @@ require (
|
|||||||
golang.org/x/text v0.36.0 // indirect
|
golang.org/x/text v0.36.0 // indirect
|
||||||
golang.org/x/time v0.12.0 // indirect
|
golang.org/x/time v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.43.0 // indirect
|
golang.org/x/tools v0.43.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/apernet/quic-go v0.59.1-0.20260330051153-c402ee641eb6 h1:cbF95uMsQwCwAzH2i8+2lNO2TReoELLuqeeMfyBjFbY=
|
github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716 h1:J1O+xpLuJWkdYbw5JPGwBqIHs2J8tiEP7Py9lPqkN2I=
|
||||||
github.com/apernet/quic-go v0.59.1-0.20260330051153-c402ee641eb6/go.mod h1:Npbg8qBtAZlsAB3FWmqwlVh5jtVG6a4DlYsOylUpvzA=
|
github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716/go.mod h1:Npbg8qBtAZlsAB3FWmqwlVh5jtVG6a4DlYsOylUpvzA=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
@@ -53,8 +53,8 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
|||||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af h1:er2acxbi3N1nvEq6HXHUAR1nTWEJmQfqiGR8EVT9rfs=
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af h1:er2acxbi3N1nvEq6HXHUAR1nTWEJmQfqiGR8EVT9rfs=
|
||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||||
@@ -69,21 +69,19 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zd
|
|||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f h1:iy2JRioxmUpoJ3SzbFPyTxHZMbR/rSHP7dOOgYaq1O8=
|
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f h1:iy2JRioxmUpoJ3SzbFPyTxHZMbR/rSHP7dOOgYaq1O8=
|
||||||
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
||||||
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d h1:ca0n8upCDojatNr25id4npJBwUsMmLgtrvLYDj4J0Hg=
|
|
||||||
github.com/xtls/reality v0.0.0-20260501094811-4379845b089d/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
@@ -139,10 +137,10 @@ golang.zx2c4.com/wireguard/windows v1.0.1 h1:eOxiDVbywPC+ZQqvdCK7x+ZwWXKbYv50TtH
|
|||||||
golang.zx2c4.com/wireguard/windows v1.0.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs=
|
golang.zx2c4.com/wireguard/windows v1.0.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs=
|
||||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw=
|
||||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
+25
-13
@@ -58,25 +58,37 @@ func (c *DNSOutboundRuleConfig) Build() (*dns.DNSRuleConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DNSOutboundConfig struct {
|
type DNSOutboundConfig struct {
|
||||||
Network Network `json:"network"`
|
RewriteNetwork Network `json:"rewriteNetwork"`
|
||||||
Address *Address `json:"address"`
|
RewriteAddress *Address `json:"rewriteAddress"`
|
||||||
Port uint16 `json:"port"`
|
RewritePort uint16 `json:"rewritePort"`
|
||||||
UserLevel uint32 `json:"userLevel"`
|
Network Network `json:"network"`
|
||||||
Rules []*DNSOutboundRuleConfig `json:"rules"`
|
Address *Address `json:"address"`
|
||||||
NonIPQuery *string `json:"nonIPQuery"` // todo: remove legacy
|
Port uint16 `json:"port"`
|
||||||
BlockTypes *[]int32 `json:"blockTypes"` // todo: remove legacy
|
UserLevel uint32 `json:"userLevel"`
|
||||||
|
Rules []*DNSOutboundRuleConfig `json:"rules"`
|
||||||
|
NonIPQuery *string `json:"nonIPQuery"` // todo: remove legacy
|
||||||
|
BlockTypes *[]int32 `json:"blockTypes"` // todo: remove legacy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
||||||
|
if len(c.Network) > 0 {
|
||||||
|
c.RewriteNetwork = c.Network
|
||||||
|
}
|
||||||
|
if c.Address != nil {
|
||||||
|
c.RewriteAddress = c.Address
|
||||||
|
}
|
||||||
|
if c.Port != 0 {
|
||||||
|
c.RewritePort = c.Port
|
||||||
|
}
|
||||||
config := &dns.Config{
|
config := &dns.Config{
|
||||||
Server: &net.Endpoint{
|
RewriteServer: &net.Endpoint{
|
||||||
Network: c.Network.Build(),
|
Network: c.RewriteNetwork.Build(),
|
||||||
Port: uint32(c.Port),
|
Port: uint32(c.RewritePort),
|
||||||
},
|
},
|
||||||
UserLevel: c.UserLevel,
|
UserLevel: c.UserLevel,
|
||||||
}
|
}
|
||||||
if c.Address != nil {
|
if c.RewriteAddress != nil {
|
||||||
config.Server.Address = c.Address.Build()
|
config.RewriteServer.Address = c.RewriteAddress.Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: remove legacy
|
// todo: remove legacy
|
||||||
@@ -84,7 +96,7 @@ func (c *DNSOutboundConfig) Build() (proto.Message, error) {
|
|||||||
if c.Rules != nil {
|
if c.Rules != nil {
|
||||||
return nil, errors.New("legacy nonIPQuery and blockTypes cannot be mixed with rules")
|
return nil, errors.New("legacy nonIPQuery and blockTypes cannot be mixed with rules")
|
||||||
}
|
}
|
||||||
errors.PrintDeprecatedFeatureWarning(`"nonIPQuery" and "blockTypes" in DNS outbound`, `"rules"`)
|
errors.PrintDeprecatedFeatureWarning(`"nonIPQuery" and "blockTypes"`, `"rules"`)
|
||||||
rules, err := c.buildLegacyDNSPolicy()
|
rules, err := c.buildLegacyDNSPolicy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func TestDnsProxyConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{
|
RewriteServer: &net.Endpoint{
|
||||||
Network: net.Network_TCP,
|
Network: net.Network_TCP,
|
||||||
Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})),
|
Address: net.NewIPOrDomain(net.IPAddress([]byte{8, 8, 8, 8})),
|
||||||
Port: 53,
|
Port: 53,
|
||||||
@@ -44,7 +44,7 @@ func TestDnsProxyConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Direct,
|
Action: dns.RuleAction_Direct,
|
||||||
@@ -84,7 +84,7 @@ func TestDnsProxyConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Reject,
|
Action: dns.RuleAction_Reject,
|
||||||
@@ -111,7 +111,7 @@ func TestDnsProxyConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Drop,
|
Action: dns.RuleAction_Drop,
|
||||||
@@ -136,7 +136,7 @@ func TestDnsProxyConfigLegacyCompatibility(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Hijack,
|
Action: dns.RuleAction_Hijack,
|
||||||
@@ -154,7 +154,7 @@ func TestDnsProxyConfigLegacyCompatibility(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Reject,
|
Action: dns.RuleAction_Reject,
|
||||||
@@ -177,7 +177,7 @@ func TestDnsProxyConfigLegacyCompatibility(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Drop,
|
Action: dns.RuleAction_Drop,
|
||||||
@@ -200,7 +200,7 @@ func TestDnsProxyConfigLegacyCompatibility(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dns.Config{
|
Output: &dns.Config{
|
||||||
Server: &net.Endpoint{},
|
RewriteServer: &net.Endpoint{},
|
||||||
Rule: []*dns.DNSRuleConfig{
|
Rule: []*dns.DNSRuleConfig{
|
||||||
{
|
{
|
||||||
Action: dns.RuleAction_Drop,
|
Action: dns.RuleAction_Drop,
|
||||||
|
|||||||
+18
-6
@@ -8,27 +8,39 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DokodemoConfig struct {
|
type DokodemoConfig struct {
|
||||||
|
AllowedNetwork *NetworkList `json:"allowedNetwork"`
|
||||||
|
RewriteAddress *Address `json:"rewriteAddress"`
|
||||||
|
RewritePort uint16 `json:"rewritePort"`
|
||||||
|
Network *NetworkList `json:"network"`
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
PortMap map[string]string `json:"portMap"`
|
PortMap map[string]string `json:"portMap"`
|
||||||
Network *NetworkList `json:"network"`
|
|
||||||
FollowRedirect bool `json:"followRedirect"`
|
FollowRedirect bool `json:"followRedirect"`
|
||||||
UserLevel uint32 `json:"userLevel"`
|
UserLevel uint32 `json:"userLevel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *DokodemoConfig) Build() (proto.Message, error) {
|
func (v *DokodemoConfig) Build() (proto.Message, error) {
|
||||||
config := new(dokodemo.Config)
|
if v.Network != nil {
|
||||||
if v.Address != nil {
|
v.AllowedNetwork = v.Network
|
||||||
config.Address = v.Address.Build()
|
|
||||||
}
|
}
|
||||||
config.Port = uint32(v.Port)
|
if v.Address != nil {
|
||||||
|
v.RewriteAddress = v.Address
|
||||||
|
}
|
||||||
|
if v.Port != 0 {
|
||||||
|
v.RewritePort = v.Port
|
||||||
|
}
|
||||||
|
config := new(dokodemo.Config)
|
||||||
|
config.AllowedNetworks = v.AllowedNetwork.Build()
|
||||||
|
if v.RewriteAddress != nil {
|
||||||
|
config.RewriteAddress = v.RewriteAddress.Build()
|
||||||
|
}
|
||||||
|
config.RewritePort = uint32(v.RewritePort)
|
||||||
config.PortMap = v.PortMap
|
config.PortMap = v.PortMap
|
||||||
for _, v := range config.PortMap {
|
for _, v := range config.PortMap {
|
||||||
if _, _, err := net.SplitHostPort(v); err != nil {
|
if _, _, err := net.SplitHostPort(v); err != nil {
|
||||||
return nil, errors.New("invalid portMap: ", v).Base(err)
|
return nil, errors.New("invalid portMap: ", v).Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.Networks = v.Network.Build()
|
|
||||||
config.FollowRedirect = v.FollowRedirect
|
config.FollowRedirect = v.FollowRedirect
|
||||||
config.UserLevel = v.UserLevel
|
config.UserLevel = v.UserLevel
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|||||||
@@ -24,15 +24,15 @@ func TestDokodemoConfig(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &dokodemo.Config{
|
Output: &dokodemo.Config{
|
||||||
Address: &net.IPOrDomain{
|
RewriteAddress: &net.IPOrDomain{
|
||||||
Address: &net.IPOrDomain_Ip{
|
Address: &net.IPOrDomain_Ip{
|
||||||
Ip: []byte{8, 8, 8, 8},
|
Ip: []byte{8, 8, 8, 8},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Port: 53,
|
RewritePort: 53,
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
FollowRedirect: true,
|
FollowRedirect: true,
|
||||||
UserLevel: 1,
|
UserLevel: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
+72
-15
@@ -1,6 +1,7 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
@@ -8,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/geodata"
|
"github.com/xtls/xray-core/common/geodata"
|
||||||
v2net "github.com/xtls/xray-core/common/net"
|
xnet "github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/proxy/freedom"
|
"github.com/xtls/xray-core/proxy/freedom"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
@@ -16,15 +17,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FreedomConfig struct {
|
type FreedomConfig struct {
|
||||||
TargetStrategy string `json:"targetStrategy"`
|
TargetStrategy string `json:"targetStrategy"`
|
||||||
DomainStrategy string `json:"domainStrategy"`
|
DomainStrategy string `json:"domainStrategy"`
|
||||||
Redirect string `json:"redirect"`
|
Redirect string `json:"redirect"`
|
||||||
UserLevel uint32 `json:"userLevel"`
|
UserLevel uint32 `json:"userLevel"`
|
||||||
Fragment *Fragment `json:"fragment"`
|
Fragment *Fragment `json:"fragment"`
|
||||||
Noise *Noise `json:"noise"`
|
Noise *Noise `json:"noise"`
|
||||||
Noises []*Noise `json:"noises"`
|
Noises []*Noise `json:"noises"`
|
||||||
ProxyProtocol uint32 `json:"proxyProtocol"`
|
ProxyProtocol uint32 `json:"proxyProtocol"`
|
||||||
IPsBlocked *StringList `json:"ipsBlocked"`
|
IPsBlocked *StringList `json:"ipsBlocked"`
|
||||||
|
FinalRules []*FreedomFinalRuleConfig `json:"finalRules"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Fragment struct {
|
type Fragment struct {
|
||||||
@@ -41,8 +43,21 @@ type Noise struct {
|
|||||||
ApplyTo string `json:"applyTo"`
|
ApplyTo string `json:"applyTo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FreedomFinalRuleConfig struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Network *NetworkList `json:"network"`
|
||||||
|
Port *PortList `json:"port"`
|
||||||
|
IP *StringList `json:"ip"`
|
||||||
|
BlockDelay *Int32Range `json:"blockDelay"`
|
||||||
|
}
|
||||||
|
|
||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *FreedomConfig) Build() (proto.Message, error) {
|
func (c *FreedomConfig) Build() (proto.Message, error) {
|
||||||
|
if c.IPsBlocked != nil {
|
||||||
|
// todo: remove legacy
|
||||||
|
errors.LogWarning(context.Background(), `The feature "ipsBlocked" has been removed and migrated to "finalRules". Please update your config(s) according to release note and documentation.`)
|
||||||
|
}
|
||||||
|
|
||||||
config := new(freedom.Config)
|
config := new(freedom.Config)
|
||||||
targetStrategy := c.TargetStrategy
|
targetStrategy := c.TargetStrategy
|
||||||
if targetStrategy == "" {
|
if targetStrategy == "" {
|
||||||
@@ -142,12 +157,13 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config.UserLevel = c.UserLevel
|
config.UserLevel = c.UserLevel
|
||||||
|
|
||||||
if len(c.Redirect) > 0 {
|
if len(c.Redirect) > 0 {
|
||||||
host, portStr, err := net.SplitHostPort(c.Redirect)
|
host, portStr, err := net.SplitHostPort(c.Redirect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid redirect address: ", c.Redirect, ": ", err).Base(err)
|
return nil, errors.New("invalid redirect address: ", c.Redirect, ": ", err).Base(err)
|
||||||
}
|
}
|
||||||
port, err := v2net.PortFromString(portStr)
|
port, err := xnet.PortFromString(portStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid redirect port: ", c.Redirect, ": ", err).Base(err)
|
return nil, errors.New("invalid redirect port: ", c.Redirect, ": ", err).Base(err)
|
||||||
}
|
}
|
||||||
@@ -158,19 +174,22 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(host) > 0 {
|
if len(host) > 0 {
|
||||||
config.DestinationOverride.Server.Address = v2net.NewIPOrDomain(v2net.ParseAddress(host))
|
config.DestinationOverride.Server.Address = xnet.NewIPOrDomain(xnet.ParseAddress(host))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ProxyProtocol > 0 && c.ProxyProtocol <= 2 {
|
if c.ProxyProtocol > 0 && c.ProxyProtocol <= 2 {
|
||||||
config.ProxyProtocol = c.ProxyProtocol
|
config.ProxyProtocol = c.ProxyProtocol
|
||||||
}
|
}
|
||||||
if c.IPsBlocked != nil {
|
|
||||||
rules, err := geodata.ParseIPRules(*c.IPsBlocked)
|
for _, r := range c.FinalRules {
|
||||||
|
rule, err := r.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.IpsBlocked = &freedom.IPRules{Rules: rules}
|
config.FinalRules = append(config.FinalRules, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,3 +248,41 @@ func ParseNoise(noise *Noise) (*freedom.Noise, error) {
|
|||||||
}
|
}
|
||||||
return NConfig, nil
|
return NConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FreedomFinalRuleConfig) Build() (*freedom.FinalRuleConfig, error) {
|
||||||
|
rule := &freedom.FinalRuleConfig{}
|
||||||
|
|
||||||
|
switch strings.ToLower(c.Action) {
|
||||||
|
case "allow":
|
||||||
|
rule.Action = freedom.RuleAction_Allow
|
||||||
|
case "block":
|
||||||
|
rule.Action = freedom.RuleAction_Block
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown action: ", c.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Network != nil {
|
||||||
|
rule.Networks = c.Network.Build()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Port != nil {
|
||||||
|
rule.PortList = c.Port.Build()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.IP != nil {
|
||||||
|
rules, err := geodata.ParseIPRules(*c.IP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rule.Ip = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.BlockDelay != nil {
|
||||||
|
rule.BlockDelay = &freedom.Range{
|
||||||
|
Min: uint64(c.BlockDelay.From),
|
||||||
|
Max: uint64(c.BlockDelay.To),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package conf_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/geodata"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
. "github.com/xtls/xray-core/infra/conf"
|
. "github.com/xtls/xray-core/infra/conf"
|
||||||
@@ -38,5 +39,64 @@ func TestFreedomConfig(t *testing.T) {
|
|||||||
UserLevel: 1,
|
UserLevel: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Input: `{
|
||||||
|
"finalRules": [{
|
||||||
|
"action": "block",
|
||||||
|
"network": "tcp,udp",
|
||||||
|
"port": "53,443",
|
||||||
|
"ip": ["10.0.0.0/8", "2001:db8::/32"],
|
||||||
|
"blockDelay": "30-60"
|
||||||
|
}, {
|
||||||
|
"action": "allow",
|
||||||
|
"network": ["udp"]
|
||||||
|
}]
|
||||||
|
}`,
|
||||||
|
Parser: loadJSON(creator),
|
||||||
|
Output: &freedom.Config{
|
||||||
|
FinalRules: []*freedom.FinalRuleConfig{
|
||||||
|
{
|
||||||
|
Action: freedom.RuleAction_Block,
|
||||||
|
Networks: []net.Network{net.Network_TCP, net.Network_UDP},
|
||||||
|
PortList: &net.PortList{
|
||||||
|
Range: []*net.PortRange{
|
||||||
|
{From: 53, To: 53},
|
||||||
|
{From: 443, To: 443},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Ip: []*geodata.IPRule{
|
||||||
|
{
|
||||||
|
Value: &geodata.IPRule_Custom{
|
||||||
|
Custom: &geodata.CIDRRule{
|
||||||
|
Cidr: &geodata.CIDR{
|
||||||
|
Ip: []byte{10, 0, 0, 0},
|
||||||
|
Prefix: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: &geodata.IPRule_Custom{
|
||||||
|
Custom: &geodata.CIDRRule{
|
||||||
|
Cidr: &geodata.CIDR{
|
||||||
|
Ip: net.ParseAddress("2001:db8::").IP(),
|
||||||
|
Prefix: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BlockDelay: &freedom.Range{
|
||||||
|
Min: 30,
|
||||||
|
Max: 60,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: freedom.RuleAction_Allow,
|
||||||
|
Networks: []net.Network{net.Network_UDP},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -23,6 +23,7 @@ func (v *HTTPAccount) Build() *http.Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPServerConfig struct {
|
type HTTPServerConfig struct {
|
||||||
|
Users []*HTTPAccount `json:"users"`
|
||||||
Accounts []*HTTPAccount `json:"accounts"`
|
Accounts []*HTTPAccount `json:"accounts"`
|
||||||
Transparent bool `json:"allowTransparent"`
|
Transparent bool `json:"allowTransparent"`
|
||||||
UserLevel uint32 `json:"userLevel"`
|
UserLevel uint32 `json:"userLevel"`
|
||||||
@@ -34,9 +35,13 @@ func (c *HTTPServerConfig) Build() (proto.Message, error) {
|
|||||||
UserLevel: c.UserLevel,
|
UserLevel: c.UserLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.Accounts) > 0 {
|
if c.Accounts != nil {
|
||||||
|
c.Users = c.Accounts
|
||||||
|
}
|
||||||
|
// TODO: PB
|
||||||
|
if len(c.Users) > 0 {
|
||||||
config.Accounts = make(map[string]string)
|
config.Accounts = make(map[string]string)
|
||||||
for _, account := range c.Accounts {
|
for _, account := range c.Users {
|
||||||
config.Accounts[account.Username] = account.Password
|
config.Accounts[account.Username] = account.Password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,8 +56,8 @@ type HTTPRemoteConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPClientConfig struct {
|
type HTTPClientConfig struct {
|
||||||
Address *Address `json:"address"`
|
Address *Address `json:"address"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
Level uint32 `json:"level"`
|
Level uint32 `json:"level"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Username string `json:"user"`
|
Username string `json:"user"`
|
||||||
|
|||||||
+18
-7
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/proxy/hysteria"
|
"github.com/xtls/xray-core/proxy/hysteria"
|
||||||
"github.com/xtls/xray-core/proxy/hysteria/account"
|
"github.com/xtls/xray-core/proxy/hysteria/account"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
@@ -38,22 +39,32 @@ type HysteriaUserConfig struct {
|
|||||||
|
|
||||||
type HysteriaServerConfig struct {
|
type HysteriaServerConfig struct {
|
||||||
Version int32 `json:"version"`
|
Version int32 `json:"version"`
|
||||||
Users []*HysteriaUserConfig `json:"clients"`
|
Users []*HysteriaUserConfig `json:"users"`
|
||||||
|
Clients []*HysteriaUserConfig `json:"clients"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HysteriaServerConfig) Build() (proto.Message, error) {
|
func (c *HysteriaServerConfig) Build() (proto.Message, error) {
|
||||||
config := new(hysteria.ServerConfig)
|
config := new(hysteria.ServerConfig)
|
||||||
|
|
||||||
if c.Users != nil {
|
if c.Clients != nil {
|
||||||
for _, user := range c.Users {
|
c.Users = c.Clients
|
||||||
account := &account.Account{
|
}
|
||||||
|
if len(c.Users) > 0 {
|
||||||
|
config.Users = make([]*protocol.User, len(c.Users))
|
||||||
|
processUser := func(idx int) error {
|
||||||
|
user := c.Users[idx]
|
||||||
|
acc := &account.Account{
|
||||||
Auth: user.Auth,
|
Auth: user.Auth,
|
||||||
}
|
}
|
||||||
config.Users = append(config.Users, &protocol.User{
|
config.Users[idx] = &protocol.User{
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Level: user.Level,
|
Level: user.Level,
|
||||||
Account: serial.ToTypedMessage(account),
|
Account: serial.ToTypedMessage(acc),
|
||||||
})
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := task.ParallelForN(len(c.Users), processUser); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,22 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/platform"
|
||||||
creflect "github.com/xtls/xray-core/common/reflect"
|
creflect "github.com/xtls/xray-core/common/reflect"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/infra/conf"
|
"github.com/xtls/xray-core/infra/conf"
|
||||||
"github.com/xtls/xray-core/main/confloader"
|
"github.com/xtls/xray-core/main/confloader"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UseStrictJSON, when true, makes JSON config decoders skip the custom
|
||||||
|
// comment-stripping reader and parse input as strict RFC 8259 JSON.
|
||||||
|
//
|
||||||
|
// Enabled by setting the env variable xray.json.strict=true (or its normalized
|
||||||
|
// form XRAY_JSON_STRICT=true). Default false preserves backward-compatible
|
||||||
|
// behavior for human-edited configs that may contain comments or other
|
||||||
|
// JSON5/JSONC syntax.
|
||||||
|
var UseStrictJSON = platform.NewEnvFlag(platform.UseStrictJSON).GetValue(func() string { return "" }) == "true"
|
||||||
|
|
||||||
func MergeConfigFromFiles(files []*core.ConfigSource) (string, error) {
|
func MergeConfigFromFiles(files []*core.ConfigSource) (string, error) {
|
||||||
c, err := mergeConfigs(files)
|
c, err := mergeConfigs(files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -31,7 +41,11 @@ func mergeConfigs(files []*core.ConfigSource) (*conf.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to read config: ", file).Base(err)
|
return nil, errors.New("failed to read config: ", file).Base(err)
|
||||||
}
|
}
|
||||||
c, err := ReaderDecoderByFormat[file.Format](r)
|
decoder := ReaderDecoderByFormat[file.Format]
|
||||||
|
if file.Format == "json" && UseStrictJSON {
|
||||||
|
decoder = DecodeJSONConfigStrict
|
||||||
|
}
|
||||||
|
c, err := decoder(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to decode config: ", file).Base(err)
|
return nil, errors.New("failed to decode config: ", file).Base(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ func findOffset(b []byte, o int) *offset {
|
|||||||
|
|
||||||
// DecodeJSONConfig reads from reader and decode the config into *conf.Config
|
// DecodeJSONConfig reads from reader and decode the config into *conf.Config
|
||||||
// syntax error could be detected.
|
// syntax error could be detected.
|
||||||
|
//
|
||||||
|
// Permissive: accepts JSON with Java/Python-style comments via json_reader.Reader.
|
||||||
|
// Used for local files and stdin where the config is human-edited.
|
||||||
func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {
|
func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {
|
||||||
jsonConfig := &conf.Config{}
|
jsonConfig := &conf.Config{}
|
||||||
|
|
||||||
@@ -69,6 +72,24 @@ func DecodeJSONConfig(reader io.Reader) (*conf.Config, error) {
|
|||||||
return jsonConfig, nil
|
return jsonConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeJSONConfigStrict reads standard RFC 8259 JSON without comment-stripping.
|
||||||
|
// Used for remote sources (http/https/http+unix) where the payload is produced by
|
||||||
|
// automated systems and cannot contain JSON5/JSONC extensions. Avoids the
|
||||||
|
// byte-by-byte comment stripper and TeeReader, which are significant overhead on
|
||||||
|
// large configs.
|
||||||
|
func DecodeJSONConfigStrict(reader io.Reader) (*conf.Config, error) {
|
||||||
|
data, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to read config file").Base(err)
|
||||||
|
}
|
||||||
|
jsonConfig := &conf.Config{}
|
||||||
|
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||||
|
return nil, errors.New("failed to parse remote JSON config").Base(err)
|
||||||
|
}
|
||||||
|
return jsonConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
|
func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
|
||||||
jsonConfig, err := DecodeJSONConfig(reader)
|
jsonConfig, err := DecodeJSONConfig(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+40
-20
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/proxy/shadowsocks"
|
"github.com/xtls/xray-core/proxy/shadowsocks"
|
||||||
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
@@ -44,13 +45,18 @@ type ShadowsocksServerConfig struct {
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Level byte `json:"level"`
|
Level byte `json:"level"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Users []*ShadowsocksUserConfig `json:"clients"`
|
Users []*ShadowsocksUserConfig `json:"users"`
|
||||||
|
Clients []*ShadowsocksUserConfig `json:"clients"`
|
||||||
NetworkList *NetworkList `json:"network"`
|
NetworkList *NetworkList `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
||||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
|
||||||
|
|
||||||
|
if v.Clients != nil {
|
||||||
|
v.Users = v.Clients
|
||||||
|
}
|
||||||
|
|
||||||
if C.Contains(shadowaead_2022.List, v.Cipher) {
|
if C.Contains(shadowaead_2022.List, v.Cipher) {
|
||||||
return buildShadowsocks2022(v)
|
return buildShadowsocks2022(v)
|
||||||
}
|
}
|
||||||
@@ -59,23 +65,31 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
|
|||||||
config.Network = v.NetworkList.Build()
|
config.Network = v.NetworkList.Build()
|
||||||
|
|
||||||
if v.Users != nil {
|
if v.Users != nil {
|
||||||
for _, user := range v.Users {
|
if len(v.Users) > 0 {
|
||||||
account := &shadowsocks.Account{
|
config.Users = make([]*protocol.User, len(v.Users))
|
||||||
Password: user.Password,
|
processUser := func(idx int) error {
|
||||||
CipherType: cipherFromString(user.Cipher),
|
user := v.Users[idx]
|
||||||
|
account := &shadowsocks.Account{
|
||||||
|
Password: user.Password,
|
||||||
|
CipherType: cipherFromString(user.Cipher),
|
||||||
|
}
|
||||||
|
if account.Password == "" {
|
||||||
|
return errors.New("Shadowsocks password is not specified.")
|
||||||
|
}
|
||||||
|
if account.CipherType < shadowsocks.CipherType_AES_128_GCM ||
|
||||||
|
account.CipherType > shadowsocks.CipherType_XCHACHA20_POLY1305 {
|
||||||
|
return errors.New("unsupported cipher method: ", user.Cipher)
|
||||||
|
}
|
||||||
|
config.Users[idx] = &protocol.User{
|
||||||
|
Email: user.Email,
|
||||||
|
Level: uint32(user.Level),
|
||||||
|
Account: serial.ToTypedMessage(account),
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if account.Password == "" {
|
if err := task.ParallelForN(len(v.Users), processUser); err != nil {
|
||||||
return nil, errors.New("Shadowsocks password is not specified.")
|
return nil, err
|
||||||
}
|
}
|
||||||
if account.CipherType < shadowsocks.CipherType_AES_128_GCM ||
|
|
||||||
account.CipherType > shadowsocks.CipherType_XCHACHA20_POLY1305 {
|
|
||||||
return nil, errors.New("unsupported cipher method: ", user.Cipher)
|
|
||||||
}
|
|
||||||
config.Users = append(config.Users, &protocol.User{
|
|
||||||
Email: user.Email,
|
|
||||||
Level: uint32(user.Level),
|
|
||||||
Account: serial.ToTypedMessage(account),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
account := &shadowsocks.Account{
|
account := &shadowsocks.Account{
|
||||||
@@ -121,18 +135,24 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
|
|||||||
config.Key = v.Password
|
config.Key = v.Password
|
||||||
config.Network = v.NetworkList.Build()
|
config.Network = v.NetworkList.Build()
|
||||||
|
|
||||||
for _, user := range v.Users {
|
config.Users = make([]*protocol.User, len(v.Users))
|
||||||
|
processUser := func(idx int) error {
|
||||||
|
user := v.Users[idx]
|
||||||
if user.Cipher != "" {
|
if user.Cipher != "" {
|
||||||
return nil, errors.New("shadowsocks 2022 (multi-user): users must have empty method")
|
return errors.New("shadowsocks 2022 (multi-user): users must have empty method")
|
||||||
}
|
}
|
||||||
account := &shadowsocks_2022.Account{
|
account := &shadowsocks_2022.Account{
|
||||||
Key: user.Password,
|
Key: user.Password,
|
||||||
}
|
}
|
||||||
config.Users = append(config.Users, &protocol.User{
|
config.Users[idx] = &protocol.User{
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Level: uint32(user.Level),
|
Level: uint32(user.Level),
|
||||||
Account: serial.ToTypedMessage(account),
|
Account: serial.ToTypedMessage(account),
|
||||||
})
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := task.ParallelForN(len(v.Users), processUser); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -29,6 +29,7 @@ const (
|
|||||||
|
|
||||||
type SocksServerConfig struct {
|
type SocksServerConfig struct {
|
||||||
AuthMethod string `json:"auth"`
|
AuthMethod string `json:"auth"`
|
||||||
|
Users []*SocksAccount `json:"users"`
|
||||||
Accounts []*SocksAccount `json:"accounts"`
|
Accounts []*SocksAccount `json:"accounts"`
|
||||||
UDP bool `json:"udp"`
|
UDP bool `json:"udp"`
|
||||||
Host *Address `json:"ip"`
|
Host *Address `json:"ip"`
|
||||||
@@ -47,9 +48,13 @@ func (v *SocksServerConfig) Build() (proto.Message, error) {
|
|||||||
config.AuthType = socks.AuthType_NO_AUTH
|
config.AuthType = socks.AuthType_NO_AUTH
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(v.Accounts) > 0 {
|
if v.Accounts != nil {
|
||||||
config.Accounts = make(map[string]string, len(v.Accounts))
|
v.Users = v.Accounts
|
||||||
for _, account := range v.Accounts {
|
}
|
||||||
|
// TODO: PB
|
||||||
|
if len(v.Users) > 0 {
|
||||||
|
config.Accounts = make(map[string]string, len(v.Users))
|
||||||
|
for _, account := range v.Users {
|
||||||
config.Accounts[account.Username] = account.Password
|
config.Accounts[account.Username] = account.Password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -497,8 +497,8 @@ func (b Bandwidth) Bps() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UdpHop struct {
|
type UdpHop struct {
|
||||||
PortList json.RawMessage `json:"ports"`
|
PortList PortList `json:"ports"`
|
||||||
Interval *Int32Range `json:"interval"`
|
Interval Int32Range `json:"interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Masquerade struct {
|
type Masquerade struct {
|
||||||
@@ -2142,18 +2142,7 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
||||||
}
|
}
|
||||||
|
|
||||||
var hop *PortList
|
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
|
||||||
if err := json.Unmarshal(c.FinalMask.QuicParams.UdpHop.PortList, &hop); err != nil {
|
|
||||||
hop = &PortList{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var inertvalMin, inertvalMax int64
|
|
||||||
if c.FinalMask.QuicParams.UdpHop.Interval != nil {
|
|
||||||
inertvalMin = int64(c.FinalMask.QuicParams.UdpHop.Interval.From)
|
|
||||||
inertvalMax = int64(c.FinalMask.QuicParams.UdpHop.Interval.To)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
|
|
||||||
return nil, errors.New("Interval must be at least 5")
|
return nil, errors.New("Interval must be at least 5")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2190,9 +2179,9 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
BrutalUp: up,
|
BrutalUp: up,
|
||||||
BrutalDown: down,
|
BrutalDown: down,
|
||||||
UdpHop: &internet.UdpHop{
|
UdpHop: &internet.UdpHop{
|
||||||
Ports: hop.Build().Ports(),
|
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
|
||||||
IntervalMin: inertvalMin,
|
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),
|
||||||
IntervalMax: inertvalMax,
|
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To),
|
||||||
},
|
},
|
||||||
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
||||||
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
||||||
|
|||||||
+15
-4
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/proxy/trojan"
|
"github.com/xtls/xray-core/proxy/trojan"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
@@ -111,6 +112,7 @@ type TrojanUserConfig struct {
|
|||||||
|
|
||||||
// TrojanServerConfig is Inbound configuration
|
// TrojanServerConfig is Inbound configuration
|
||||||
type TrojanServerConfig struct {
|
type TrojanServerConfig struct {
|
||||||
|
Users []*TrojanUserConfig `json:"users"`
|
||||||
Clients []*TrojanUserConfig `json:"clients"`
|
Clients []*TrojanUserConfig `json:"clients"`
|
||||||
Fallbacks []*TrojanInboundFallback `json:"fallbacks"`
|
Fallbacks []*TrojanInboundFallback `json:"fallbacks"`
|
||||||
}
|
}
|
||||||
@@ -119,13 +121,18 @@ type TrojanServerConfig struct {
|
|||||||
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||||
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
|
||||||
|
|
||||||
config := &trojan.ServerConfig{
|
if c.Clients != nil {
|
||||||
Users: make([]*protocol.User, len(c.Clients)),
|
c.Users = c.Clients
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, rawUser := range c.Clients {
|
config := &trojan.ServerConfig{
|
||||||
|
Users: make([]*protocol.User, len(c.Users)),
|
||||||
|
}
|
||||||
|
|
||||||
|
processClient := func(idx int) error {
|
||||||
|
rawUser := c.Users[idx]
|
||||||
if rawUser.Flow != "" {
|
if rawUser.Flow != "" {
|
||||||
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
|
return errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Users[idx] = &protocol.User{
|
config.Users[idx] = &protocol.User{
|
||||||
@@ -135,6 +142,10 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
|||||||
Password: rawUser.Password,
|
Password: rawUser.Password,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := task.ParallelForN(len(c.Users), processClient); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fb := range c.Fallbacks {
|
for _, fb := range c.Fallbacks {
|
||||||
|
|||||||
+22
-10
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
"github.com/xtls/xray-core/proxy/vless/inbound"
|
"github.com/xtls/xray-core/proxy/vless/inbound"
|
||||||
@@ -30,6 +31,7 @@ type VLessInboundFallback struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VLessInboundConfig struct {
|
type VLessInboundConfig struct {
|
||||||
|
Users []json.RawMessage `json:"users"`
|
||||||
Clients []json.RawMessage `json:"clients"`
|
Clients []json.RawMessage `json:"clients"`
|
||||||
Decryption string `json:"decryption"`
|
Decryption string `json:"decryption"`
|
||||||
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
|
Fallbacks []*VLessInboundFallback `json:"fallbacks"`
|
||||||
@@ -40,25 +42,30 @@ type VLessInboundConfig struct {
|
|||||||
// Build implements Buildable
|
// Build implements Buildable
|
||||||
func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||||
config := new(inbound.Config)
|
config := new(inbound.Config)
|
||||||
config.Clients = make([]*protocol.User, len(c.Clients))
|
|
||||||
|
if c.Clients != nil {
|
||||||
|
c.Users = c.Clients
|
||||||
|
}
|
||||||
|
config.Users = make([]*protocol.User, len(c.Users))
|
||||||
switch c.Flow {
|
switch c.Flow {
|
||||||
case vless.XRV, "":
|
case vless.XRV, "":
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
|
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
|
||||||
}
|
}
|
||||||
for idx, rawUser := range c.Clients {
|
processClient := func(idx int) error {
|
||||||
|
rawUser := c.Users[idx]
|
||||||
user := new(protocol.User)
|
user := new(protocol.User)
|
||||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||||
return nil, errors.New(`VLESS clients: invalid user`).Base(err)
|
return errors.New(`VLESS users: invalid user`).Base(err)
|
||||||
}
|
}
|
||||||
account := new(vless.Account)
|
account := new(vless.Account)
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New(`VLESS clients: invalid user`).Base(err)
|
return errors.New(`VLESS users: invalid user`).Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := uuid.ParseString(account.Id)
|
u, err := uuid.ParseString(account.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
account.Id = u.String()
|
account.Id = u.String()
|
||||||
|
|
||||||
@@ -67,7 +74,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
account.Flow = c.Flow
|
account.Flow = c.Flow
|
||||||
case vless.XRV:
|
case vless.XRV:
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
return errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(account.Testseed) < 4 {
|
if len(account.Testseed) < 4 {
|
||||||
@@ -75,20 +82,25 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if account.Encryption != "" {
|
if account.Encryption != "" {
|
||||||
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
|
return errors.New(`VLESS users: "encryption" should not be in inbound settings`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if account.Reverse != nil {
|
if account.Reverse != nil {
|
||||||
if account.Reverse.Tag == "" {
|
if account.Reverse.Tag == "" {
|
||||||
return nil, errors.New(`VLESS clients: "tag" can't be empty for "reverse"`)
|
return errors.New(`VLESS users: "tag" can't be empty for "reverse"`)
|
||||||
}
|
}
|
||||||
if account.Reverse.Sniffing != nil { // may not be reached: error json unmarshal
|
if account.Reverse.Sniffing != nil { // may not be reached: error json unmarshal
|
||||||
return nil, errors.New(`VLESS clients: inbound's "reverse" can't have "sniffing"`)
|
return errors.New(`VLESS users: inbound's "reverse" can't have "sniffing"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Account = serial.ToTypedMessage(account)
|
user.Account = serial.ToTypedMessage(account)
|
||||||
config.Clients[idx] = user
|
config.Users[idx] = user
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.ParallelForN(len(c.Users), processClient); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Decryption = c.Decryption
|
config.Decryption = c.Decryption
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func TestVLessInbound(t *testing.T) {
|
|||||||
}`,
|
}`,
|
||||||
Parser: loadJSON(creator),
|
Parser: loadJSON(creator),
|
||||||
Output: &inbound.Config{
|
Output: &inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
|
||||||
|
|||||||
+15
-5
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"github.com/xtls/xray-core/proxy/vmess"
|
"github.com/xtls/xray-core/proxy/vmess"
|
||||||
"github.com/xtls/xray-core/proxy/vmess/inbound"
|
"github.com/xtls/xray-core/proxy/vmess/inbound"
|
||||||
@@ -58,7 +59,8 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VMessInboundConfig struct {
|
type VMessInboundConfig struct {
|
||||||
Users []json.RawMessage `json:"clients"`
|
Users []json.RawMessage `json:"users"`
|
||||||
|
Clients []json.RawMessage `json:"clients"`
|
||||||
Defaults *VMessDefaultConfig `json:"default"`
|
Defaults *VMessDefaultConfig `json:"default"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,25 +74,33 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
|
|||||||
config.Default = c.Defaults.Build()
|
config.Default = c.Defaults.Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Clients != nil {
|
||||||
|
c.Users = c.Clients
|
||||||
|
}
|
||||||
config.User = make([]*protocol.User, len(c.Users))
|
config.User = make([]*protocol.User, len(c.Users))
|
||||||
for idx, rawData := range c.Users {
|
processUser := func(idx int) error {
|
||||||
|
rawData := c.Users[idx]
|
||||||
user := new(protocol.User)
|
user := new(protocol.User)
|
||||||
if err := json.Unmarshal(rawData, user); err != nil {
|
if err := json.Unmarshal(rawData, user); err != nil {
|
||||||
return nil, errors.New("invalid VMess user").Base(err)
|
return errors.New("invalid VMess user").Base(err)
|
||||||
}
|
}
|
||||||
account := new(VMessAccount)
|
account := new(VMessAccount)
|
||||||
if err := json.Unmarshal(rawData, account); err != nil {
|
if err := json.Unmarshal(rawData, account); err != nil {
|
||||||
return nil, errors.New("invalid VMess user").Base(err)
|
return errors.New("invalid VMess user").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := uuid.ParseString(account.ID)
|
u, err := uuid.ParseString(account.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
account.ID = u.String()
|
account.ID = u.String()
|
||||||
|
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
config.User[idx] = user
|
config.User[idx] = user
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := task.ParallelForN(len(c.Users), processUser); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func extractInboundUsers(inb *core.InboundHandlerConfig) []*protocol.User {
|
|||||||
case *vmessin.Config:
|
case *vmessin.Config:
|
||||||
return ty.User
|
return ty.User
|
||||||
case *vlessin.Config:
|
case *vlessin.Config:
|
||||||
return ty.Clients
|
return ty.Users
|
||||||
case *trojan.ServerConfig:
|
case *trojan.ServerConfig:
|
||||||
return ty.Users
|
return ty.Users
|
||||||
case *shadowsocks.ServerConfig:
|
case *shadowsocks.ServerConfig:
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ func init() {
|
|||||||
}
|
}
|
||||||
return cf.Build()
|
return cf.Build()
|
||||||
case io.Reader:
|
case io.Reader:
|
||||||
|
if serial.UseStrictJSON {
|
||||||
|
cfg, err := serial.DecodeJSONConfigStrict(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cfg.Build()
|
||||||
|
}
|
||||||
return serial.LoadJSONConfig(v)
|
return serial.LoadJSONConfig(v)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unknown type")
|
return nil, errors.New("unknown type")
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/buf"
|
||||||
|
"github.com/xtls/xray-core/common/dice"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/common/signal"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
)
|
)
|
||||||
@@ -38,7 +42,17 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
// Sleep a little here to make sure the response is sent to client.
|
// Sleep a little here to make sure the response is sent to client.
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
common.Interrupt(link.Writer)
|
defer common.Interrupt(link.Writer)
|
||||||
|
defer common.Interrupt(link.Reader)
|
||||||
|
// wait to drain all the possible incoming UDP data
|
||||||
|
if ob.Target.Network == net.Network_UDP {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
timer := signal.CancelAfterInactivity(ctx, func() {
|
||||||
|
cancel()
|
||||||
|
}, time.Duration(30+dice.Roll(61))*time.Second)
|
||||||
|
go buf.Copy(link.Reader, buf.Discard, buf.UpdateActivity(timer))
|
||||||
|
<-ctx.Done()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ type Config struct {
|
|||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
UserLevel uint32 `protobuf:"varint,1,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
UserLevel uint32 `protobuf:"varint,1,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||||
Rule []*DNSRuleConfig `protobuf:"bytes,2,rep,name=rule,proto3" json:"rule,omitempty"`
|
Rule []*DNSRuleConfig `protobuf:"bytes,2,rep,name=rule,proto3" json:"rule,omitempty"`
|
||||||
Server *net.Endpoint `protobuf:"bytes,3,opt,name=server,proto3" json:"server,omitempty"`
|
RewriteServer *net.Endpoint `protobuf:"bytes,3,opt,name=rewrite_server,json=rewriteServer,proto3" json:"rewrite_server,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -188,9 +188,9 @@ func (x *Config) GetRule() []*DNSRuleConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetServer() *net.Endpoint {
|
func (x *Config) GetRewriteServer() *net.Endpoint {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Server
|
return x.RewriteServer
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -203,12 +203,12 @@ const file_proxy_dns_config_proto_rawDesc = "" +
|
|||||||
"\rDNSRuleConfig\x122\n" +
|
"\rDNSRuleConfig\x122\n" +
|
||||||
"\x06action\x18\x01 \x01(\x0e2\x1a.xray.proxy.dns.RuleActionR\x06action\x12\x14\n" +
|
"\x06action\x18\x01 \x01(\x0e2\x1a.xray.proxy.dns.RuleActionR\x06action\x12\x14\n" +
|
||||||
"\x05qtype\x18\x02 \x03(\x05R\x05qtype\x127\n" +
|
"\x05qtype\x18\x02 \x03(\x05R\x05qtype\x127\n" +
|
||||||
"\x06domain\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x06domain\"\x8d\x01\n" +
|
"\x06domain\x18\x03 \x03(\v2\x1f.xray.common.geodata.DomainRuleR\x06domain\"\x9c\x01\n" +
|
||||||
"\x06Config\x12\x1d\n" +
|
"\x06Config\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"user_level\x18\x01 \x01(\rR\tuserLevel\x121\n" +
|
"user_level\x18\x01 \x01(\rR\tuserLevel\x121\n" +
|
||||||
"\x04rule\x18\x02 \x03(\v2\x1d.xray.proxy.dns.DNSRuleConfigR\x04rule\x121\n" +
|
"\x04rule\x18\x02 \x03(\v2\x1d.xray.proxy.dns.DNSRuleConfigR\x04rule\x12@\n" +
|
||||||
"\x06server\x18\x03 \x01(\v2\x19.xray.common.net.EndpointR\x06server*:\n" +
|
"\x0erewrite_server\x18\x03 \x01(\v2\x19.xray.common.net.EndpointR\rrewriteServer*:\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"RuleAction\x12\n" +
|
"RuleAction\x12\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
@@ -245,7 +245,7 @@ var file_proxy_dns_config_proto_depIdxs = []int32{
|
|||||||
0, // 0: xray.proxy.dns.DNSRuleConfig.action:type_name -> xray.proxy.dns.RuleAction
|
0, // 0: xray.proxy.dns.DNSRuleConfig.action:type_name -> xray.proxy.dns.RuleAction
|
||||||
3, // 1: xray.proxy.dns.DNSRuleConfig.domain:type_name -> xray.common.geodata.DomainRule
|
3, // 1: xray.proxy.dns.DNSRuleConfig.domain:type_name -> xray.common.geodata.DomainRule
|
||||||
1, // 2: xray.proxy.dns.Config.rule:type_name -> xray.proxy.dns.DNSRuleConfig
|
1, // 2: xray.proxy.dns.Config.rule:type_name -> xray.proxy.dns.DNSRuleConfig
|
||||||
4, // 3: xray.proxy.dns.Config.server:type_name -> xray.common.net.Endpoint
|
4, // 3: xray.proxy.dns.Config.rewrite_server:type_name -> xray.common.net.Endpoint
|
||||||
4, // [4:4] is the sub-list for method output_type
|
4, // [4:4] is the sub-list for method output_type
|
||||||
4, // [4:4] is the sub-list for method input_type
|
4, // [4:4] is the sub-list for method input_type
|
||||||
4, // [4:4] is the sub-list for extension type_name
|
4, // [4:4] is the sub-list for extension type_name
|
||||||
|
|||||||
@@ -25,5 +25,5 @@ message DNSRuleConfig {
|
|||||||
message Config {
|
message Config {
|
||||||
uint32 user_level = 1;
|
uint32 user_level = 1;
|
||||||
repeated DNSRuleConfig rule = 2;
|
repeated DNSRuleConfig rule = 2;
|
||||||
xray.common.net.Endpoint server = 3;
|
xray.common.net.Endpoint rewrite_server = 3;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -74,7 +74,7 @@ type Handler struct {
|
|||||||
client dns.Client
|
client dns.Client
|
||||||
fdns dns.FakeDNSEngine
|
fdns dns.FakeDNSEngine
|
||||||
ownLinkVerifier ownLinkVerifier
|
ownLinkVerifier ownLinkVerifier
|
||||||
server net.Destination
|
rewriteServer net.Destination
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
rules []*DNSRule
|
rules []*DNSRule
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,8 @@ func (h *Handler) Init(config *Config, dnsClient dns.Client, policyManager polic
|
|||||||
h.ownLinkVerifier = v
|
h.ownLinkVerifier = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Server != nil {
|
if config.RewriteServer != nil {
|
||||||
h.server = config.Server.AsDestination()
|
h.rewriteServer = config.RewriteServer.AsDestination()
|
||||||
}
|
}
|
||||||
|
|
||||||
h.rules = make([]*DNSRule, 0, len(config.Rule))
|
h.rules = make([]*DNSRule, 0, len(config.Rule))
|
||||||
@@ -161,14 +161,14 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||||||
srcNetwork := ob.Target.Network
|
srcNetwork := ob.Target.Network
|
||||||
|
|
||||||
dest := ob.Target
|
dest := ob.Target
|
||||||
if h.server.Network != net.Network_Unknown {
|
if h.rewriteServer.Network != net.Network_Unknown {
|
||||||
dest.Network = h.server.Network
|
dest.Network = h.rewriteServer.Network
|
||||||
}
|
}
|
||||||
if h.server.Address != nil {
|
if h.rewriteServer.Address != nil {
|
||||||
dest.Address = h.server.Address
|
dest.Address = h.rewriteServer.Address
|
||||||
}
|
}
|
||||||
if h.server.Port != 0 {
|
if h.rewriteServer.Port != 0 {
|
||||||
dest.Port = h.server.Port
|
dest.Port = h.rewriteServer.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(ctx, "handling DNS traffic to ", dest)
|
errors.LogInfo(ctx, "handling DNS traffic to ", dest)
|
||||||
|
|||||||
+13
-13
@@ -114,9 +114,9 @@ func TestUDPDNSTunnel(t *testing.T) {
|
|||||||
Inbound: []*core.InboundHandlerConfig{
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(port),
|
RewritePort: uint32(port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
||||||
@@ -233,9 +233,9 @@ func TestTCPDNSTunnel(t *testing.T) {
|
|||||||
Inbound: []*core.InboundHandlerConfig{
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(port),
|
RewritePort: uint32(port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
||||||
@@ -319,9 +319,9 @@ func TestUDP2TCPDNSTunnel(t *testing.T) {
|
|||||||
Inbound: []*core.InboundHandlerConfig{
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(port),
|
RewritePort: uint32(port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
||||||
@@ -332,7 +332,7 @@ func TestUDP2TCPDNSTunnel(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{
|
ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{
|
||||||
Server: &net.Endpoint{
|
RewriteServer: &net.Endpoint{
|
||||||
Network: net.Network_TCP,
|
Network: net.Network_TCP,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -409,9 +409,9 @@ func TestDNSRules(t *testing.T) {
|
|||||||
Inbound: []*core.InboundHandlerConfig{
|
Inbound: []*core.InboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(port),
|
RewritePort: uint32(port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
// GetPredefinedAddress returns the defined address from proto config. Null if address is not valid.
|
// GetPredefinedAddress returns the defined address from proto config. Null if address is not valid.
|
||||||
func (v *Config) GetPredefinedAddress() net.Address {
|
func (v *Config) GetPredefinedAddress() net.Address {
|
||||||
addr := v.Address.AsAddress()
|
addr := v.RewriteAddress.AsAddress()
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-23
@@ -23,16 +23,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
|
RewriteAddress *net.IPOrDomain `protobuf:"bytes,1,opt,name=rewrite_address,json=rewriteAddress,proto3" json:"rewrite_address,omitempty"`
|
||||||
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
|
RewritePort uint32 `protobuf:"varint,2,opt,name=rewrite_port,json=rewritePort,proto3" json:"rewrite_port,omitempty"`
|
||||||
PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||||
// List of networks that the Dokodemo accepts.
|
// List of networks that the Dokodemo accepts.
|
||||||
Networks []net.Network `protobuf:"varint,7,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
|
AllowedNetworks []net.Network `protobuf:"varint,7,rep,packed,name=allowed_networks,json=allowedNetworks,proto3,enum=xray.common.net.Network" json:"allowed_networks,omitempty"`
|
||||||
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
||||||
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -65,16 +65,16 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}
|
return file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetAddress() *net.IPOrDomain {
|
func (x *Config) GetRewriteAddress() *net.IPOrDomain {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Address
|
return x.RewriteAddress
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetPort() uint32 {
|
func (x *Config) GetRewritePort() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Port
|
return x.RewritePort
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -86,9 +86,9 @@ func (x *Config) GetPortMap() map[string]string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetNetworks() []net.Network {
|
func (x *Config) GetAllowedNetworks() []net.Network {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Networks
|
return x.AllowedNetworks
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -111,12 +111,12 @@ var File_proxy_dokodemo_config_proto protoreflect.FileDescriptor
|
|||||||
|
|
||||||
const file_proxy_dokodemo_config_proto_rawDesc = "" +
|
const file_proxy_dokodemo_config_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x1bproxy/dokodemo/config.proto\x12\x13xray.proxy.dokodemo\x1a\x18common/net/address.proto\x1a\x18common/net/network.proto\"\xd2\x02\n" +
|
"\x1bproxy/dokodemo/config.proto\x12\x13xray.proxy.dokodemo\x1a\x18common/net/address.proto\x1a\x18common/net/network.proto\"\xff\x02\n" +
|
||||||
"\x06Config\x125\n" +
|
"\x06Config\x12D\n" +
|
||||||
"\aaddress\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\aaddress\x12\x12\n" +
|
"\x0frewrite_address\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x0erewriteAddress\x12!\n" +
|
||||||
"\x04port\x18\x02 \x01(\rR\x04port\x12C\n" +
|
"\frewrite_port\x18\x02 \x01(\rR\vrewritePort\x12C\n" +
|
||||||
"\bport_map\x18\x03 \x03(\v2(.xray.proxy.dokodemo.Config.PortMapEntryR\aportMap\x124\n" +
|
"\bport_map\x18\x03 \x03(\v2(.xray.proxy.dokodemo.Config.PortMapEntryR\aportMap\x12C\n" +
|
||||||
"\bnetworks\x18\a \x03(\x0e2\x18.xray.common.net.NetworkR\bnetworks\x12'\n" +
|
"\x10allowed_networks\x18\a \x03(\x0e2\x18.xray.common.net.NetworkR\x0fallowedNetworks\x12'\n" +
|
||||||
"\x0ffollow_redirect\x18\x05 \x01(\bR\x0efollowRedirect\x12\x1d\n" +
|
"\x0ffollow_redirect\x18\x05 \x01(\bR\x0efollowRedirect\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"user_level\x18\x06 \x01(\rR\tuserLevel\x1a:\n" +
|
"user_level\x18\x06 \x01(\rR\tuserLevel\x1a:\n" +
|
||||||
@@ -145,9 +145,9 @@ var file_proxy_dokodemo_config_proto_goTypes = []any{
|
|||||||
(net.Network)(0), // 3: xray.common.net.Network
|
(net.Network)(0), // 3: xray.common.net.Network
|
||||||
}
|
}
|
||||||
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.proxy.dokodemo.Config.address:type_name -> xray.common.net.IPOrDomain
|
2, // 0: xray.proxy.dokodemo.Config.rewrite_address:type_name -> xray.common.net.IPOrDomain
|
||||||
1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
||||||
3, // 2: xray.proxy.dokodemo.Config.networks:type_name -> xray.common.net.Network
|
3, // 2: xray.proxy.dokodemo.Config.allowed_networks:type_name -> xray.common.net.Network
|
||||||
3, // [3:3] is the sub-list for method output_type
|
3, // [3:3] is the sub-list for method output_type
|
||||||
3, // [3:3] is the sub-list for method input_type
|
3, // [3:3] is the sub-list for method input_type
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
|
|||||||
@@ -10,14 +10,11 @@ import "common/net/address.proto";
|
|||||||
import "common/net/network.proto";
|
import "common/net/network.proto";
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
xray.common.net.IPOrDomain address = 1;
|
|
||||||
uint32 port = 2;
|
|
||||||
|
|
||||||
map<string, string> port_map = 3;
|
|
||||||
|
|
||||||
// List of networks that the Dokodemo accepts.
|
// List of networks that the Dokodemo accepts.
|
||||||
repeated xray.common.net.Network networks = 7;
|
repeated xray.common.net.Network allowed_networks = 7;
|
||||||
|
xray.common.net.IPOrDomain rewrite_address = 1;
|
||||||
|
uint32 rewrite_port = 2;
|
||||||
|
map<string, string> port_map = 3;
|
||||||
bool follow_redirect = 5;
|
bool follow_redirect = 5;
|
||||||
uint32 user_level = 6;
|
uint32 user_level = 6;
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -32,22 +32,22 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DokodemoDoor struct {
|
type DokodemoDoor struct {
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
config *Config
|
config *Config
|
||||||
address net.Address
|
rewriteAddress net.Address
|
||||||
port net.Port
|
rewritePort net.Port
|
||||||
portMap map[string]string
|
portMap map[string]string
|
||||||
sockopt *session.Sockopt
|
sockopt *session.Sockopt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the DokodemoDoor instance with necessary parameters.
|
// Init initializes the DokodemoDoor instance with necessary parameters.
|
||||||
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
|
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
|
||||||
if len(config.Networks) == 0 {
|
if len(config.AllowedNetworks) == 0 {
|
||||||
return errors.New("no network specified")
|
return errors.New("no network specified")
|
||||||
}
|
}
|
||||||
d.config = config
|
d.config = config
|
||||||
d.address = config.GetPredefinedAddress()
|
d.rewriteAddress = config.GetPredefinedAddress()
|
||||||
d.port = net.Port(config.Port)
|
d.rewritePort = net.Port(config.RewritePort)
|
||||||
d.portMap = config.PortMap
|
d.portMap = config.PortMap
|
||||||
d.policyManager = pm
|
d.policyManager = pm
|
||||||
d.sockopt = sockopt
|
d.sockopt = sockopt
|
||||||
@@ -57,10 +57,10 @@ func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.
|
|||||||
|
|
||||||
// Network implements proxy.Inbound.
|
// Network implements proxy.Inbound.
|
||||||
func (d *DokodemoDoor) Network() []net.Network {
|
func (d *DokodemoDoor) Network() []net.Network {
|
||||||
if slices.Contains(d.config.Networks, net.Network_TCP) {
|
if slices.Contains(d.config.AllowedNetworks, net.Network_TCP) {
|
||||||
return append(d.config.Networks, net.Network_UNIX)
|
return append(d.config.AllowedNetworks, net.Network_UNIX)
|
||||||
}
|
}
|
||||||
return d.config.Networks
|
return d.config.AllowedNetworks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DokodemoDoor) policy() policy.Session {
|
func (d *DokodemoDoor) policy() policy.Session {
|
||||||
@@ -78,8 +78,8 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||||||
}
|
}
|
||||||
dest := net.Destination{
|
dest := net.Destination{
|
||||||
Network: network,
|
Network: network,
|
||||||
Address: d.address,
|
Address: d.rewriteAddress,
|
||||||
Port: d.port,
|
Port: d.rewritePort,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !d.config.FollowRedirect {
|
if !d.config.FollowRedirect {
|
||||||
@@ -95,7 +95,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dest.Port == 0 {
|
if dest.Port == 0 && port != "" {
|
||||||
dest.Port = net.Port(common.Must2(strconv.Atoi(port)))
|
dest.Port = net.Port(common.Must2(strconv.Atoi(port)))
|
||||||
}
|
}
|
||||||
if d.portMap != nil && d.portMap[port] != "" {
|
if d.portMap != nil && d.portMap[port] != "" {
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
package freedom
|
|
||||||
+200
-49
@@ -8,6 +8,7 @@ package freedom
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
geodata "github.com/xtls/xray-core/common/geodata"
|
geodata "github.com/xtls/xray-core/common/geodata"
|
||||||
|
net "github.com/xtls/xray-core/common/net"
|
||||||
protocol "github.com/xtls/xray-core/common/protocol"
|
protocol "github.com/xtls/xray-core/common/protocol"
|
||||||
internet "github.com/xtls/xray-core/transport/internet"
|
internet "github.com/xtls/xray-core/transport/internet"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
@@ -24,6 +25,52 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RuleAction int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
RuleAction_Allow RuleAction = 0
|
||||||
|
RuleAction_Block RuleAction = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for RuleAction.
|
||||||
|
var (
|
||||||
|
RuleAction_name = map[int32]string{
|
||||||
|
0: "Allow",
|
||||||
|
1: "Block",
|
||||||
|
}
|
||||||
|
RuleAction_value = map[string]int32{
|
||||||
|
"Allow": 0,
|
||||||
|
"Block": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x RuleAction) Enum() *RuleAction {
|
||||||
|
p := new(RuleAction)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x RuleAction) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (RuleAction) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_proxy_freedom_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (RuleAction) Type() protoreflect.EnumType {
|
||||||
|
return &file_proxy_freedom_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x RuleAction) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RuleAction.Descriptor instead.
|
||||||
|
func (RuleAction) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
type DestinationOverride struct {
|
type DestinationOverride struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
||||||
@@ -252,27 +299,28 @@ func (x *Noise) GetApplyTo() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type IPRules struct {
|
type Range struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Rules []*geodata.IPRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"`
|
Min uint64 `protobuf:"varint,1,opt,name=min,proto3" json:"min,omitempty"`
|
||||||
|
Max uint64 `protobuf:"varint,2,opt,name=max,proto3" json:"max,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IPRules) Reset() {
|
func (x *Range) Reset() {
|
||||||
*x = IPRules{}
|
*x = Range{}
|
||||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IPRules) String() string {
|
func (x *Range) String() string {
|
||||||
return protoimpl.X.MessageStringOf(x)
|
return protoimpl.X.MessageStringOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*IPRules) ProtoMessage() {}
|
func (*Range) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *IPRules) ProtoReflect() protoreflect.Message {
|
func (x *Range) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
mi := &file_proxy_freedom_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
@@ -284,14 +332,97 @@ func (x *IPRules) ProtoReflect() protoreflect.Message {
|
|||||||
return mi.MessageOf(x)
|
return mi.MessageOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use IPRules.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Range.ProtoReflect.Descriptor instead.
|
||||||
func (*IPRules) Descriptor() ([]byte, []int) {
|
func (*Range) Descriptor() ([]byte, []int) {
|
||||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *IPRules) GetRules() []*geodata.IPRule {
|
func (x *Range) GetMin() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Rules
|
return x.Min
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Range) GetMax() uint64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Max
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type FinalRuleConfig struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Action RuleAction `protobuf:"varint,1,opt,name=action,proto3,enum=xray.proxy.freedom.RuleAction" json:"action,omitempty"`
|
||||||
|
Networks []net.Network `protobuf:"varint,2,rep,packed,name=networks,proto3,enum=xray.common.net.Network" json:"networks,omitempty"`
|
||||||
|
PortList *net.PortList `protobuf:"bytes,3,opt,name=port_list,json=portList,proto3" json:"port_list,omitempty"`
|
||||||
|
Ip []*geodata.IPRule `protobuf:"bytes,4,rep,name=ip,proto3" json:"ip,omitempty"`
|
||||||
|
BlockDelay *Range `protobuf:"bytes,5,opt,name=block_delay,json=blockDelay,proto3" json:"block_delay,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) Reset() {
|
||||||
|
*x = FinalRuleConfig{}
|
||||||
|
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*FinalRuleConfig) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use FinalRuleConfig.ProtoReflect.Descriptor instead.
|
||||||
|
func (*FinalRuleConfig) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) GetAction() RuleAction {
|
||||||
|
if x != nil {
|
||||||
|
return x.Action
|
||||||
|
}
|
||||||
|
return RuleAction_Allow
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) GetNetworks() []net.Network {
|
||||||
|
if x != nil {
|
||||||
|
return x.Networks
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) GetPortList() *net.PortList {
|
||||||
|
if x != nil {
|
||||||
|
return x.PortList
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) GetIp() []*geodata.IPRule {
|
||||||
|
if x != nil {
|
||||||
|
return x.Ip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *FinalRuleConfig) GetBlockDelay() *Range {
|
||||||
|
if x != nil {
|
||||||
|
return x.BlockDelay
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -304,14 +435,14 @@ type Config struct {
|
|||||||
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
Fragment *Fragment `protobuf:"bytes,5,opt,name=fragment,proto3" json:"fragment,omitempty"`
|
||||||
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
ProxyProtocol uint32 `protobuf:"varint,6,opt,name=proxy_protocol,json=proxyProtocol,proto3" json:"proxy_protocol,omitempty"`
|
||||||
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
Noises []*Noise `protobuf:"bytes,7,rep,name=noises,proto3" json:"noises,omitempty"`
|
||||||
IpsBlocked *IPRules `protobuf:"bytes,8,opt,name=ips_blocked,json=ipsBlocked,proto3,oneof" json:"ips_blocked,omitempty"`
|
FinalRules []*FinalRuleConfig `protobuf:"bytes,8,rep,name=final_rules,json=finalRules,proto3" json:"final_rules,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
*x = Config{}
|
*x = Config{}
|
||||||
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
mi := &file_proxy_freedom_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -323,7 +454,7 @@ func (x *Config) String() string {
|
|||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proxy_freedom_config_proto_msgTypes[4]
|
mi := &file_proxy_freedom_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -336,7 +467,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{4}
|
return file_proxy_freedom_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetDomainStrategy() internet.DomainStrategy {
|
func (x *Config) GetDomainStrategy() internet.DomainStrategy {
|
||||||
@@ -381,9 +512,9 @@ func (x *Config) GetNoises() []*Noise {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetIpsBlocked() *IPRules {
|
func (x *Config) GetFinalRules() []*FinalRuleConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.IpsBlocked
|
return x.FinalRules
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -392,7 +523,7 @@ var File_proxy_freedom_config_proto protoreflect.FileDescriptor
|
|||||||
|
|
||||||
const file_proxy_freedom_config_proto_rawDesc = "" +
|
const file_proxy_freedom_config_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x1aproxy/freedom/config.proto\x12\x12xray.proxy.freedom\x1a!common/protocol/server_spec.proto\x1a\x1ftransport/internet/config.proto\x1a\x1bcommon/geodata/geodat.proto\"S\n" +
|
"\x1aproxy/freedom/config.proto\x12\x12xray.proxy.freedom\x1a!common/protocol/server_spec.proto\x1a\x1ftransport/internet/config.proto\x1a\x15common/net/port.proto\x1a\x18common/net/network.proto\x1a\x1bcommon/geodata/geodat.proto\"S\n" +
|
||||||
"\x13DestinationOverride\x12<\n" +
|
"\x13DestinationOverride\x12<\n" +
|
||||||
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server\"\x98\x02\n" +
|
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server\"\x98\x02\n" +
|
||||||
"\bFragment\x12!\n" +
|
"\bFragment\x12!\n" +
|
||||||
@@ -415,9 +546,17 @@ const file_proxy_freedom_config_proto_rawDesc = "" +
|
|||||||
"\tdelay_min\x18\x03 \x01(\x04R\bdelayMin\x12\x1b\n" +
|
"\tdelay_min\x18\x03 \x01(\x04R\bdelayMin\x12\x1b\n" +
|
||||||
"\tdelay_max\x18\x04 \x01(\x04R\bdelayMax\x12\x16\n" +
|
"\tdelay_max\x18\x04 \x01(\x04R\bdelayMax\x12\x16\n" +
|
||||||
"\x06packet\x18\x05 \x01(\fR\x06packet\x12\x19\n" +
|
"\x06packet\x18\x05 \x01(\fR\x06packet\x12\x19\n" +
|
||||||
"\bapply_to\x18\x06 \x01(\tR\aapplyTo\"<\n" +
|
"\bapply_to\x18\x06 \x01(\tR\aapplyTo\"+\n" +
|
||||||
"\aIPRules\x121\n" +
|
"\x05Range\x12\x10\n" +
|
||||||
"\x05rules\x18\x01 \x03(\v2\x1b.xray.common.geodata.IPRuleR\x05rules\"\xbc\x03\n" +
|
"\x03min\x18\x01 \x01(\x04R\x03min\x12\x10\n" +
|
||||||
|
"\x03max\x18\x02 \x01(\x04R\x03max\"\xa0\x02\n" +
|
||||||
|
"\x0fFinalRuleConfig\x126\n" +
|
||||||
|
"\x06action\x18\x01 \x01(\x0e2\x1e.xray.proxy.freedom.RuleActionR\x06action\x124\n" +
|
||||||
|
"\bnetworks\x18\x02 \x03(\x0e2\x18.xray.common.net.NetworkR\bnetworks\x126\n" +
|
||||||
|
"\tport_list\x18\x03 \x01(\v2\x19.xray.common.net.PortListR\bportList\x12+\n" +
|
||||||
|
"\x02ip\x18\x04 \x03(\v2\x1b.xray.common.geodata.IPRuleR\x02ip\x12:\n" +
|
||||||
|
"\vblock_delay\x18\x05 \x01(\v2\x19.xray.proxy.freedom.RangeR\n" +
|
||||||
|
"blockDelay\"\xaf\x03\n" +
|
||||||
"\x06Config\x12P\n" +
|
"\x06Config\x12P\n" +
|
||||||
"\x0fdomain_strategy\x18\x01 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12Z\n" +
|
"\x0fdomain_strategy\x18\x01 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12Z\n" +
|
||||||
"\x14destination_override\x18\x03 \x01(\v2'.xray.proxy.freedom.DestinationOverrideR\x13destinationOverride\x12\x1d\n" +
|
"\x14destination_override\x18\x03 \x01(\v2'.xray.proxy.freedom.DestinationOverrideR\x13destinationOverride\x12\x1d\n" +
|
||||||
@@ -425,10 +564,13 @@ const file_proxy_freedom_config_proto_rawDesc = "" +
|
|||||||
"user_level\x18\x04 \x01(\rR\tuserLevel\x128\n" +
|
"user_level\x18\x04 \x01(\rR\tuserLevel\x128\n" +
|
||||||
"\bfragment\x18\x05 \x01(\v2\x1c.xray.proxy.freedom.FragmentR\bfragment\x12%\n" +
|
"\bfragment\x18\x05 \x01(\v2\x1c.xray.proxy.freedom.FragmentR\bfragment\x12%\n" +
|
||||||
"\x0eproxy_protocol\x18\x06 \x01(\rR\rproxyProtocol\x121\n" +
|
"\x0eproxy_protocol\x18\x06 \x01(\rR\rproxyProtocol\x121\n" +
|
||||||
"\x06noises\x18\a \x03(\v2\x19.xray.proxy.freedom.NoiseR\x06noises\x12A\n" +
|
"\x06noises\x18\a \x03(\v2\x19.xray.proxy.freedom.NoiseR\x06noises\x12D\n" +
|
||||||
"\vips_blocked\x18\b \x01(\v2\x1b.xray.proxy.freedom.IPRulesH\x00R\n" +
|
"\vfinal_rules\x18\b \x03(\v2#.xray.proxy.freedom.FinalRuleConfigR\n" +
|
||||||
"ipsBlocked\x88\x01\x01B\x0e\n" +
|
"finalRules*\"\n" +
|
||||||
"\f_ips_blockedBX\n" +
|
"\n" +
|
||||||
|
"RuleAction\x12\t\n" +
|
||||||
|
"\x05Allow\x10\x00\x12\t\n" +
|
||||||
|
"\x05Block\x10\x01BX\n" +
|
||||||
"\x16com.xray.proxy.freedomP\x01Z'github.com/xtls/xray-core/proxy/freedom\xaa\x02\x12Xray.Proxy.Freedomb\x06proto3"
|
"\x16com.xray.proxy.freedomP\x01Z'github.com/xtls/xray-core/proxy/freedom\xaa\x02\x12Xray.Proxy.Freedomb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -443,30 +585,39 @@ func file_proxy_freedom_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_freedom_config_proto_rawDescData
|
return file_proxy_freedom_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
var file_proxy_freedom_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_proxy_freedom_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_proxy_freedom_config_proto_goTypes = []any{
|
var file_proxy_freedom_config_proto_goTypes = []any{
|
||||||
(*DestinationOverride)(nil), // 0: xray.proxy.freedom.DestinationOverride
|
(RuleAction)(0), // 0: xray.proxy.freedom.RuleAction
|
||||||
(*Fragment)(nil), // 1: xray.proxy.freedom.Fragment
|
(*DestinationOverride)(nil), // 1: xray.proxy.freedom.DestinationOverride
|
||||||
(*Noise)(nil), // 2: xray.proxy.freedom.Noise
|
(*Fragment)(nil), // 2: xray.proxy.freedom.Fragment
|
||||||
(*IPRules)(nil), // 3: xray.proxy.freedom.IPRules
|
(*Noise)(nil), // 3: xray.proxy.freedom.Noise
|
||||||
(*Config)(nil), // 4: xray.proxy.freedom.Config
|
(*Range)(nil), // 4: xray.proxy.freedom.Range
|
||||||
(*protocol.ServerEndpoint)(nil), // 5: xray.common.protocol.ServerEndpoint
|
(*FinalRuleConfig)(nil), // 5: xray.proxy.freedom.FinalRuleConfig
|
||||||
(*geodata.IPRule)(nil), // 6: xray.common.geodata.IPRule
|
(*Config)(nil), // 6: xray.proxy.freedom.Config
|
||||||
(internet.DomainStrategy)(0), // 7: xray.transport.internet.DomainStrategy
|
(*protocol.ServerEndpoint)(nil), // 7: xray.common.protocol.ServerEndpoint
|
||||||
|
(net.Network)(0), // 8: xray.common.net.Network
|
||||||
|
(*net.PortList)(nil), // 9: xray.common.net.PortList
|
||||||
|
(*geodata.IPRule)(nil), // 10: xray.common.geodata.IPRule
|
||||||
|
(internet.DomainStrategy)(0), // 11: xray.transport.internet.DomainStrategy
|
||||||
}
|
}
|
||||||
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
var file_proxy_freedom_config_proto_depIdxs = []int32{
|
||||||
5, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
7, // 0: xray.proxy.freedom.DestinationOverride.server:type_name -> xray.common.protocol.ServerEndpoint
|
||||||
6, // 1: xray.proxy.freedom.IPRules.rules:type_name -> xray.common.geodata.IPRule
|
0, // 1: xray.proxy.freedom.FinalRuleConfig.action:type_name -> xray.proxy.freedom.RuleAction
|
||||||
7, // 2: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
8, // 2: xray.proxy.freedom.FinalRuleConfig.networks:type_name -> xray.common.net.Network
|
||||||
0, // 3: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
9, // 3: xray.proxy.freedom.FinalRuleConfig.port_list:type_name -> xray.common.net.PortList
|
||||||
1, // 4: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
10, // 4: xray.proxy.freedom.FinalRuleConfig.ip:type_name -> xray.common.geodata.IPRule
|
||||||
2, // 5: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
4, // 5: xray.proxy.freedom.FinalRuleConfig.block_delay:type_name -> xray.proxy.freedom.Range
|
||||||
3, // 6: xray.proxy.freedom.Config.ips_blocked:type_name -> xray.proxy.freedom.IPRules
|
11, // 6: xray.proxy.freedom.Config.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
7, // [7:7] is the sub-list for method output_type
|
1, // 7: xray.proxy.freedom.Config.destination_override:type_name -> xray.proxy.freedom.DestinationOverride
|
||||||
7, // [7:7] is the sub-list for method input_type
|
2, // 8: xray.proxy.freedom.Config.fragment:type_name -> xray.proxy.freedom.Fragment
|
||||||
7, // [7:7] is the sub-list for extension type_name
|
3, // 9: xray.proxy.freedom.Config.noises:type_name -> xray.proxy.freedom.Noise
|
||||||
7, // [7:7] is the sub-list for extension extendee
|
5, // 10: xray.proxy.freedom.Config.final_rules:type_name -> xray.proxy.freedom.FinalRuleConfig
|
||||||
0, // [0:7] is the sub-list for field type_name
|
11, // [11:11] is the sub-list for method output_type
|
||||||
|
11, // [11:11] is the sub-list for method input_type
|
||||||
|
11, // [11:11] is the sub-list for extension type_name
|
||||||
|
11, // [11:11] is the sub-list for extension extendee
|
||||||
|
0, // [0:11] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_freedom_config_proto_init() }
|
func init() { file_proxy_freedom_config_proto_init() }
|
||||||
@@ -474,19 +625,19 @@ func file_proxy_freedom_config_proto_init() {
|
|||||||
if File_proxy_freedom_config_proto != nil {
|
if File_proxy_freedom_config_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_proxy_freedom_config_proto_msgTypes[4].OneofWrappers = []any{}
|
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_freedom_config_proto_rawDesc), len(file_proxy_freedom_config_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_freedom_config_proto_rawDesc), len(file_proxy_freedom_config_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 5,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_proxy_freedom_config_proto_goTypes,
|
GoTypes: file_proxy_freedom_config_proto_goTypes,
|
||||||
DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
|
DependencyIndexes: file_proxy_freedom_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_proxy_freedom_config_proto_enumTypes,
|
||||||
MessageInfos: file_proxy_freedom_config_proto_msgTypes,
|
MessageInfos: file_proxy_freedom_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proxy_freedom_config_proto = out.File
|
File_proxy_freedom_config_proto = out.File
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ option java_multiple_files = true;
|
|||||||
|
|
||||||
import "common/protocol/server_spec.proto";
|
import "common/protocol/server_spec.proto";
|
||||||
import "transport/internet/config.proto";
|
import "transport/internet/config.proto";
|
||||||
|
import "common/net/port.proto";
|
||||||
|
import "common/net/network.proto";
|
||||||
import "common/geodata/geodat.proto";
|
import "common/geodata/geodat.proto";
|
||||||
|
|
||||||
message DestinationOverride {
|
message DestinationOverride {
|
||||||
@@ -24,6 +26,7 @@ message Fragment {
|
|||||||
uint64 max_split_min = 7;
|
uint64 max_split_min = 7;
|
||||||
uint64 max_split_max = 8;
|
uint64 max_split_max = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Noise {
|
message Noise {
|
||||||
uint64 length_min = 1;
|
uint64 length_min = 1;
|
||||||
uint64 length_max = 2;
|
uint64 length_max = 2;
|
||||||
@@ -33,8 +36,22 @@ message Noise {
|
|||||||
string apply_to = 6;
|
string apply_to = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message IPRules {
|
message Range {
|
||||||
repeated xray.common.geodata.IPRule rules = 1;
|
uint64 min = 1;
|
||||||
|
uint64 max = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RuleAction {
|
||||||
|
Allow = 0;
|
||||||
|
Block = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FinalRuleConfig {
|
||||||
|
RuleAction action = 1;
|
||||||
|
repeated xray.common.net.Network networks = 2;
|
||||||
|
xray.common.net.PortList port_list = 3;
|
||||||
|
repeated xray.common.geodata.IPRule ip = 4;
|
||||||
|
Range block_delay = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
@@ -44,5 +61,5 @@ message Config {
|
|||||||
Fragment fragment = 5;
|
Fragment fragment = 5;
|
||||||
uint32 proxy_protocol = 6;
|
uint32 proxy_protocol = 6;
|
||||||
repeated Noise noises = 7;
|
repeated Noise noises = 7;
|
||||||
optional IPRules ips_blocked = 8;
|
repeated FinalRuleConfig final_rules = 8;
|
||||||
}
|
}
|
||||||
|
|||||||
+239
-75
@@ -31,32 +31,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var useSplice bool
|
var useSplice bool
|
||||||
|
var allNetworks [8]bool
|
||||||
var defaultPrivateBlockIP = []string{
|
var defaultBlockPrivateRule *FinalRule
|
||||||
"0.0.0.0/8",
|
var defaultBlockAllRule *FinalRule
|
||||||
"10.0.0.0/8",
|
|
||||||
"100.64.0.0/10",
|
|
||||||
"127.0.0.0/8",
|
|
||||||
"169.254.0.0/16",
|
|
||||||
"172.16.0.0/12",
|
|
||||||
"192.0.0.0/24",
|
|
||||||
"192.0.2.0/24",
|
|
||||||
"192.88.99.0/24",
|
|
||||||
"192.168.0.0/16",
|
|
||||||
"198.18.0.0/15",
|
|
||||||
"198.51.100.0/24",
|
|
||||||
"203.0.113.0/24",
|
|
||||||
"224.0.0.0/3",
|
|
||||||
"::/127",
|
|
||||||
"fc00::/7",
|
|
||||||
"fe80::/10",
|
|
||||||
"ff00::/8",
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultPrivateBlockIPMatcher = func() geodata.IPMatcher {
|
|
||||||
rules := common.Must2(geodata.ParseIPRules(defaultPrivateBlockIP))
|
|
||||||
return common.Must2(geodata.IPReg.BuildIPMatcher(rules))
|
|
||||||
}()
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
@@ -68,31 +45,184 @@ func init() {
|
|||||||
}
|
}
|
||||||
return h, nil
|
return h, nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
||||||
value := platform.NewEnvFlag(platform.UseFreedomSplice).GetValue(func() string { return defaultFlagValue })
|
value := platform.NewEnvFlag(platform.UseFreedomSplice).GetValue(func() string { return defaultFlagValue })
|
||||||
switch value {
|
switch value {
|
||||||
case defaultFlagValue, "auto", "enable":
|
case defaultFlagValue, "auto", "enable":
|
||||||
useSplice = true
|
useSplice = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := range allNetworks {
|
||||||
|
allNetworks[i] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultBlockPrivateRule = &FinalRule{
|
||||||
|
action: RuleAction_Block,
|
||||||
|
network: allNetworks,
|
||||||
|
ip: common.Must2(geodata.IPReg.BuildIPMatcher(common.Must2(geodata.ParseIPRules([]string{
|
||||||
|
"0.0.0.0/8",
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"100.64.0.0/10",
|
||||||
|
"127.0.0.0/8",
|
||||||
|
"169.254.0.0/16",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.0.0.0/24",
|
||||||
|
"192.0.2.0/24",
|
||||||
|
"192.88.99.0/24",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"198.18.0.0/15",
|
||||||
|
"198.51.100.0/24",
|
||||||
|
"203.0.113.0/24",
|
||||||
|
"224.0.0.0/3",
|
||||||
|
"::/127",
|
||||||
|
"fc00::/7",
|
||||||
|
"fe80::/10",
|
||||||
|
"ff00::/8",
|
||||||
|
})))),
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultBlockAllRule = &FinalRule{
|
||||||
|
action: RuleAction_Block,
|
||||||
|
network: allNetworks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FinalRule struct {
|
||||||
|
action RuleAction
|
||||||
|
network [8]bool
|
||||||
|
port net.MemoryPortList
|
||||||
|
ip geodata.IPMatcher
|
||||||
|
blockDelay *Range
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler handles Freedom connections.
|
// Handler handles Freedom connections.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
config *Config
|
config *Config
|
||||||
blockedIPMatcher geodata.IPMatcher
|
finalRules []*FinalRule
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
|
||||||
|
rule := &FinalRule{
|
||||||
|
action: config.GetAction(),
|
||||||
|
blockDelay: config.GetBlockDelay(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Networks) == 0 {
|
||||||
|
rule.network = allNetworks
|
||||||
|
} else {
|
||||||
|
for _, network := range config.Networks {
|
||||||
|
rule.network[int(network)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.PortList != nil {
|
||||||
|
rule.port = net.PortListFromProto(config.PortList)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Ip) > 0 {
|
||||||
|
matcher, err := geodata.IPReg.BuildIPMatcher(config.Ip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rule.ip = matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FinalRule) matchNetwork(network net.Network) bool {
|
||||||
|
return r.network[int(network)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FinalRule) matchPort(port net.Port) bool {
|
||||||
|
if len(r.port) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return r.port.Contains(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FinalRule) matchIP(addr net.Address) bool {
|
||||||
|
if r.ip == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return addr != nil && addr.Family().IsIP() && r.ip.Match(addr.IP())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FinalRule) Apply(network net.Network, address net.Address, port net.Port) bool {
|
||||||
|
if !r.matchNetwork(network) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !r.matchPort(port) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return r.matchIP(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDefaultFinalRule(inbound *session.Inbound) *FinalRule {
|
||||||
|
if inbound == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch inbound.Name {
|
||||||
|
case "vless-reverse":
|
||||||
|
return defaultBlockAllRule
|
||||||
|
case "vless", "vmess", "trojan", "hysteria", "wireguard":
|
||||||
|
return defaultBlockPrivateRule
|
||||||
|
default:
|
||||||
|
if strings.HasPrefix(inbound.Name, "shadowsocks") {
|
||||||
|
return defaultBlockPrivateRule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) shouldResolveDomainBeforeFinalRules(dialDest net.Destination, defaultRule *FinalRule) bool {
|
||||||
|
if !dialDest.Address.Family().IsDomain() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(h.finalRules) > 0 {
|
||||||
|
rule := h.finalRules[0]
|
||||||
|
if rule.action == RuleAction_Allow && rule.network[dialDest.Network] && len(rule.port) == 0 && rule.ip == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if defaultRule != nil || len(h.finalRules) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) matchFinalRule(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) *FinalRule {
|
||||||
|
for _, rule := range h.finalRules {
|
||||||
|
if rule.Apply(network, address, port) {
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if defaultRule != nil && defaultRule.Apply(network, address, port) {
|
||||||
|
return defaultRule
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
|
||||||
|
if rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {
|
||||||
|
return rule.action
|
||||||
|
}
|
||||||
|
return RuleAction_Allow
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initializes the Handler with necessary parameters.
|
// Init initializes the Handler with necessary parameters.
|
||||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||||
h.config = config
|
h.config = config
|
||||||
h.policyManager = pm
|
h.policyManager = pm
|
||||||
if config.IpsBlocked != nil && len(config.IpsBlocked.Rules) > 0 {
|
h.finalRules = make([]*FinalRule, 0, len(config.FinalRules))
|
||||||
m, err := geodata.IPReg.BuildIPMatcher(config.IpsBlocked.Rules)
|
for _, rc := range config.FinalRules {
|
||||||
|
rule, err := buildFinalRule(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to build blocked ip matcher").Base(err)
|
return errors.New("failed to build final rule").Base(err)
|
||||||
}
|
}
|
||||||
h.blockedIPMatcher = m
|
h.finalRules = append(h.finalRules, rule)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -102,6 +232,20 @@ func (h *Handler) policy() policy.Session {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
|
||||||
|
min := uint64(30)
|
||||||
|
max := uint64(90)
|
||||||
|
if rule.blockDelay != nil {
|
||||||
|
min = rule.blockDelay.Min
|
||||||
|
max = rule.blockDelay.Max
|
||||||
|
}
|
||||||
|
span := max - min
|
||||||
|
if max < min {
|
||||||
|
span = min - max
|
||||||
|
}
|
||||||
|
return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
func isValidAddress(addr *net.IPOrDomain) bool {
|
func isValidAddress(addr *net.IPOrDomain) bool {
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return false
|
return false
|
||||||
@@ -111,32 +255,6 @@ func isValidAddress(addr *net.IPOrDomain) bool {
|
|||||||
return a != net.AnyIP && a != net.AnyIPv6
|
return a != net.AnyIP && a != net.AnyIPv6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) getBlockedIPMatcher(ctx context.Context, inbound *session.Inbound) geodata.IPMatcher {
|
|
||||||
if h.blockedIPMatcher != nil {
|
|
||||||
return h.blockedIPMatcher
|
|
||||||
}
|
|
||||||
if h.config.IpsBlocked != nil && len(h.config.IpsBlocked.Rules) == 0 { // "ipsBlocked": []
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if inbound == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch inbound.Name {
|
|
||||||
case "vmess", "trojan", "hysteria", "wireguard":
|
|
||||||
errors.LogInfo(ctx, "applying default private IP blocking policy for inbound ", inbound.Name)
|
|
||||||
return defaultPrivateBlockIPMatcher
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(inbound.Name, "vless") || strings.HasPrefix(inbound.Name, "shadowsocks") {
|
|
||||||
errors.LogInfo(ctx, "applying default private IP blocking policy for inbound ", inbound.Name)
|
|
||||||
return defaultPrivateBlockIPMatcher
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isBlockedAddress(matcher geodata.IPMatcher, addr net.Address) bool {
|
|
||||||
return matcher != nil && addr != nil && addr.Family().IsIP() && matcher.Match(addr.IP())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process implements proxy.Outbound.
|
// Process implements proxy.Outbound.
|
||||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
@@ -147,7 +265,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
ob.Name = "freedom"
|
ob.Name = "freedom"
|
||||||
ob.CanSpliceCopy = 1
|
ob.CanSpliceCopy = 1
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
blockedIPMatcher := h.getBlockedIPMatcher(ctx, inbound)
|
defaultRule := getDefaultFinalRule(inbound)
|
||||||
|
|
||||||
destination := ob.Target
|
destination := ob.Target
|
||||||
origTargetAddr := ob.OriginalTarget.Address
|
origTargetAddr := ob.OriginalTarget.Address
|
||||||
@@ -173,6 +291,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
output := link.Writer
|
output := link.Writer
|
||||||
|
|
||||||
var conn stat.Connection
|
var conn stat.Connection
|
||||||
|
var blockedDest *net.Destination
|
||||||
|
var blockedRule *FinalRule
|
||||||
|
firstResolve := true
|
||||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
dialDest := destination
|
dialDest := destination
|
||||||
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||||
@@ -183,7 +304,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||||
if h.config.DomainStrategy.ForceIP() {
|
if h.config.DomainStrategy.ForceIP() || h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -194,6 +315,36 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||||
}
|
}
|
||||||
|
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules
|
||||||
|
domain := dialDest.Address.Domain()
|
||||||
|
var ips []net.IP
|
||||||
|
if firstResolve {
|
||||||
|
firstResolve = false
|
||||||
|
supportIPv4, supportIPv6 := utils.CheckRoutes()
|
||||||
|
if supportIPv4 {
|
||||||
|
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip4", domain)
|
||||||
|
}
|
||||||
|
if len(ips) == 0 && supportIPv6 {
|
||||||
|
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip6", domain)
|
||||||
|
}
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return errors.New("failed to get IP address for domain ", domain)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ips, _ = net.DefaultResolver.LookupIP(ctx, "ip", domain)
|
||||||
|
}
|
||||||
|
if len(ips) == 0 { // SRV/TXT, lookup failed
|
||||||
|
return errors.New("failed to get IP address for domain ", domain)
|
||||||
|
}
|
||||||
|
if addr := net.IPAddress(ips[dice.Roll(len(ips))]); addr != nil {
|
||||||
|
dialDest.Address = addr
|
||||||
|
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||||
|
blockedDest = &dialDest
|
||||||
|
blockedRule = rule
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rawConn, err := dialer.Dial(ctx, dialDest)
|
rawConn, err := dialer.Dial(ctx, dialDest)
|
||||||
@@ -207,9 +358,20 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to open connection to ", destination).Base(err)
|
return errors.New("failed to open connection to ", destination).Base(err)
|
||||||
}
|
}
|
||||||
if remoteAddr := net.DestinationFromAddr(conn.RemoteAddr()).Address; isBlockedAddress(blockedIPMatcher, remoteAddr) {
|
if blockedDest != nil {
|
||||||
conn.Close()
|
delay := h.blockDelay(blockedRule)
|
||||||
return errors.New("blocked target IP: ", remoteAddr).AtInfo()
|
errors.LogInfo(ctx, "blocked target: ", *blockedDest, ", blackholing connection for ", delay)
|
||||||
|
timer := time.AfterFunc(delay, func() {
|
||||||
|
common.Interrupt(input)
|
||||||
|
common.Interrupt(output)
|
||||||
|
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *blockedDest)
|
||||||
|
})
|
||||||
|
defer timer.Stop()
|
||||||
|
defer common.Close(output)
|
||||||
|
if err := buf.Copy(input, buf.Discard); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
||||||
version := byte(h.config.ProxyProtocol)
|
version := byte(h.config.ProxyProtocol)
|
||||||
@@ -255,7 +417,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
writer = buf.NewWriter(conn)
|
writer = buf.NewWriter(conn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writer = NewPacketWriter(conn, h, UDPOverride, destination, blockedIPMatcher)
|
writer = NewPacketWriter(conn, h, defaultRule, UDPOverride, destination)
|
||||||
if h.config.Noises != nil {
|
if h.config.Noises != nil {
|
||||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||||
writer = &NoisePacketWriter{
|
writer = &NoisePacketWriter{
|
||||||
@@ -290,7 +452,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if destination.Network == net.Network_TCP {
|
if destination.Network == net.Network_TCP {
|
||||||
reader = buf.NewReader(conn)
|
reader = buf.NewReader(conn)
|
||||||
} else {
|
} else {
|
||||||
reader = NewPacketReader(conn, UDPOverride, destination, blockedIPMatcher)
|
reader = NewPacketReader(conn, h, defaultRule, UDPOverride, destination)
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to process response").Base(err)
|
return errors.New("failed to process response").Base(err)
|
||||||
@@ -309,7 +471,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination, blockedIPMatcher geodata.IPMatcher) buf.Reader {
|
func NewPacketReader(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -328,7 +490,8 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De
|
|||||||
return &PacketReader{
|
return &PacketReader{
|
||||||
PacketConnWrapper: c,
|
PacketConnWrapper: c,
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
BlockedIPMatcher: blockedIPMatcher,
|
Handler: h,
|
||||||
|
DefaultRule: defaultRule,
|
||||||
IsOverridden: isOverridden,
|
IsOverridden: isOverridden,
|
||||||
InitUnchangedAddr: DialDest.Address,
|
InitUnchangedAddr: DialDest.Address,
|
||||||
InitChangedAddr: net.DestinationFromAddr(conn.RemoteAddr()).Address,
|
InitChangedAddr: net.DestinationFromAddr(conn.RemoteAddr()).Address,
|
||||||
@@ -340,7 +503,8 @@ func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.De
|
|||||||
type PacketReader struct {
|
type PacketReader struct {
|
||||||
*internet.PacketConnWrapper
|
*internet.PacketConnWrapper
|
||||||
stats.Counter
|
stats.Counter
|
||||||
BlockedIPMatcher geodata.IPMatcher
|
Handler *Handler
|
||||||
|
DefaultRule *FinalRule
|
||||||
IsOverridden bool
|
IsOverridden bool
|
||||||
InitUnchangedAddr net.Address
|
InitUnchangedAddr net.Address
|
||||||
InitChangedAddr net.Address
|
InitChangedAddr net.Address
|
||||||
@@ -357,7 +521,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
udpAddr := d.(*net.UDPAddr)
|
udpAddr := d.(*net.UDPAddr)
|
||||||
sourceAddr := net.IPAddress(udpAddr.IP)
|
sourceAddr := net.IPAddress(udpAddr.IP)
|
||||||
if isBlockedAddress(r.BlockedIPMatcher, sourceAddr) {
|
if r.Handler.applyFinalRules(net.Network_UDP, sourceAddr, net.Port(udpAddr.Port), r.DefaultRule) == RuleAction_Block {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(n))
|
b.Resize(0, int32(n))
|
||||||
@@ -382,7 +546,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialDest means the dial target used in the dialer when creating conn
|
// DialDest means the dial target used in the dialer when creating conn
|
||||||
func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, DialDest net.Destination, blockedIPMatcher geodata.IPMatcher) buf.Writer {
|
func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
if ok {
|
if ok {
|
||||||
@@ -403,7 +567,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, UDPOverride net.Destination, Dia
|
|||||||
PacketConnWrapper: c,
|
PacketConnWrapper: c,
|
||||||
Counter: counter,
|
Counter: counter,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
BlockedIPMatcher: blockedIPMatcher,
|
DefaultRule: defaultRule,
|
||||||
UDPOverride: UDPOverride,
|
UDPOverride: UDPOverride,
|
||||||
ResolvedUDPAddr: resolvedUDPAddr,
|
ResolvedUDPAddr: resolvedUDPAddr,
|
||||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
||||||
@@ -417,8 +581,8 @@ type PacketWriter struct {
|
|||||||
*internet.PacketConnWrapper
|
*internet.PacketConnWrapper
|
||||||
stats.Counter
|
stats.Counter
|
||||||
*Handler
|
*Handler
|
||||||
BlockedIPMatcher geodata.IPMatcher
|
DefaultRule *FinalRule
|
||||||
UDPOverride net.Destination
|
UDPOverride net.Destination
|
||||||
|
|
||||||
// Dest of udp packets might be a domain, we will resolve them to IP
|
// Dest of udp packets might be a domain, we will resolve them to IP
|
||||||
// But resolver will return a random one if the domain has many IPs
|
// But resolver will return a random one if the domain has many IPs
|
||||||
@@ -476,7 +640,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isBlockedAddress(w.BlockedIPMatcher, b.UDP.Address) {
|
if w.applyFinalRules(net.Network_UDP, b.UDP.Address, b.UDP.Port, w.DefaultRule) == RuleAction_Block {
|
||||||
b.Release()
|
b.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-54
@@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/task"
|
"github.com/xtls/xray-core/common/task"
|
||||||
"github.com/xtls/xray-core/core"
|
"github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/features/policy"
|
"github.com/xtls/xray-core/features/policy"
|
||||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||||
@@ -56,7 +55,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
ob.CanSpliceCopy = 3
|
ob.CanSpliceCopy = 3
|
||||||
target := ob.Target
|
target := ob.Target
|
||||||
|
|
||||||
conn, err := dialer.Dial(hyCtx.ContextWithRequireDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
conn, err := dialer.Dial(hysteria.ContextWithDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
@@ -118,7 +117,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
|
|
||||||
if target.Network == net.Network_UDP {
|
if target.Network == net.Network_UDP {
|
||||||
iConn := stat.TryUnwrapStatsConn(conn)
|
iConn := stat.TryUnwrapStatsConn(conn)
|
||||||
_, ok := iConn.(*hysteria.InterUdpConn)
|
_, ok := iConn.(*hysteria.InterConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("udp requires hysteria udp transport")
|
return errors.New("udp requires hysteria udp transport")
|
||||||
}
|
}
|
||||||
@@ -127,8 +126,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
|
|
||||||
writer := &UDPWriter{
|
writer := &UDPWriter{
|
||||||
Writer: conn,
|
writer: conn,
|
||||||
buf: make([]byte, MaxUDPSize),
|
|
||||||
addr: target.NetAddr(),
|
addr: target.NetAddr(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,8 +141,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
|
|
||||||
reader := &UDPReader{
|
reader := &UDPReader{
|
||||||
Reader: conn,
|
reader: conn,
|
||||||
buf: make([]byte, MaxUDPSize),
|
|
||||||
df: &Defragger{},
|
df: &Defragger{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,28 +170,22 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UDPWriter struct {
|
type UDPWriter struct {
|
||||||
Writer io.Writer
|
writer io.Writer
|
||||||
buf []byte
|
|
||||||
addr string
|
addr string
|
||||||
|
buf [buf.Size]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *UDPWriter) sendMsg(msg *UDPMessage) error {
|
func (w *UDPWriter) SendMessage(msg *UDPMessage) error {
|
||||||
msgN := msg.Serialize(w.buf)
|
msgN := msg.Serialize(w.buf[:])
|
||||||
if msgN < 0 {
|
if msgN < 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err := w.Writer.Write(w.buf[:msgN])
|
_, err := w.writer.Write(w.buf[:msgN])
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
for {
|
for i, b := range mb {
|
||||||
mb2, b := buf.SplitFirst(mb)
|
|
||||||
mb = mb2
|
|
||||||
if b == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
addr := w.addr
|
addr := w.addr
|
||||||
if b.UDP != nil {
|
if b.UDP != nil {
|
||||||
addr = b.UDP.NetAddr()
|
addr = b.UDP.NetAddr()
|
||||||
@@ -209,22 +200,20 @@ func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
Data: b.Bytes(),
|
Data: b.Bytes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := w.sendMsg(msg)
|
err := w.SendMessage(msg)
|
||||||
var errTooLarge *quic.DatagramTooLargeError
|
var errTooLarge *quic.DatagramTooLargeError
|
||||||
if go_errors.As(err, &errTooLarge) {
|
if go_errors.As(err, &errTooLarge) {
|
||||||
msg.PacketID = uint16(rand.Intn(0xFFFF)) + 1
|
msg.PacketID = uint16(rand.Intn(0xFFFF)) + 1
|
||||||
fMsgs := FragUDPMessage(msg, int(errTooLarge.MaxDatagramPayloadSize))
|
fMsgs := FragUDPMessage(msg, int(errTooLarge.MaxDatagramPayloadSize))
|
||||||
for _, fMsg := range fMsgs {
|
for _, fMsg := range fMsgs {
|
||||||
err := w.sendMsg(&fMsg)
|
err := w.SendMessage(&fMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Release()
|
buf.ReleaseMulti(mb[i:])
|
||||||
buf.ReleaseMulti(mb)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
b.Release()
|
buf.ReleaseMulti(mb[i:])
|
||||||
buf.ReleaseMulti(mb)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,34 +224,21 @@ func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UDPReader struct {
|
type UDPReader struct {
|
||||||
Reader io.Reader
|
reader io.Reader
|
||||||
buf []byte
|
df *Defragger
|
||||||
df *Defragger
|
firstBuf *buf.Buffer
|
||||||
firstMsg *UDPMessage
|
|
||||||
firstDest *net.Destination
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (r *UDPReader) ReadFrom(p []byte) (n int, addr *net.Destination, err error) {
|
||||||
if r.firstMsg != nil {
|
|
||||||
buffer := buf.New()
|
|
||||||
_, err := buffer.Write(r.firstMsg.Data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
buffer.UDP = r.firstDest
|
|
||||||
|
|
||||||
r.firstMsg = nil
|
|
||||||
r.firstDest = nil
|
|
||||||
|
|
||||||
return buf.MultiBuffer{buffer}, nil
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
n, err := r.Reader.Read(r.buf)
|
var buf [hysteria.MaxDatagramFrameSize]byte
|
||||||
|
|
||||||
|
n, err := r.reader.Read(buf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := ParseUDPMessage(r.buf[:n])
|
msg, err := ParseUDPMessage(buf[:n])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -274,17 +250,31 @@ func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
|
|
||||||
dest, err := net.ParseDestination("udp:" + dfMsg.Addr)
|
dest, err := net.ParseDestination("udp:" + dfMsg.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogDebug(context.Background(), dfMsg.Addr, " ParseDestination err ", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := buf.New()
|
if len(p) < len(dfMsg.Data) {
|
||||||
if _, err := buffer.Write(dfMsg.Data); err != nil {
|
continue
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.UDP = &dest
|
return copy(p, dfMsg.Data), &dest, nil
|
||||||
|
|
||||||
return buf.MultiBuffer{buffer}, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
|
if r.firstBuf != nil {
|
||||||
|
mb := buf.MultiBuffer{r.firstBuf}
|
||||||
|
r.firstBuf = nil
|
||||||
|
return mb, nil
|
||||||
|
}
|
||||||
|
b := buf.New()
|
||||||
|
b.Resize(0, buf.Size)
|
||||||
|
n, addr, err := r.ReadFrom(b.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
b.Release()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.Resize(0, int32(n))
|
||||||
|
b.UDP = addr
|
||||||
|
return buf.MultiBuffer{b}, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1 @@
|
|||||||
package hysteria
|
package hysteria
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/padding"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
tcpRequestPadding = padding.Padding{Min: 64, Max: 512}
|
|
||||||
tcpResponsePadding = padding.Padding{Min: 128, Max: 1024}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
package ctx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/proxy/hysteria/account"
|
|
||||||
)
|
|
||||||
|
|
||||||
type key int
|
|
||||||
|
|
||||||
const (
|
|
||||||
requireDatagram key = iota
|
|
||||||
validator
|
|
||||||
)
|
|
||||||
|
|
||||||
func ContextWithRequireDatagram(ctx context.Context, udp bool) context.Context {
|
|
||||||
if !udp {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
return context.WithValue(ctx, requireDatagram, struct{}{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func RequireDatagramFromContext(ctx context.Context) bool {
|
|
||||||
_, ok := ctx.Value(requireDatagram).(struct{})
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func ContextWithValidator(ctx context.Context, v *account.Validator) context.Context {
|
|
||||||
return context.WithValue(ctx, validator, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidatorFromContext(ctx context.Context) *account.Validator {
|
|
||||||
v, _ := ctx.Value(validator).(*account.Validator)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package hysteria
|
|
||||||
|
|
||||||
func FragUDPMessage(m *UDPMessage, maxSize int) []UDPMessage {
|
|
||||||
if m.Size() <= maxSize {
|
|
||||||
return []UDPMessage{*m}
|
|
||||||
}
|
|
||||||
fullPayload := m.Data
|
|
||||||
maxPayloadSize := maxSize - m.HeaderSize()
|
|
||||||
off := 0
|
|
||||||
fragID := uint8(0)
|
|
||||||
fragCount := uint8((len(fullPayload) + maxPayloadSize - 1) / maxPayloadSize) // round up
|
|
||||||
frags := make([]UDPMessage, fragCount)
|
|
||||||
for off < len(fullPayload) {
|
|
||||||
payloadSize := len(fullPayload) - off
|
|
||||||
if payloadSize > maxPayloadSize {
|
|
||||||
payloadSize = maxPayloadSize
|
|
||||||
}
|
|
||||||
frag := *m
|
|
||||||
frag.FragID = fragID
|
|
||||||
frag.FragCount = fragCount
|
|
||||||
frag.Data = fullPayload[off : off+payloadSize]
|
|
||||||
frags[fragID] = frag
|
|
||||||
off += payloadSize
|
|
||||||
fragID++
|
|
||||||
}
|
|
||||||
return frags
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defragger handles the defragmentation of UDP messages.
|
|
||||||
// The current implementation can only handle one packet ID at a time.
|
|
||||||
// If another packet arrives before a packet has received all fragments
|
|
||||||
// in their entirety, any previous state is discarded.
|
|
||||||
type Defragger struct {
|
|
||||||
pktID uint16
|
|
||||||
frags []*UDPMessage
|
|
||||||
count uint8
|
|
||||||
size int // data size
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Defragger) Feed(m *UDPMessage) *UDPMessage {
|
|
||||||
if m.FragCount <= 1 {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
if m.FragID >= m.FragCount {
|
|
||||||
// wtf is this?
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if m.PacketID != d.pktID || m.FragCount != uint8(len(d.frags)) {
|
|
||||||
// new message, clear previous state
|
|
||||||
d.pktID = m.PacketID
|
|
||||||
d.frags = make([]*UDPMessage, m.FragCount)
|
|
||||||
d.frags[m.FragID] = m
|
|
||||||
d.count = 1
|
|
||||||
d.size = len(m.Data)
|
|
||||||
} else if d.frags[m.FragID] == nil {
|
|
||||||
d.frags[m.FragID] = m
|
|
||||||
d.count++
|
|
||||||
d.size += len(m.Data)
|
|
||||||
if int(d.count) == len(d.frags) {
|
|
||||||
// all fragments received, assemble
|
|
||||||
data := make([]byte, d.size)
|
|
||||||
off := 0
|
|
||||||
for _, frag := range d.frags {
|
|
||||||
off += copy(data[off:], frag.Data)
|
|
||||||
}
|
|
||||||
m.Data = data
|
|
||||||
m.FragID = 0
|
|
||||||
m.FragCount = 1
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/apernet/quic-go/quicvarint"
|
"github.com/apernet/quic-go/quicvarint"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -17,8 +18,6 @@ const (
|
|||||||
MaxMessageLength = 2048
|
MaxMessageLength = 2048
|
||||||
MaxPaddingLength = 4096
|
MaxPaddingLength = 4096
|
||||||
|
|
||||||
MaxUDPSize = 4096
|
|
||||||
|
|
||||||
maxVarInt1 = 63
|
maxVarInt1 = 63
|
||||||
maxVarInt2 = 16383
|
maxVarInt2 = 16383
|
||||||
maxVarInt4 = 1073741823
|
maxVarInt4 = 1073741823
|
||||||
@@ -62,7 +61,7 @@ func ReadTCPRequest(r io.Reader) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteTCPRequest(w io.Writer, addr string) error {
|
func WriteTCPRequest(w io.Writer, addr string) error {
|
||||||
padding := tcpRequestPadding.String()
|
padding := hysteria.TcpRequestPadding.String()
|
||||||
paddingLen := len(padding)
|
paddingLen := len(padding)
|
||||||
addrLen := len(addr)
|
addrLen := len(addr)
|
||||||
sz := int(quicvarint.Len(uint64(addrLen))) + addrLen +
|
sz := int(quicvarint.Len(uint64(addrLen))) + addrLen +
|
||||||
@@ -122,7 +121,7 @@ func ReadTCPResponse(r io.Reader) (bool, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteTCPResponse(w io.Writer, ok bool, msg string) error {
|
func WriteTCPResponse(w io.Writer, ok bool, msg string) error {
|
||||||
padding := tcpResponsePadding.String()
|
padding := hysteria.TcpResponsePadding.String()
|
||||||
paddingLen := len(padding)
|
paddingLen := len(padding)
|
||||||
msgLen := len(msg)
|
msgLen := len(msg)
|
||||||
sz := 1 + int(quicvarint.Len(uint64(msgLen))) + msgLen +
|
sz := 1 + int(quicvarint.Len(uint64(msgLen))) + msgLen +
|
||||||
@@ -247,3 +246,75 @@ func varintPut(b []byte, i uint64) int {
|
|||||||
}
|
}
|
||||||
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FragUDPMessage(m *UDPMessage, maxSize int) []UDPMessage {
|
||||||
|
if m.Size() <= maxSize {
|
||||||
|
return []UDPMessage{*m}
|
||||||
|
}
|
||||||
|
fullPayload := m.Data
|
||||||
|
maxPayloadSize := maxSize - m.HeaderSize()
|
||||||
|
off := 0
|
||||||
|
fragID := uint8(0)
|
||||||
|
fragCount := uint8((len(fullPayload) + maxPayloadSize - 1) / maxPayloadSize) // round up
|
||||||
|
frags := make([]UDPMessage, fragCount)
|
||||||
|
for off < len(fullPayload) {
|
||||||
|
payloadSize := len(fullPayload) - off
|
||||||
|
if payloadSize > maxPayloadSize {
|
||||||
|
payloadSize = maxPayloadSize
|
||||||
|
}
|
||||||
|
frag := *m
|
||||||
|
frag.FragID = fragID
|
||||||
|
frag.FragCount = fragCount
|
||||||
|
frag.Data = fullPayload[off : off+payloadSize]
|
||||||
|
frags[fragID] = frag
|
||||||
|
off += payloadSize
|
||||||
|
fragID++
|
||||||
|
}
|
||||||
|
return frags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defragger handles the defragmentation of UDP messages.
|
||||||
|
// The current implementation can only handle one packet ID at a time.
|
||||||
|
// If another packet arrives before a packet has received all fragments
|
||||||
|
// in their entirety, any previous state is discarded.
|
||||||
|
type Defragger struct {
|
||||||
|
pktID uint16
|
||||||
|
frags []*UDPMessage
|
||||||
|
count uint8
|
||||||
|
size int // data size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Defragger) Feed(m *UDPMessage) *UDPMessage {
|
||||||
|
if m.FragCount <= 1 {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
if m.FragID >= m.FragCount {
|
||||||
|
// wtf is this?
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if m.PacketID != d.pktID || m.FragCount != uint8(len(d.frags)) {
|
||||||
|
// new message, clear previous state
|
||||||
|
d.pktID = m.PacketID
|
||||||
|
d.frags = make([]*UDPMessage, m.FragCount)
|
||||||
|
d.frags[m.FragID] = m
|
||||||
|
d.count = 1
|
||||||
|
d.size = len(m.Data)
|
||||||
|
} else if d.frags[m.FragID] == nil {
|
||||||
|
d.frags[m.FragID] = m
|
||||||
|
d.count++
|
||||||
|
d.size += len(m.Data)
|
||||||
|
if int(d.count) == len(d.frags) {
|
||||||
|
// all fragments received, assemble
|
||||||
|
data := make([]byte, d.size)
|
||||||
|
off := 0
|
||||||
|
for _, frag := range d.frags {
|
||||||
|
off += copy(data[off:], frag.Data)
|
||||||
|
}
|
||||||
|
m.Data = data
|
||||||
|
m.FragID = 0
|
||||||
|
m.FragCount = 1
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+18
-43
@@ -2,7 +2,6 @@ package hysteria
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
@@ -91,54 +90,30 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
inbound.User = v.User()
|
inbound.User = v.User()
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := iConn.(*hysteria.InterUdpConn); ok {
|
if _, ok := iConn.(*hysteria.InterConn); ok {
|
||||||
r := io.Reader(conn)
|
|
||||||
b := make([]byte, MaxUDPSize)
|
|
||||||
df := &Defragger{}
|
|
||||||
var firstMsg *UDPMessage
|
|
||||||
var firstDest net.Destination
|
|
||||||
|
|
||||||
for {
|
|
||||||
n, err := r.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, err := ParseUDPMessage(b[:n])
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dfMsg := df.Feed(msg)
|
|
||||||
if dfMsg == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
firstMsg = dfMsg
|
|
||||||
firstDest, err = net.ParseDestination("udp:" + firstMsg.Addr)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogDebug(context.Background(), dfMsg.Addr, " ParseDestination err ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := &UDPReader{
|
reader := &UDPReader{
|
||||||
Reader: r,
|
reader: conn,
|
||||||
buf: b,
|
df: &Defragger{},
|
||||||
df: df,
|
|
||||||
firstMsg: firstMsg,
|
|
||||||
firstDest: &firstDest,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b := buf.New()
|
||||||
|
b.Resize(0, buf.Size)
|
||||||
|
n, addr, err := reader.ReadFrom(b.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
b.Release()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.Resize(0, int32(n))
|
||||||
|
b.UDP = addr
|
||||||
|
|
||||||
|
reader.firstBuf = b
|
||||||
|
|
||||||
writer := &UDPWriter{
|
writer := &UDPWriter{
|
||||||
Writer: conn,
|
writer: conn,
|
||||||
buf: make([]byte, MaxUDPSize),
|
addr: addr.NetAddr(),
|
||||||
addr: firstMsg.Addr,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dispatcher.DispatchLink(ctx, firstDest, &transport.Link{
|
return dispatcher.DispatchLink(ctx, *addr, &transport.Link{
|
||||||
Reader: reader,
|
Reader: reader,
|
||||||
Writer: writer,
|
Writer: writer,
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-2
@@ -41,10 +41,12 @@ Here is simple Xray config snippet to enable the inbound:
|
|||||||
|
|
||||||
- IPv4 and IPv6
|
- IPv4 and IPv6
|
||||||
- TCP and UDP
|
- TCP and UDP
|
||||||
|
- ICMP Echo (ping)
|
||||||
|
|
||||||
## LIMITATION
|
## LIMITATION
|
||||||
|
|
||||||
- No ICMP support
|
- Only ICMP Echo request/reply is supported; other ICMP message types are ignored
|
||||||
|
- ICMP Echo replies are generated locally by the TUN stack; they do not validate real remote ICMP reachability
|
||||||
- Connections are established to any host, as connection success is only a mark of successful accepting packet for proxying. Hosts that are not accepting connections or don't even exists, will look like they opened a connection (SYN-ACK), and never send back a single byte, closing connection (RST) after some time. This is the side effect of the whole process actually being a proxy, and not real network layer 3 vpn
|
- Connections are established to any host, as connection success is only a mark of successful accepting packet for proxying. Hosts that are not accepting connections or don't even exists, will look like they opened a connection (SYN-ACK), and never send back a single byte, closing connection (RST) after some time. This is the side effect of the whole process actually being a proxy, and not real network layer 3 vpn
|
||||||
|
|
||||||
## CONSIDERATIONS
|
## CONSIDERATIONS
|
||||||
@@ -248,4 +250,4 @@ Set the environment variable `xray.tun.fd` (or `XRAY_TUN_FD`) to the fd number b
|
|||||||
Build using gomobile for iOS framework integration:
|
Build using gomobile for iOS framework integration:
|
||||||
```
|
```
|
||||||
gomobile bind -target=ios
|
gomobile bind -target=ios
|
||||||
```
|
```
|
||||||
|
|||||||
+60
-13
@@ -3,6 +3,8 @@ package tun
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -45,26 +47,53 @@ func (updater *InterfaceUpdater) Update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var got *net.Interface
|
var got *net.Interface
|
||||||
for _, iface := range interfaces {
|
if updater.fixedName != "" {
|
||||||
if iface.Index == updater.tunIndex {
|
for _, iface := range interfaces {
|
||||||
continue
|
if iface.Index == updater.tunIndex {
|
||||||
}
|
continue
|
||||||
if updater.fixedName != "" {
|
}
|
||||||
if iface.Name == updater.fixedName {
|
if iface.Name == updater.fixedName {
|
||||||
got = &iface
|
got = &iface
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
addrs, err := iface.Addrs()
|
} else {
|
||||||
if err != nil {
|
var ifs []struct {
|
||||||
|
index int
|
||||||
|
score int
|
||||||
|
}
|
||||||
|
for i, iface := range interfaces {
|
||||||
|
if iface.Index == updater.tunIndex {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (iface.Flags&net.FlagUp != 0) &&
|
if strings.Contains(iface.Name, "vEthernet") {
|
||||||
(iface.Flags&net.FlagLoopback == 0) &&
|
continue
|
||||||
len(addrs) > 0 {
|
|
||||||
got = &iface
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
if iface.Flags&net.FlagUp == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if iface.Flags&net.FlagLoopback != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ifs = append(ifs, struct {
|
||||||
|
index int
|
||||||
|
score int
|
||||||
|
}{i, score(&iface, addrs)})
|
||||||
|
}
|
||||||
|
sort.Slice(ifs, func(i, j int) bool {
|
||||||
|
if ifs[i].score != ifs[j].score {
|
||||||
|
return ifs[i].score > ifs[j].score
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaces[ifs[i].index].Name < interfaces[ifs[j].index].Name
|
||||||
|
})
|
||||||
|
if len(ifs) > 0 {
|
||||||
|
iface := interfaces[ifs[0].index]
|
||||||
|
got = &iface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,3 +105,21 @@ func (updater *InterfaceUpdater) Update() {
|
|||||||
updater.iface = got
|
updater.iface = got
|
||||||
errors.LogInfo(context.Background(), "[tun] update interface ", got.Name, " ", got.Index)
|
errors.LogInfo(context.Background(), "[tun] update interface ", got.Name, " ", got.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func score(iface *net.Interface, addrs []net.Addr) int {
|
||||||
|
score := 0
|
||||||
|
|
||||||
|
name := strings.ToLower(iface.Name)
|
||||||
|
if strings.Contains(name, "wlan") || strings.Contains(name, "wi-fi") {
|
||||||
|
score += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if strings.HasPrefix(addr.String(), "192.168.") {
|
||||||
|
score += 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package icmp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProtocolLabel(netProto tcpip.NetworkProtocolNumber) string {
|
||||||
|
switch netProto {
|
||||||
|
case header.IPv4ProtocolNumber:
|
||||||
|
return "ipv4"
|
||||||
|
case header.IPv6ProtocolNumber:
|
||||||
|
return "ipv6"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseEchoRequest(netProto tcpip.NetworkProtocolNumber, message []byte) (uint16, uint16, bool) {
|
||||||
|
switch netProto {
|
||||||
|
case header.IPv4ProtocolNumber:
|
||||||
|
if len(message) < header.ICMPv4MinimumSize {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv4(message)
|
||||||
|
if icmpHdr.Type() != header.ICMPv4Echo || icmpHdr.Code() != header.ICMPv4UnusedCode {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
return icmpHdr.Ident(), icmpHdr.Sequence(), true
|
||||||
|
case header.IPv6ProtocolNumber:
|
||||||
|
if len(message) < header.ICMPv6MinimumSize {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv6(message)
|
||||||
|
if icmpHdr.Type() != header.ICMPv6EchoRequest || icmpHdr.Code() != header.ICMPv6UnusedCode {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
return icmpHdr.Ident(), icmpHdr.Sequence(), true
|
||||||
|
default:
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RewriteChecksum(netProto tcpip.NetworkProtocolNumber, message []byte, srcIP, dstIP tcpip.Address) error {
|
||||||
|
switch netProto {
|
||||||
|
case header.IPv4ProtocolNumber:
|
||||||
|
if len(message) < header.ICMPv4MinimumSize {
|
||||||
|
return errors.New("invalid icmpv4 packet")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv4(message)
|
||||||
|
icmpHdr.SetChecksum(0)
|
||||||
|
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr[:header.ICMPv4MinimumSize], checksum.Checksum(icmpHdr.Payload(), 0)))
|
||||||
|
return nil
|
||||||
|
case header.IPv6ProtocolNumber:
|
||||||
|
if len(message) < header.ICMPv6MinimumSize {
|
||||||
|
return errors.New("invalid icmpv6 packet")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv6(message)
|
||||||
|
icmpHdr.SetChecksum(0)
|
||||||
|
icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
|
||||||
|
Header: icmpHdr[:header.ICMPv6MinimumSize],
|
||||||
|
Src: srcIP,
|
||||||
|
Dst: dstIP,
|
||||||
|
PayloadCsum: checksum.Checksum(icmpHdr.Payload(), 0),
|
||||||
|
PayloadLen: len(icmpHdr.Payload()),
|
||||||
|
}))
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return errors.New("unsupported icmp network protocol")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildLocalEchoReply(netProto tcpip.NetworkProtocolNumber, request []byte, srcIP, dstIP tcpip.Address) ([]byte, error) {
|
||||||
|
reply := append([]byte(nil), request...)
|
||||||
|
|
||||||
|
switch netProto {
|
||||||
|
case header.IPv4ProtocolNumber:
|
||||||
|
if len(reply) < header.ICMPv4MinimumSize {
|
||||||
|
return nil, errors.New("invalid icmpv4 echo packet")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv4(reply)
|
||||||
|
if icmpHdr.Type() != header.ICMPv4Echo || icmpHdr.Code() != header.ICMPv4UnusedCode {
|
||||||
|
return nil, errors.New("not an icmpv4 echo request")
|
||||||
|
}
|
||||||
|
reply[0] = byte(header.ICMPv4EchoReply)
|
||||||
|
case header.IPv6ProtocolNumber:
|
||||||
|
if len(reply) < header.ICMPv6MinimumSize {
|
||||||
|
return nil, errors.New("invalid icmpv6 echo packet")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv6(reply)
|
||||||
|
if icmpHdr.Type() != header.ICMPv6EchoRequest || icmpHdr.Code() != header.ICMPv6UnusedCode {
|
||||||
|
return nil, errors.New("not an icmpv6 echo request")
|
||||||
|
}
|
||||||
|
reply[0] = byte(header.ICMPv6EchoReply)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unsupported icmp network protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RewriteChecksum(netProto, reply, srcIP, dstIP); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package icmp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseEchoRequest(t *testing.T) {
|
||||||
|
t.Run("ipv4 echo", func(t *testing.T) {
|
||||||
|
var zero tcpip.Address
|
||||||
|
packet := []byte{
|
||||||
|
byte(header.ICMPv4Echo), 0,
|
||||||
|
0, 0,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x56, 0x78,
|
||||||
|
0xaa, 0xbb,
|
||||||
|
}
|
||||||
|
if err := RewriteChecksum(header.IPv4ProtocolNumber, packet, zero, zero); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ident, sequence, ok := ParseEchoRequest(header.IPv4ProtocolNumber, packet)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected ipv4 echo request to parse")
|
||||||
|
}
|
||||||
|
if ident != 0x1234 || sequence != 0x5678 {
|
||||||
|
t.Fatalf("unexpected ident/sequence: %x/%x", ident, sequence)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ipv6 echo", func(t *testing.T) {
|
||||||
|
packet := []byte{
|
||||||
|
byte(header.ICMPv6EchoRequest), 0,
|
||||||
|
0, 0,
|
||||||
|
0xab, 0xcd,
|
||||||
|
0xef, 0x01,
|
||||||
|
0xaa, 0xbb,
|
||||||
|
}
|
||||||
|
src := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
|
||||||
|
dst := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2})
|
||||||
|
if err := RewriteChecksum(header.IPv6ProtocolNumber, packet, src, dst); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ident, sequence, ok := ParseEchoRequest(header.IPv6ProtocolNumber, packet)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected ipv6 echo request to parse")
|
||||||
|
}
|
||||||
|
if ident != 0xabcd || sequence != 0xef01 {
|
||||||
|
t.Fatalf("unexpected ident/sequence: %x/%x", ident, sequence)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRewriteChecksum(t *testing.T) {
|
||||||
|
t.Run("ipv4", func(t *testing.T) {
|
||||||
|
var zero tcpip.Address
|
||||||
|
packet := []byte{
|
||||||
|
byte(header.ICMPv4Echo), 0,
|
||||||
|
0xff, 0xff,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x56, 0x78,
|
||||||
|
0xaa, 0xbb, 0xcc,
|
||||||
|
}
|
||||||
|
if err := RewriteChecksum(header.IPv4ProtocolNumber, packet, zero, zero); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
icmpHdr := header.ICMPv4(packet)
|
||||||
|
if got, want := icmpHdr.Checksum(), header.ICMPv4Checksum(icmpHdr[:header.ICMPv4MinimumSize], checksumPayloadV4(icmpHdr.Payload())); got != want {
|
||||||
|
t.Fatalf("unexpected ipv4 checksum: got %x want %x", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ipv6", func(t *testing.T) {
|
||||||
|
packet := []byte{
|
||||||
|
byte(header.ICMPv6EchoReply), 0,
|
||||||
|
0xff, 0xff,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x56, 0x78,
|
||||||
|
0xaa, 0xbb, 0xcc,
|
||||||
|
}
|
||||||
|
src := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
|
||||||
|
dst := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2})
|
||||||
|
if err := RewriteChecksum(header.IPv6ProtocolNumber, packet, src, dst); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
icmpHdr := header.ICMPv6(packet)
|
||||||
|
want := header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
|
||||||
|
Header: icmpHdr[:header.ICMPv6MinimumSize],
|
||||||
|
Src: src,
|
||||||
|
Dst: dst,
|
||||||
|
PayloadLen: len(icmpHdr.Payload()),
|
||||||
|
PayloadCsum: checksumPayloadV6(icmpHdr.Payload()),
|
||||||
|
})
|
||||||
|
if got := icmpHdr.Checksum(); got != want {
|
||||||
|
t.Fatalf("unexpected ipv6 checksum: got %x want %x", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildLocalEchoReply(t *testing.T) {
|
||||||
|
t.Run("ipv4", func(t *testing.T) {
|
||||||
|
request := []byte{
|
||||||
|
byte(header.ICMPv4Echo), 0,
|
||||||
|
0, 0,
|
||||||
|
0x12, 0x34,
|
||||||
|
0x56, 0x78,
|
||||||
|
0xaa, 0xbb, 0xcc,
|
||||||
|
}
|
||||||
|
src := tcpip.Address{}
|
||||||
|
dst := tcpip.Address{}
|
||||||
|
if err := RewriteChecksum(header.IPv4ProtocolNumber, request, src, dst); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := BuildLocalEchoReply(header.IPv4ProtocolNumber, request, dst, src)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if request[0] != byte(header.ICMPv4Echo) {
|
||||||
|
t.Fatal("request mutated")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv4(reply)
|
||||||
|
if icmpHdr.Type() != header.ICMPv4EchoReply || icmpHdr.Code() != header.ICMPv4UnusedCode {
|
||||||
|
t.Fatalf("unexpected ipv4 reply type/code: %d/%d", icmpHdr.Type(), icmpHdr.Code())
|
||||||
|
}
|
||||||
|
if icmpHdr.Ident() != 0x1234 || icmpHdr.Sequence() != 0x5678 {
|
||||||
|
t.Fatalf("unexpected ipv4 ident/sequence: %x/%x", icmpHdr.Ident(), icmpHdr.Sequence())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ipv6", func(t *testing.T) {
|
||||||
|
request := []byte{
|
||||||
|
byte(header.ICMPv6EchoRequest), 0,
|
||||||
|
0, 0,
|
||||||
|
0xab, 0xcd,
|
||||||
|
0xef, 0x01,
|
||||||
|
0xaa, 0xbb, 0xcc,
|
||||||
|
}
|
||||||
|
src := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
|
||||||
|
dst := tcpip.AddrFromSlice([]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2})
|
||||||
|
if err := RewriteChecksum(header.IPv6ProtocolNumber, request, src, dst); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := BuildLocalEchoReply(header.IPv6ProtocolNumber, request, dst, src)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if request[0] != byte(header.ICMPv6EchoRequest) {
|
||||||
|
t.Fatal("request mutated")
|
||||||
|
}
|
||||||
|
icmpHdr := header.ICMPv6(reply)
|
||||||
|
if icmpHdr.Type() != header.ICMPv6EchoReply || icmpHdr.Code() != header.ICMPv6UnusedCode {
|
||||||
|
t.Fatalf("unexpected ipv6 reply type/code: %d/%d", icmpHdr.Type(), icmpHdr.Code())
|
||||||
|
}
|
||||||
|
if icmpHdr.Ident() != 0xabcd || icmpHdr.Sequence() != 0xef01 {
|
||||||
|
t.Fatalf("unexpected ipv6 ident/sequence: %x/%x", icmpHdr.Ident(), icmpHdr.Sequence())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func checksumPayloadV4(payload []byte) uint16 {
|
||||||
|
return checksum.Checksum(payload, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checksumPayloadV6(payload []byte) uint16 {
|
||||||
|
return checksum.Checksum(payload, 0)
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||||
"gvisor.dev/gvisor/pkg/waiter"
|
"gvisor.dev/gvisor/pkg/waiter"
|
||||||
@@ -117,6 +118,8 @@ func (t *stackGVisor) Start() error {
|
|||||||
udpForwarder.HandlePacket(src, dst, data)
|
udpForwarder.HandlePacket(src, dst, data)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, t.handleICMPv4Packet)
|
||||||
|
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, t.handleICMPv6Packet)
|
||||||
|
|
||||||
t.stack = ipStack
|
t.stack = ipStack
|
||||||
t.endpoint = linkEndpoint
|
t.endpoint = linkEndpoint
|
||||||
@@ -205,7 +208,7 @@ func (t *stackGVisor) Close() error {
|
|||||||
func createStack(ep stack.LinkEndpoint) (*stack.Stack, error) {
|
func createStack(ep stack.LinkEndpoint) (*stack.Stack, error) {
|
||||||
opts := stack.Options{
|
opts := stack.Options{
|
||||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||||
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
|
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},
|
||||||
HandleLocal: false,
|
HandleLocal: false,
|
||||||
}
|
}
|
||||||
gStack := stack.New(opts)
|
gStack := stack.New(opts)
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
tunicmp "github.com/xtls/xray-core/proxy/tun/icmp"
|
||||||
|
"gvisor.dev/gvisor/pkg/buffer"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *stackGVisor) handleICMPv4Packet(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||||
|
return t.handleICMPEchoPacket(header.IPv4ProtocolNumber, id, pkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stackGVisor) handleICMPv6Packet(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||||
|
return t.handleICMPEchoPacket(header.IPv6ProtocolNumber, id, pkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stackGVisor) handleICMPEchoPacket(netProto tcpip.NetworkProtocolNumber, id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||||
|
srcIP := id.RemoteAddress
|
||||||
|
dstIP := id.LocalAddress
|
||||||
|
if srcIP.Len() == 0 || dstIP.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
message := transportPacketBytes(pkt)
|
||||||
|
ident, sequence, ok := tunicmp.ParseEchoRequest(netProto, message)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := tunicmp.BuildLocalEchoReply(netProto, message, dstIP, srcIP)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogInfoInner(t.ctx, err, "[tun] failed to build local icmp echo reply")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.LogDebug(t.ctx, "[tun][icmp] ", tunicmp.ProtocolLabel(netProto), " local echo reply ", dstIP, " -> ", srcIP, " id=", ident, " seq=", sequence)
|
||||||
|
if err := t.writeRawICMPPacket(netProto, reply, dstIP, srcIP); err != nil {
|
||||||
|
errors.LogInfoInner(t.ctx, err, "[tun] failed to write local icmp echo reply")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *stackGVisor) writeRawICMPPacket(netProto tcpip.NetworkProtocolNumber, message []byte, srcIP, dstIP tcpip.Address) error {
|
||||||
|
ipHeaderSize := header.IPv6MinimumSize
|
||||||
|
ipProtocol := header.IPv6ProtocolNumber
|
||||||
|
transportProtocol := header.ICMPv6ProtocolNumber
|
||||||
|
if netProto == header.IPv4ProtocolNumber {
|
||||||
|
ipHeaderSize = header.IPv4MinimumSize
|
||||||
|
ipProtocol = header.IPv4ProtocolNumber
|
||||||
|
transportProtocol = header.ICMPv4ProtocolNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
|
ReserveHeaderBytes: ipHeaderSize,
|
||||||
|
Payload: buffer.MakeWithData(message),
|
||||||
|
})
|
||||||
|
defer pkt.DecRef()
|
||||||
|
|
||||||
|
if netProto == header.IPv4ProtocolNumber {
|
||||||
|
ipHdr := header.IPv4(pkt.NetworkHeader().Push(header.IPv4MinimumSize))
|
||||||
|
ipHdr.Encode(&header.IPv4Fields{
|
||||||
|
TotalLength: uint16(header.IPv4MinimumSize + len(message)),
|
||||||
|
TTL: 64,
|
||||||
|
Protocol: uint8(transportProtocol),
|
||||||
|
SrcAddr: srcIP,
|
||||||
|
DstAddr: dstIP,
|
||||||
|
})
|
||||||
|
ipHdr.SetChecksum(^ipHdr.CalculateChecksum())
|
||||||
|
} else {
|
||||||
|
ipHdr := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
|
||||||
|
ipHdr.Encode(&header.IPv6Fields{
|
||||||
|
PayloadLength: uint16(len(message)),
|
||||||
|
TransportProtocol: transportProtocol,
|
||||||
|
HopLimit: 64,
|
||||||
|
SrcAddr: srcIP,
|
||||||
|
DstAddr: dstIP,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := t.stack.WriteRawPacket(defaultNIC, ipProtocol, buffer.MakeWithView(pkt.ToView())); err != nil {
|
||||||
|
return errors.New("failed to write raw icmp packet back to stack", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func transportPacketBytes(pkt *stack.PacketBuffer) []byte {
|
||||||
|
headerBytes := pkt.TransportHeader().Slice()
|
||||||
|
payloadBytes := pkt.Data().AsRange().ToSlice()
|
||||||
|
message := make([]byte, len(headerBytes)+len(payloadBytes))
|
||||||
|
copy(message, headerBytes)
|
||||||
|
copy(message[len(headerBytes):], payloadBytes)
|
||||||
|
return message
|
||||||
|
}
|
||||||
@@ -177,9 +177,6 @@ func (t *WindowsTun) Start() error {
|
|||||||
|
|
||||||
if updater != nil {
|
if updater != nil {
|
||||||
t.changeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
t.changeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
||||||
if notificationType != winipcfg.MibDeleteInstance {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
updater.Update()
|
updater.Update()
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func (x *Fallback) GetXver() uint64 {
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Clients []*protocol.User `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
|
Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||||
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
||||||
Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"`
|
Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"`
|
||||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||||
@@ -149,9 +149,9 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
|
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetClients() []*protocol.User {
|
func (x *Config) GetUsers() []*protocol.User {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Clients
|
return x.Users
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -209,9 +209,9 @@ const file_proxy_vless_inbound_config_proto_rawDesc = "" +
|
|||||||
"\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n" +
|
"\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n" +
|
||||||
"\x04type\x18\x04 \x01(\tR\x04type\x12\x12\n" +
|
"\x04type\x18\x04 \x01(\tR\x04type\x12\x12\n" +
|
||||||
"\x04dest\x18\x05 \x01(\tR\x04dest\x12\x12\n" +
|
"\x04dest\x18\x05 \x01(\tR\x04dest\x12\x12\n" +
|
||||||
"\x04xver\x18\x06 \x01(\x04R\x04xver\"\x96\x02\n" +
|
"\x04xver\x18\x06 \x01(\x04R\x04xver\"\x92\x02\n" +
|
||||||
"\x06Config\x124\n" +
|
"\x06Config\x120\n" +
|
||||||
"\aclients\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\aclients\x12@\n" +
|
"\x05users\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x12@\n" +
|
||||||
"\tfallbacks\x18\x02 \x03(\v2\".xray.proxy.vless.inbound.FallbackR\tfallbacks\x12\x1e\n" +
|
"\tfallbacks\x18\x02 \x03(\v2\".xray.proxy.vless.inbound.FallbackR\tfallbacks\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"decryption\x18\x03 \x01(\tR\n" +
|
"decryption\x18\x03 \x01(\tR\n" +
|
||||||
@@ -242,7 +242,7 @@ var file_proxy_vless_inbound_config_proto_goTypes = []any{
|
|||||||
(*protocol.User)(nil), // 2: xray.common.protocol.User
|
(*protocol.User)(nil), // 2: xray.common.protocol.User
|
||||||
}
|
}
|
||||||
var file_proxy_vless_inbound_config_proto_depIdxs = []int32{
|
var file_proxy_vless_inbound_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.proxy.vless.inbound.Config.clients:type_name -> xray.common.protocol.User
|
2, // 0: xray.proxy.vless.inbound.Config.users:type_name -> xray.common.protocol.User
|
||||||
0, // 1: xray.proxy.vless.inbound.Config.fallbacks:type_name -> xray.proxy.vless.inbound.Fallback
|
0, // 1: xray.proxy.vless.inbound.Config.fallbacks:type_name -> xray.proxy.vless.inbound.Fallback
|
||||||
2, // [2:2] is the sub-list for method output_type
|
2, // [2:2] is the sub-list for method output_type
|
||||||
2, // [2:2] is the sub-list for method input_type
|
2, // [2:2] is the sub-list for method input_type
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ message Fallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
repeated xray.common.protocol.User clients = 1;
|
repeated xray.common.protocol.User users = 1;
|
||||||
repeated Fallback fallbacks = 2;
|
repeated Fallback fallbacks = 2;
|
||||||
|
|
||||||
string decryption = 3;
|
string decryption = 3;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func init() {
|
|||||||
c := config.(*Config)
|
c := config.(*Config)
|
||||||
|
|
||||||
validator := new(vless.MemoryValidator)
|
validator := new(vless.MemoryValidator)
|
||||||
for _, user := range c.Clients {
|
for _, user := range c.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
|
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
|
||||||
|
|||||||
@@ -62,16 +62,16 @@ func TestCommanderListenConfigurationItem(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "default-outbound",
|
Tag: "default-outbound",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -145,9 +145,9 @@ func TestCommanderRemoveHandler(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -157,16 +157,16 @@ func TestCommanderRemoveHandler(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "default-outbound",
|
Tag: "default-outbound",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -240,9 +240,9 @@ func TestCommanderListHandlers(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -252,9 +252,9 @@ func TestCommanderListHandlers(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -262,7 +262,7 @@ func TestCommanderListHandlers(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Tag: "default-outbound",
|
Tag: "default-outbound",
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -379,16 +379,16 @@ func TestCommanderAddRemoveUser(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -416,9 +416,9 @@ func TestCommanderAddRemoveUser(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -428,7 +428,7 @@ func TestCommanderAddRemoveUser(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: u2.String(),
|
Id: u2.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
@@ -567,16 +567,16 @@ func TestCommanderStats(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -591,9 +591,9 @@ func TestCommanderStats(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -603,7 +603,7 @@ func TestCommanderStats(t *testing.T) {
|
|||||||
Receiver: &protocol.ServerEndpoint{
|
Receiver: &protocol.ServerEndpoint{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
Address: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: uint32(serverPort),
|
Port: uint32(serverPort),
|
||||||
User: &protocol.User{
|
User: &protocol.User{
|
||||||
Account: serial.ToTypedMessage(&vmess.Account{
|
Account: serial.ToTypedMessage(&vmess.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
SecuritySettings: &protocol.SecurityConfig{
|
SecuritySettings: &protocol.SecurityConfig{
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestDokodemoTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -87,9 +87,9 @@ func TestDokodemoTCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -160,7 +160,7 @@ func TestDokodemoUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -181,9 +181,9 @@ func TestDokodemoUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,16 +53,16 @@ func TestPassiveConnection(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -123,7 +123,7 @@ func TestProxy(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,7 +152,7 @@ func TestProxy(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -167,9 +167,9 @@ func TestProxy(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -252,7 +252,7 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -281,7 +281,7 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
||||||
StreamSettings: &internet.StreamConfig{
|
StreamSettings: &internet.StreamConfig{
|
||||||
@@ -301,9 +301,9 @@ func TestProxyOverKCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -380,9 +380,9 @@ func TestBlackhole(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -391,16 +391,16 @@ func TestBlackhole(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest2.Address),
|
RewriteAddress: net.NewIPOrDomain(dest2.Address),
|
||||||
Port: uint32(dest2.Port),
|
RewritePort: uint32(dest2.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "direct",
|
Tag: "direct",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "blocked",
|
Tag: "blocked",
|
||||||
@@ -506,16 +506,16 @@ func TestUDPConnection(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -552,9 +552,9 @@ func TestDomainSniffing(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
RewriteAddress: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
Port: 443,
|
RewritePort: 443,
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -580,7 +580,7 @@ func TestDomainSniffing(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "direct",
|
Tag: "direct",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
App: []*serial.TypedMessage{
|
App: []*serial.TypedMessage{
|
||||||
@@ -667,7 +667,7 @@ func TestDialXray(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func TestHttpConformance(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -111,7 +111,7 @@ func TestHttpError(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -161,7 +161,7 @@ func TestHTTPConnectMethod(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -243,7 +243,7 @@ func TestHttpPost(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -315,7 +315,7 @@ func TestHttpBasicAuth(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,16 +54,16 @@ func TestMetrics(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "default-outbound",
|
Tag: "default-outbound",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func TestVMessClosing(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -112,9 +112,9 @@ func TestVMessClosing(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -193,7 +193,7 @@ func TestZeroBuffer(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -214,9 +214,9 @@ func TestZeroBuffer(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ func TestReverseProxy(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -142,16 +142,16 @@ func TestReverseProxy(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "freedom",
|
Tag: "freedom",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "reverse",
|
Tag: "reverse",
|
||||||
@@ -252,9 +252,9 @@ func TestReverseProxyLongRunning(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -331,16 +331,16 @@ func TestReverseProxyLongRunning(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
Tag: "freedom",
|
Tag: "freedom",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "reverse",
|
Tag: "reverse",
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func testShadowsocks2022Tcp(t *testing.T, method string, password string) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -103,9 +103,9 @@ func testShadowsocks2022Tcp(t *testing.T, method string, password string) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -167,7 +167,7 @@ func testShadowsocks2022Udp(t *testing.T, method string, password string) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -188,9 +188,9 @@ func testShadowsocks2022Udp(t *testing.T, method string, password string) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(udpDest.Address),
|
RewriteAddress: net.NewIPOrDomain(udpDest.Address),
|
||||||
Port: uint32(udpDest.Port),
|
RewritePort: uint32(udpDest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -68,9 +68,9 @@ func TestShadowsocksChaCha20Poly1305TCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -141,7 +141,7 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -162,9 +162,9 @@ func TestShadowsocksAES256GCMTCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -236,7 +236,7 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -257,9 +257,9 @@ func TestShadowsocksAES128GCMUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -330,7 +330,7 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -351,9 +351,9 @@ func TestShadowsocksAES128GCMUDPMux(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -425,7 +425,7 @@ func TestShadowsocksNone(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -440,9 +440,9 @@ func TestShadowsocksNone(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func TestSocksBridgeTCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -66,9 +66,9 @@ func TestSocksBridgeTCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -128,7 +128,7 @@ func TestSocksWithHttpRequest(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -143,9 +143,9 @@ func TestSocksWithHttpRequest(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -209,15 +209,15 @@ func TestSocksBridageUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -243,9 +243,9 @@ func TestSocksBridageUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -320,9 +320,9 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -332,7 +332,7 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: "out",
|
Tag: "out",
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -358,9 +358,9 @@ func TestSocksBridageUDPWithRouting(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -429,7 +429,7 @@ func TestSocksConformanceMod(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func TestSimpleTLSConnection(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -84,9 +84,9 @@ func TestSimpleTLSConnection(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -182,7 +182,7 @@ func TestAutoIssuingCertificate(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -197,9 +197,9 @@ func TestAutoIssuingCertificate(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -287,7 +287,7 @@ func TestTLSOverKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -302,9 +302,9 @@ func TestTLSOverKCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -387,7 +387,7 @@ func TestTLSOverWebSocket(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -402,9 +402,9 @@ func TestTLSOverWebSocket(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -503,7 +503,7 @@ func TestGRPC(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -518,9 +518,9 @@ func TestGRPC(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -619,7 +619,7 @@ func TestGRPCMultiMode(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -634,9 +634,9 @@ func TestGRPCMultiMode(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -728,7 +728,7 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -743,9 +743,9 @@ func TestSimpleTLSConnectionPinned(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -827,7 +827,7 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -842,9 +842,9 @@ func TestSimpleTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -925,7 +925,7 @@ func TestUTLSConnectionPinned(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -940,9 +940,9 @@ func TestUTLSConnectionPinned(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1025,7 +1025,7 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1040,9 +1040,9 @@ func TestUTLSConnectionPinnedWrongCert(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func TestHTTPConnectionHeader(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -78,9 +78,9 @@ func TestHTTPConnectionHeader(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func TestVless(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -67,7 +67,7 @@ func TestVless(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -88,9 +88,9 @@ func TestVless(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -159,7 +159,7 @@ func TestVlessTls(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -172,7 +172,7 @@ func TestVlessTls(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -193,9 +193,9 @@ func TestVlessTls(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -281,7 +281,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -295,7 +295,7 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -316,9 +316,9 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -413,7 +413,7 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -427,7 +427,7 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -448,9 +448,9 @@ func TestVlessXtlsVisionReality(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -553,7 +553,7 @@ func TestVlessRealityFingerprints(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -566,7 +566,7 @@ func TestVlessRealityFingerprints(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -586,9 +586,9 @@ func TestVlessRealityFingerprints(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func TestVMessGCM(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -83,9 +83,9 @@ func TestVMessGCM(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -162,7 +162,7 @@ func TestVMessGCMReadv(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -183,9 +183,9 @@ func TestVMessGCMReadv(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -265,7 +265,7 @@ func TestVMessGCMUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -286,9 +286,9 @@ func TestVMessGCMUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -362,7 +362,7 @@ func TestVMessChacha20(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -383,9 +383,9 @@ func TestVMessChacha20(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -460,7 +460,7 @@ func TestVMessNone(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -481,9 +481,9 @@ func TestVMessNone(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -560,7 +560,7 @@ func TestVMessKCP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -581,9 +581,9 @@ func TestVMessKCP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -665,7 +665,7 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -686,9 +686,9 @@ func TestVMessKCPLarge(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -771,7 +771,7 @@ func TestVMessGCMMux(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -792,9 +792,9 @@ func TestVMessGCMMux(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -884,7 +884,7 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -906,9 +906,9 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -917,9 +917,9 @@ func TestVMessGCMMuxUDP(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(udpDest.Address),
|
RewriteAddress: net.NewIPOrDomain(udpDest.Address),
|
||||||
Port: uint32(udpDest.Port),
|
RewritePort: uint32(udpDest.Port),
|
||||||
Networks: []net.Network{net.Network_UDP},
|
AllowedNetworks: []net.Network{net.Network_UDP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1007,7 +1007,7 @@ func TestVMessZero(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1028,9 +1028,9 @@ func TestVMessZero(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1104,7 +1104,7 @@ func TestVMessGCMLengthAuth(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1125,9 +1125,9 @@ func TestVMessGCMLengthAuth(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1206,7 +1206,7 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1227,9 +1227,9 @@ func TestVMessGCMLengthAuthPlusNoTerminationSignal(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func TestWireguard(t *testing.T) {
|
|||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{
|
{
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -84,9 +84,9 @@ func TestWireguard(t *testing.T) {
|
|||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
RewriteAddress: net.NewIPOrDomain(dest.Address),
|
||||||
Port: uint32(dest.Port),
|
RewritePort: uint32(dest.Port),
|
||||||
Networks: []net.Network{net.Network_TCP},
|
AllowedNetworks: []net.Network{net.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ import (
|
|||||||
var webpage []byte
|
var webpage []byte
|
||||||
|
|
||||||
type task struct {
|
type task struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Extra any `json:"extra,omitempty"`
|
Extra any `json:"extra,omitempty"`
|
||||||
StreamResponse bool `json:"streamResponse"`
|
StreamResponse bool `json:"streamResponse"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var conns chan *websocket.Conn
|
var conns chan *websocket.Conn
|
||||||
@@ -51,9 +51,9 @@ func Reload() {
|
|||||||
if HasBrowserDialer() {
|
if HasBrowserDialer() {
|
||||||
for len(conns) > 0 {
|
for len(conns) > 0 {
|
||||||
select {
|
select {
|
||||||
case c := <-conns:
|
case c := <-conns:
|
||||||
c.Close()
|
c.Close()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conns = nil
|
conns = nil
|
||||||
@@ -75,7 +75,7 @@ func Reload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*");
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
w.Write(webpage)
|
w.Write(webpage)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -94,15 +94,13 @@ type webSocketExtra struct {
|
|||||||
|
|
||||||
func DialWS(uri string, ed []byte) (*websocket.Conn, error) {
|
func DialWS(uri string, ed []byte) (*websocket.Conn, error) {
|
||||||
task := task{
|
task := task{
|
||||||
Method: "WS",
|
Method: "WS",
|
||||||
URL: uri,
|
URL: uri,
|
||||||
StreamResponse: true,
|
StreamResponse: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ed != nil {
|
task.Extra = webSocketExtra{
|
||||||
task.Extra = webSocketExtra{
|
Protocol: base64.RawURLEncoding.EncodeToString(ed),
|
||||||
Protocol: base64.RawURLEncoding.EncodeToString(ed),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialTask(task)
|
return dialTask(task)
|
||||||
@@ -144,9 +142,9 @@ func httpExtraFromHeadersAndCookies(headers http.Header, cookies []*http.Cookie)
|
|||||||
|
|
||||||
func DialGet(uri string, headers http.Header, cookies []*http.Cookie) (*websocket.Conn, error) {
|
func DialGet(uri string, headers http.Header, cookies []*http.Cookie) (*websocket.Conn, error) {
|
||||||
task := task{
|
task := task{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
URL: uri,
|
URL: uri,
|
||||||
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
|
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
|
||||||
StreamResponse: true,
|
StreamResponse: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +157,9 @@ func DialPacket(method string, uri string, headers http.Header, cookies []*http.
|
|||||||
|
|
||||||
func dialWithBody(method string, uri string, headers http.Header, cookies []*http.Cookie, payload []byte) error {
|
func dialWithBody(method string, uri string, headers http.Header, cookies []*http.Cookie, payload []byte) error {
|
||||||
task := task{
|
task := task{
|
||||||
Method: method,
|
Method: method,
|
||||||
URL: uri,
|
URL: uri,
|
||||||
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
|
Extra: httpExtraFromHeadersAndCookies(headers, cookies),
|
||||||
StreamResponse: false,
|
StreamResponse: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,4 +220,3 @@ func CheckOK(conn *websocket.Conn) error {
|
|||||||
func init() {
|
func init() {
|
||||||
Reload()
|
Reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -730,8 +730,6 @@ type SocketConfig struct {
|
|||||||
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
||||||
// option. This option is for UDP only.
|
// option. This option is for UDP only.
|
||||||
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
||||||
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
|
|
||||||
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
|
|
||||||
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
||||||
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||||
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
||||||
@@ -811,20 +809,6 @@ func (x *SocketConfig) GetReceiveOriginalDestAddress() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SocketConfig) GetBindAddress() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.BindAddress
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SocketConfig) GetBindPort() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.BindPort
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SocketConfig) GetAcceptProxyProtocol() bool {
|
func (x *SocketConfig) GetAcceptProxyProtocol() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.AcceptProxyProtocol
|
return x.AcceptProxyProtocol
|
||||||
@@ -1066,14 +1050,12 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\x05level\x18\x03 \x01(\tR\x05level\x12\x10\n" +
|
"\x05level\x18\x03 \x01(\tR\x05level\x12\x10\n" +
|
||||||
"\x03opt\x18\x04 \x01(\tR\x03opt\x12\x14\n" +
|
"\x03opt\x18\x04 \x01(\tR\x03opt\x12\x14\n" +
|
||||||
"\x05value\x18\x05 \x01(\tR\x05value\x12\x12\n" +
|
"\x05value\x18\x05 \x01(\tR\x05value\x12\x12\n" +
|
||||||
"\x04type\x18\x06 \x01(\tR\x04type\"\x89\t\n" +
|
"\x04type\x18\x06 \x01(\tR\x04type\"\xc9\b\n" +
|
||||||
"\fSocketConfig\x12\x12\n" +
|
"\fSocketConfig\x12\x12\n" +
|
||||||
"\x04mark\x18\x01 \x01(\x05R\x04mark\x12\x10\n" +
|
"\x04mark\x18\x01 \x01(\x05R\x04mark\x12\x10\n" +
|
||||||
"\x03tfo\x18\x02 \x01(\x05R\x03tfo\x12H\n" +
|
"\x03tfo\x18\x02 \x01(\x05R\x03tfo\x12H\n" +
|
||||||
"\x06tproxy\x18\x03 \x01(\x0e20.xray.transport.internet.SocketConfig.TProxyModeR\x06tproxy\x12A\n" +
|
"\x06tproxy\x18\x03 \x01(\x0e20.xray.transport.internet.SocketConfig.TProxyModeR\x06tproxy\x12A\n" +
|
||||||
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x12!\n" +
|
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x122\n" +
|
||||||
"\fbind_address\x18\x05 \x01(\fR\vbindAddress\x12\x1b\n" +
|
|
||||||
"\tbind_port\x18\x06 \x01(\rR\bbindPort\x122\n" +
|
|
||||||
"\x15accept_proxy_protocol\x18\a \x01(\bR\x13acceptProxyProtocol\x12P\n" +
|
"\x15accept_proxy_protocol\x18\a \x01(\bR\x13acceptProxyProtocol\x12P\n" +
|
||||||
"\x0fdomain_strategy\x18\b \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12!\n" +
|
"\x0fdomain_strategy\x18\b \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12!\n" +
|
||||||
"\fdialer_proxy\x18\t \x01(\tR\vdialerProxy\x125\n" +
|
"\fdialer_proxy\x18\t \x01(\tR\vdialerProxy\x125\n" +
|
||||||
|
|||||||
@@ -124,10 +124,6 @@ message SocketConfig {
|
|||||||
// option. This option is for UDP only.
|
// option. This option is for UDP only.
|
||||||
bool receive_original_dest_address = 4;
|
bool receive_original_dest_address = 4;
|
||||||
|
|
||||||
bytes bind_address = 5;
|
|
||||||
|
|
||||||
uint32 bind_port = 6;
|
|
||||||
|
|
||||||
bool accept_proxy_protocol = 7;
|
bool accept_proxy_protocol = 7;
|
||||||
|
|
||||||
DomainStrategy domain_strategy = 8;
|
DomainStrategy domain_strategy = 8;
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ func runVLESSRealityCase(t *testing.T, bin string, mode trafficMode, payloadSize
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -279,7 +279,7 @@ func runVLESSRealityCase(t *testing.T, bin string, mode trafficMode, payloadSize
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
})},
|
})},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -292,9 +292,9 @@ func runVLESSRealityCase(t *testing.T, bin string, mode trafficMode, payloadSize
|
|||||||
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: xnet.NewIPOrDomain(backend.Address()),
|
RewriteAddress: xnet.NewIPOrDomain(backend.Address()),
|
||||||
Port: uint32(backend.Port()),
|
RewritePort: uint32(backend.Port()),
|
||||||
Networks: []xnet.Network{xnet.Network_TCP},
|
AllowedNetworks: []xnet.Network{xnet.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -399,7 +399,7 @@ func runHysteria2Case(t *testing.T, bin string, mode trafficMode, payloadSize in
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
})},
|
})},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -412,9 +412,9 @@ func runHysteria2Case(t *testing.T, bin string, mode trafficMode, payloadSize in
|
|||||||
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: xnet.NewIPOrDomain(backend.Address()),
|
RewriteAddress: xnet.NewIPOrDomain(backend.Address()),
|
||||||
Port: uint32(backend.Port()),
|
RewritePort: uint32(backend.Port()),
|
||||||
Networks: []xnet.Network{xnet.Network_TCP},
|
AllowedNetworks: []xnet.Network{xnet.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -501,7 +501,7 @@ func runVLesseEncCase(t *testing.T, bin string, mode trafficMode, payloadSize in
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -517,7 +517,7 @@ func runVLesseEncCase(t *testing.T, bin string, mode trafficMode, payloadSize in
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
})},
|
})},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -530,9 +530,9 @@ func runVLesseEncCase(t *testing.T, bin string, mode trafficMode, payloadSize in
|
|||||||
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: xnet.NewIPOrDomain(backend.Address()),
|
RewriteAddress: xnet.NewIPOrDomain(backend.Address()),
|
||||||
Port: uint32(backend.Port()),
|
RewritePort: uint32(backend.Port()),
|
||||||
Networks: []xnet.Network{xnet.Network_TCP},
|
AllowedNetworks: []xnet.Network{xnet.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -605,7 +605,7 @@ func runVLESSXHTTPCase(t *testing.T, bin string, mode trafficMode, payloadSize i
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
ProxySettings: serial.ToTypedMessage(&vin.Config{
|
||||||
Clients: []*protocol.User{
|
Users: []*protocol.User{
|
||||||
{
|
{
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
Account: serial.ToTypedMessage(&vless.Account{
|
||||||
Id: userID.String(),
|
Id: userID.String(),
|
||||||
@@ -617,7 +617,7 @@ func runVLESSXHTTPCase(t *testing.T, bin string, mode trafficMode, payloadSize i
|
|||||||
},
|
},
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
Outbound: []*core.OutboundHandlerConfig{
|
||||||
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
{ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
IpsBlocked: &freedom.IPRules{},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
})},
|
})},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -630,9 +630,9 @@ func runVLESSXHTTPCase(t *testing.T, bin string, mode trafficMode, payloadSize i
|
|||||||
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
Listen: xnet.NewIPOrDomain(xnet.LocalHostIP),
|
||||||
}),
|
}),
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
||||||
Address: xnet.NewIPOrDomain(backend.Address()),
|
RewriteAddress: xnet.NewIPOrDomain(backend.Address()),
|
||||||
Port: uint32(backend.Port()),
|
RewritePort: uint32(backend.Port()),
|
||||||
Networks: []xnet.Network{xnet.Network_TCP},
|
AllowedNetworks: []xnet.Network{xnet.Network_TCP},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -85,9 +85,9 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
|
|||||||
if ip == nil {
|
if ip == nil {
|
||||||
return nil, errors.New("invalid ip address")
|
return nil, errors.New("invalid ip address")
|
||||||
}
|
}
|
||||||
port, _ := strconv.Atoi(p)
|
port, err := strconv.Atoi(p)
|
||||||
if port == 0 {
|
if err != nil {
|
||||||
return nil, errors.New("invalid port")
|
return nil, errors.New("invalid port").Base(err)
|
||||||
}
|
}
|
||||||
addr := &net.UDPAddr{IP: ip, Port: port}
|
addr := &net.UDPAddr{IP: ip, Port: port}
|
||||||
resolverAddrs = append(resolverAddrs, addr)
|
resolverAddrs = append(resolverAddrs, addr)
|
||||||
|
|||||||
@@ -1,45 +1,82 @@
|
|||||||
package hysteria
|
package hysteria
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/proxy/hysteria/account"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/padding"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
closeErrCodeOK = 0x100 // HTTP3 ErrCodeNoError
|
closeErrCodeOK = 0x100 // HTTP3 ErrCodeNoError
|
||||||
closeErrCodeProtocolError = 0x101 // HTTP3 ErrCodeGeneralProtocolError
|
closeErrCodeProtocolError = 0x101 // HTTP3 ErrCodeGeneralProtocolError
|
||||||
|
URLHost = "hysteria"
|
||||||
MaxDatagramFrameSize = 1200
|
URLPath = "/auth"
|
||||||
|
RequestHeaderAuth = "Hysteria-Auth"
|
||||||
URLHost = "hysteria"
|
ResponseHeaderUDPEnabled = "Hysteria-UDP"
|
||||||
URLPath = "/auth"
|
CommonHeaderCCRX = "Hysteria-CC-RX"
|
||||||
|
CommonHeaderPadding = "Hysteria-Padding"
|
||||||
RequestHeaderAuth = "Hysteria-Auth"
|
StatusAuthOK = 233
|
||||||
ResponseHeaderUDPEnabled = "Hysteria-UDP"
|
FrameTypeTCPRequest = 0x401
|
||||||
CommonHeaderCCRX = "Hysteria-CC-RX"
|
MaxDatagramFrameSize = 1200
|
||||||
CommonHeaderPadding = "Hysteria-Padding"
|
udpMessageChanSize = 1024
|
||||||
|
idleCleanupInterval = 1 * time.Second
|
||||||
StatusAuthOK = 233
|
|
||||||
|
|
||||||
udpMessageChanSize = 1024
|
|
||||||
|
|
||||||
FrameTypeTCPRequest = 0x401
|
|
||||||
|
|
||||||
idleCleanupInterval = 1 * time.Second
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
authRequestPadding = padding.Padding{Min: 256, Max: 2048}
|
|
||||||
authResponsePadding = padding.Padding{Min: 256, Max: 2048}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Status int
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusUnknown Status = iota
|
paddingChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
)
|
||||||
|
|
||||||
|
type padding struct {
|
||||||
|
Min int
|
||||||
|
Max int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p padding) String() string {
|
||||||
|
n := p.Min + rand.Intn(p.Max-p.Min)
|
||||||
|
bs := make([]byte, n)
|
||||||
|
for i := range bs {
|
||||||
|
bs[i] = paddingChars[rand.Intn(len(paddingChars))]
|
||||||
|
}
|
||||||
|
return string(bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
AuthRequestPadding = padding{Min: 256, Max: 2048}
|
||||||
|
AuthResponsePadding = padding{Min: 256, Max: 2048}
|
||||||
|
TcpRequestPadding = padding{Min: 64, Max: 512}
|
||||||
|
TcpResponsePadding = padding{Min: 128, Max: 1024}
|
||||||
|
)
|
||||||
|
|
||||||
|
type datagramKey struct{}
|
||||||
|
|
||||||
|
func ContextWithDatagram(ctx context.Context, v bool) context.Context {
|
||||||
|
return context.WithValue(ctx, datagramKey{}, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DatagramFromContext(ctx context.Context) bool {
|
||||||
|
v, _ := ctx.Value(datagramKey{}).(bool)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type validatorKey struct{}
|
||||||
|
|
||||||
|
func ContextWithValidator(ctx context.Context, v *account.Validator) context.Context {
|
||||||
|
return context.WithValue(ctx, validatorKey{}, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidatorFromContext(ctx context.Context) *account.Validator {
|
||||||
|
v, _ := ctx.Value(validatorKey{}).(*account.Validator)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type status int
|
||||||
|
|
||||||
|
const (
|
||||||
|
StatusNull status = iota
|
||||||
StatusActive
|
StatusActive
|
||||||
StatusInactive
|
StatusInactive
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hysteria
|
package hysteria
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -8,8 +9,10 @@ import (
|
|||||||
|
|
||||||
"github.com/apernet/quic-go"
|
"github.com/apernet/quic-go"
|
||||||
"github.com/apernet/quic-go/quicvarint"
|
"github.com/apernet/quic-go/quicvarint"
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type interConn struct {
|
type interConn struct {
|
||||||
@@ -18,144 +21,278 @@ type interConn struct {
|
|||||||
remote net.Addr
|
remote net.Addr
|
||||||
|
|
||||||
client bool
|
client bool
|
||||||
mutex sync.Mutex
|
user *protocol.MemoryUser
|
||||||
|
|
||||||
user *protocol.MemoryUser
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) User() *protocol.MemoryUser {
|
func (c *interConn) User() *protocol.MemoryUser {
|
||||||
return i.user
|
return c.user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) Read(b []byte) (int, error) {
|
func (c *interConn) Read(b []byte) (int, error) {
|
||||||
return i.stream.Read(b)
|
return c.stream.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) Write(b []byte) (int, error) {
|
func (c *interConn) Write(b []byte) (int, error) {
|
||||||
if i.client {
|
if c.client {
|
||||||
i.mutex.Lock()
|
c.client = false
|
||||||
defer i.mutex.Unlock()
|
if _, err := c.stream.Write(append(quicvarint.Append(nil, FrameTypeTCPRequest), b...)); err != nil {
|
||||||
if i.client {
|
return 0, err
|
||||||
buf := make([]byte, 0, quicvarint.Len(FrameTypeTCPRequest)+len(b))
|
|
||||||
buf = quicvarint.Append(buf, FrameTypeTCPRequest)
|
|
||||||
buf = append(buf, b...)
|
|
||||||
_, err := i.stream.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
i.client = false
|
|
||||||
return len(b), nil
|
|
||||||
}
|
}
|
||||||
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return i.stream.Write(b)
|
return c.stream.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) Close() error {
|
func (c *interConn) Close() error {
|
||||||
i.stream.CancelRead(0)
|
c.stream.CancelRead(0)
|
||||||
return i.stream.Close()
|
return c.stream.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) LocalAddr() net.Addr {
|
func (c *interConn) LocalAddr() net.Addr {
|
||||||
return i.local
|
return c.local
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) RemoteAddr() net.Addr {
|
func (c *interConn) RemoteAddr() net.Addr {
|
||||||
return i.remote
|
return c.remote
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) SetDeadline(t time.Time) error {
|
func (c *interConn) SetDeadline(t time.Time) error {
|
||||||
return i.stream.SetDeadline(t)
|
return c.stream.SetDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) SetReadDeadline(t time.Time) error {
|
func (c *interConn) SetReadDeadline(t time.Time) error {
|
||||||
return i.stream.SetReadDeadline(t)
|
return c.stream.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interConn) SetWriteDeadline(t time.Time) error {
|
func (c *interConn) SetWriteDeadline(t time.Time) error {
|
||||||
return i.stream.SetWriteDeadline(t)
|
return c.stream.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
type InterUdpConn struct {
|
type InterConn struct {
|
||||||
conn *quic.Conn
|
|
||||||
local net.Addr
|
local net.Addr
|
||||||
remote net.Addr
|
remote net.Addr
|
||||||
|
|
||||||
id uint32
|
id uint32
|
||||||
ch chan []byte
|
ch chan []byte
|
||||||
|
time time.Time
|
||||||
|
mutex sync.Mutex
|
||||||
|
closed bool
|
||||||
|
|
||||||
closed bool
|
write func(p []byte) error
|
||||||
closeFunc func()
|
close func()
|
||||||
|
user *protocol.MemoryUser
|
||||||
last time.Time
|
|
||||||
mutex sync.Mutex
|
|
||||||
|
|
||||||
user *protocol.MemoryUser
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) User() *protocol.MemoryUser {
|
func (i *InterConn) User() *protocol.MemoryUser {
|
||||||
return i.user
|
return i.user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) SetLast() {
|
func (c *InterConn) Time() time.Time {
|
||||||
i.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer i.mutex.Unlock()
|
v := c.time
|
||||||
|
c.mutex.Unlock()
|
||||||
i.last = time.Now()
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) GetLast() time.Time {
|
func (c *InterConn) Update() {
|
||||||
i.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer i.mutex.Unlock()
|
c.time = time.Now()
|
||||||
|
c.mutex.Unlock()
|
||||||
return i.last
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) Read(p []byte) (int, error) {
|
func (c *InterConn) Read(p []byte) (int, error) {
|
||||||
b, ok := <-i.ch
|
b, ok := <-c.ch
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
n := copy(p, b)
|
if len(p) < len(b) {
|
||||||
if n != len(b) {
|
|
||||||
return 0, io.ErrShortBuffer
|
return 0, io.ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
c.Update()
|
||||||
i.SetLast()
|
return copy(p, b), nil
|
||||||
return n, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) Write(p []byte) (int, error) {
|
func (c *InterConn) Write(p []byte) (int, error) {
|
||||||
i.SetLast()
|
if c.closed {
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
binary.BigEndian.PutUint32(p, i.id)
|
}
|
||||||
if err := i.conn.SendDatagram(p); err != nil {
|
binary.BigEndian.PutUint32(p, c.id)
|
||||||
|
if err := c.write(p); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
c.Update()
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) Close() error {
|
func (c *InterConn) Close() error {
|
||||||
i.closeFunc()
|
c.close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) LocalAddr() net.Addr {
|
func (c *InterConn) LocalAddr() net.Addr {
|
||||||
return i.local
|
return c.local
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) RemoteAddr() net.Addr {
|
func (c *InterConn) RemoteAddr() net.Addr {
|
||||||
return i.remote
|
return c.remote
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) SetDeadline(t time.Time) error {
|
func (c *InterConn) SetDeadline(t time.Time) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) SetReadDeadline(t time.Time) error {
|
func (c *InterConn) SetReadDeadline(t time.Time) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterUdpConn) SetWriteDeadline(t time.Time) error {
|
func (c *InterConn) SetWriteDeadline(t time.Time) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type udpSessionManager struct {
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
|
conn *quic.Conn
|
||||||
|
m map[uint32]*InterConn
|
||||||
|
next uint32
|
||||||
|
closed bool
|
||||||
|
|
||||||
|
addConn internet.ConnHandler
|
||||||
|
udpIdleTimeout time.Duration
|
||||||
|
user *protocol.MemoryUser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *udpSessionManager) close(udpConn *InterConn) {
|
||||||
|
if !udpConn.closed {
|
||||||
|
udpConn.closed = true
|
||||||
|
close(udpConn.ch)
|
||||||
|
delete(m.m, udpConn.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *udpSessionManager) clean() {
|
||||||
|
ticker := time.NewTicker(idleCleanupInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
if m.closed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.RLock()
|
||||||
|
now := time.Now()
|
||||||
|
timeoutConn := make([]*InterConn, 0, len(m.m))
|
||||||
|
for _, udpConn := range m.m {
|
||||||
|
if now.Sub(udpConn.Time()) > m.udpIdleTimeout {
|
||||||
|
timeoutConn = append(timeoutConn, udpConn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.RUnlock()
|
||||||
|
|
||||||
|
for _, udpConn := range timeoutConn {
|
||||||
|
m.Lock()
|
||||||
|
m.close(udpConn)
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *udpSessionManager) run() {
|
||||||
|
for {
|
||||||
|
d, err := m.conn.ReceiveDatagram(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d) < 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id := binary.BigEndian.Uint32(d[:4])
|
||||||
|
|
||||||
|
m.feed(id, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
m.closed = true
|
||||||
|
|
||||||
|
for _, udpConn := range m.m {
|
||||||
|
m.close(udpConn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *udpSessionManager) udp() (*InterConn, error) {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
if m.closed {
|
||||||
|
return nil, errors.New("closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
udpConn := &InterConn{
|
||||||
|
local: m.conn.LocalAddr(),
|
||||||
|
remote: m.conn.RemoteAddr(),
|
||||||
|
|
||||||
|
id: m.next,
|
||||||
|
ch: make(chan []byte, udpMessageChanSize),
|
||||||
|
}
|
||||||
|
udpConn.write = m.conn.SendDatagram
|
||||||
|
udpConn.close = func() {
|
||||||
|
m.Lock()
|
||||||
|
m.close(udpConn)
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
m.m[m.next] = udpConn
|
||||||
|
m.next++
|
||||||
|
|
||||||
|
return udpConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *udpSessionManager) feed(id uint32, d []byte) {
|
||||||
|
m.RLock()
|
||||||
|
udpConn, ok := m.m[id]
|
||||||
|
if ok {
|
||||||
|
select {
|
||||||
|
case udpConn.ch <- d:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
m.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.RUnlock()
|
||||||
|
|
||||||
|
if m.addConn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
|
udpConn, ok = m.m[id]
|
||||||
|
if !ok {
|
||||||
|
udpConn = &InterConn{
|
||||||
|
local: m.conn.LocalAddr(),
|
||||||
|
remote: m.conn.RemoteAddr(),
|
||||||
|
|
||||||
|
id: id,
|
||||||
|
ch: make(chan []byte, udpMessageChanSize),
|
||||||
|
time: time.Now(),
|
||||||
|
}
|
||||||
|
udpConn.write = m.conn.SendDatagram
|
||||||
|
udpConn.close = func() {
|
||||||
|
m.Lock()
|
||||||
|
m.close(udpConn)
|
||||||
|
m.Unlock()
|
||||||
|
}
|
||||||
|
udpConn.user = m.user
|
||||||
|
m.m[id] = udpConn
|
||||||
|
m.addConn(udpConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case udpConn.ch <- d:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package hysteria
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_tls "crypto/tls"
|
go_tls "crypto/tls"
|
||||||
"encoding/binary"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -18,8 +18,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/net/cnc"
|
"github.com/xtls/xray-core/common/net/cnc"
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
||||||
@@ -29,107 +27,25 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
type udpSessionManagerClient struct {
|
|
||||||
conn *quic.Conn
|
|
||||||
m map[uint32]*InterUdpConn
|
|
||||||
next uint32
|
|
||||||
closed bool
|
|
||||||
mutex sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerClient) close(udpConn *InterUdpConn) {
|
|
||||||
if !udpConn.closed {
|
|
||||||
udpConn.closed = true
|
|
||||||
close(udpConn.ch)
|
|
||||||
delete(m.m, udpConn.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerClient) run() {
|
|
||||||
for {
|
|
||||||
d, err := m.conn.ReceiveDatagram(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(d) < 4 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
id := binary.BigEndian.Uint32(d[:4])
|
|
||||||
|
|
||||||
m.feed(id, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
m.closed = true
|
|
||||||
|
|
||||||
for _, udpConn := range m.m {
|
|
||||||
m.close(udpConn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerClient) udp() (*InterUdpConn, error) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
if m.closed {
|
|
||||||
return nil, errors.New("closed")
|
|
||||||
}
|
|
||||||
|
|
||||||
udpConn := &InterUdpConn{
|
|
||||||
conn: m.conn,
|
|
||||||
local: m.conn.LocalAddr(),
|
|
||||||
remote: m.conn.RemoteAddr(),
|
|
||||||
|
|
||||||
id: m.next,
|
|
||||||
ch: make(chan []byte, udpMessageChanSize),
|
|
||||||
}
|
|
||||||
udpConn.closeFunc = func() {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
m.close(udpConn)
|
|
||||||
}
|
|
||||||
m.m[m.next] = udpConn
|
|
||||||
m.next++
|
|
||||||
|
|
||||||
return udpConn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerClient) feed(id uint32, d []byte) {
|
|
||||||
m.mutex.RLock()
|
|
||||||
defer m.mutex.RUnlock()
|
|
||||||
|
|
||||||
udpConn, ok := m.m[id]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case udpConn.ch <- d:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
ctx context.Context
|
sync.Mutex
|
||||||
|
|
||||||
dest net.Destination
|
dest net.Destination
|
||||||
pktConn net.PacketConn
|
|
||||||
conn *quic.Conn
|
|
||||||
config *Config
|
config *Config
|
||||||
tlsConfig *go_tls.Config
|
tlsConfig *go_tls.Config
|
||||||
socketConfig *internet.SocketConfig
|
socketConfig *internet.SocketConfig
|
||||||
udpmaskManager *finalmask.UdpmaskManager
|
udpmaskManager *finalmask.UdpmaskManager
|
||||||
quicParams *internet.QuicParams
|
quicParams *internet.QuicParams
|
||||||
|
|
||||||
udpSM *udpSessionManagerClient
|
conn *quic.Conn
|
||||||
mutex sync.Mutex
|
tr *quic.Transport
|
||||||
|
pktConn net.PacketConn
|
||||||
|
udpSM *udpSessionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) status() Status {
|
func (c *client) status() status {
|
||||||
if c.conn == nil {
|
if c.conn == nil {
|
||||||
return StatusUnknown
|
return StatusNull
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-c.conn.Context().Done():
|
case <-c.conn.Context().Done():
|
||||||
@@ -140,14 +56,16 @@ func (c *client) status() Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) close() {
|
func (c *client) close() {
|
||||||
_ = c.conn.CloseWithError(closeErrCodeOK, "")
|
c.conn.CloseWithError(closeErrCodeOK, "")
|
||||||
_ = c.pktConn.Close()
|
c.tr.Close()
|
||||||
c.pktConn = nil
|
c.pktConn.Close()
|
||||||
c.conn = nil
|
c.conn = nil
|
||||||
|
c.tr = nil
|
||||||
|
c.pktConn = nil
|
||||||
c.udpSM = nil
|
c.udpSM = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) dial() error {
|
func (c *client) dial(ctx context.Context) error {
|
||||||
status := c.status()
|
status := c.status()
|
||||||
if status == StatusActive {
|
if status == StatusActive {
|
||||||
return nil
|
return nil
|
||||||
@@ -164,61 +82,6 @@ func (c *client) dial() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var index int
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
|
||||||
index = rand.Intn(len(quicParams.UdpHop.Ports))
|
|
||||||
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
raw, err := internet.DialSystem(c.ctx, c.dest, c.socketConfig)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to dial to dest").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
|
||||||
var remote *net.UDPAddr
|
|
||||||
|
|
||||||
switch conn := raw.(type) {
|
|
||||||
case *internet.PacketConnWrapper:
|
|
||||||
pktConn = conn.PacketConn
|
|
||||||
remote = conn.RemoteAddr().(*net.UDPAddr)
|
|
||||||
case *net.UDPConn:
|
|
||||||
pktConn = conn
|
|
||||||
remote = conn.RemoteAddr().(*net.UDPAddr)
|
|
||||||
case *cnc.Connection:
|
|
||||||
fakeConn := &internet.FakePacketConn{Conn: conn}
|
|
||||||
pktConn = fakeConn
|
|
||||||
remote = fakeConn.RemoteAddr().(*net.UDPAddr)
|
|
||||||
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
|
||||||
raw.Close()
|
|
||||||
return errors.New("udphop requires being at the outermost level")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
raw.Close()
|
|
||||||
return errors.New("unknown conn ", reflect.TypeOf(conn))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
|
||||||
addr := &udphop.UDPHopAddr{
|
|
||||||
IP: remote.IP,
|
|
||||||
Ports: quicParams.UdpHop.Ports,
|
|
||||||
}
|
|
||||||
pktConn, err = udphop.NewUDPHopPacketConn(addr, index, quicParams.UdpHop.IntervalMin, quicParams.UdpHop.IntervalMax, c.udphopDialer, pktConn)
|
|
||||||
if err != nil {
|
|
||||||
raw.Close()
|
|
||||||
return errors.New("udphop err").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.udpmaskManager != nil {
|
|
||||||
pktConn, err = c.udpmaskManager.WrapPacketConnClient(pktConn)
|
|
||||||
if err != nil {
|
|
||||||
raw.Close()
|
|
||||||
return errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quicConfig := &quic.Config{
|
quicConfig := &quic.Config{
|
||||||
InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
|
InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
|
||||||
MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
|
MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
|
||||||
@@ -226,9 +89,10 @@ func (c *client) dial() error {
|
|||||||
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
|
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
|
||||||
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
|
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
|
||||||
KeepAlivePeriod: time.Duration(quicParams.KeepAlivePeriod) * time.Second,
|
KeepAlivePeriod: time.Duration(quicParams.KeepAlivePeriod) * time.Second,
|
||||||
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
|
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery || (runtime.GOOS != "linux" && runtime.GOOS != "windows" && runtime.GOOS != "darwin"),
|
||||||
EnableDatagrams: true,
|
EnableDatagrams: true,
|
||||||
MaxDatagramFrameSize: MaxDatagramFrameSize,
|
MaxDatagramFrameSize: MaxDatagramFrameSize,
|
||||||
|
OmitMaxDatagramFrameSize: time.Now().After(time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)),
|
||||||
DisablePathManager: true,
|
DisablePathManager: true,
|
||||||
}
|
}
|
||||||
if quicParams.InitStreamReceiveWindow == 0 {
|
if quicParams.InitStreamReceiveWindow == 0 {
|
||||||
@@ -250,16 +114,80 @@ func (c *client) dial() error {
|
|||||||
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var quicConn *quic.Conn
|
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||||
|
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||||
|
return nil, errors.New("")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pktConn net.PacketConn
|
||||||
|
|
||||||
|
switch c := conn.(type) {
|
||||||
|
case *internet.PacketConnWrapper:
|
||||||
|
pktConn = c.PacketConn
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pktConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pktConn net.PacketConn
|
||||||
|
var udpAddr *net.UDPAddr
|
||||||
|
if len(quicParams.UdpHop.Ports) > 0 {
|
||||||
|
index := rand.Intn(len(quicParams.UdpHop.Ports))
|
||||||
|
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
||||||
|
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to dial to dest").Base(err)
|
||||||
|
}
|
||||||
|
switch c := conn.(type) {
|
||||||
|
case *internet.PacketConnWrapper:
|
||||||
|
pktConn = c.PacketConn
|
||||||
|
udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
|
||||||
|
} else {
|
||||||
|
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to dial to dest").Base(err)
|
||||||
|
}
|
||||||
|
switch c := conn.(type) {
|
||||||
|
case *internet.PacketConnWrapper:
|
||||||
|
pktConn = c.PacketConn
|
||||||
|
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||||
|
case *cnc.Connection:
|
||||||
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.udpmaskManager != nil {
|
||||||
|
newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn)
|
||||||
|
if err != nil {
|
||||||
|
pktConn.Close()
|
||||||
|
return errors.New("mask err").Base(err)
|
||||||
|
}
|
||||||
|
pktConn = newConn
|
||||||
|
}
|
||||||
|
|
||||||
|
tr := &quic.Transport{Conn: pktConn}
|
||||||
|
|
||||||
|
var conn *quic.Conn
|
||||||
rt := &http3.Transport{
|
rt := &http3.Transport{
|
||||||
TLSClientConfig: c.tlsConfig,
|
TLSClientConfig: c.tlsConfig,
|
||||||
QUICConfig: quicConfig,
|
QUICConfig: quicConfig,
|
||||||
Dial: func(ctx context.Context, _ string, tlsCfg *go_tls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
Dial: func(ctx context.Context, _ string, tlsCfg *go_tls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
||||||
qc, err := quic.DialEarly(ctx, pktConn, remote, tlsCfg, cfg)
|
qc, err := tr.DialEarly(ctx, udpAddr, tlsCfg, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
quicConn = qc
|
conn = qc
|
||||||
return qc, nil
|
return qc, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -273,77 +201,63 @@ func (c *client) dial() error {
|
|||||||
Header: http.Header{
|
Header: http.Header{
|
||||||
RequestHeaderAuth: []string{c.config.Auth},
|
RequestHeaderAuth: []string{c.config.Auth},
|
||||||
CommonHeaderCCRX: []string{strconv.FormatUint(quicParams.BrutalDown, 10)},
|
CommonHeaderCCRX: []string{strconv.FormatUint(quicParams.BrutalDown, 10)},
|
||||||
CommonHeaderPadding: []string{authRequestPadding.String()},
|
CommonHeaderPadding: []string{AuthRequestPadding.String()},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
resp, err := rt.RoundTrip(req)
|
resp, err := rt.RoundTrip(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if quicConn != nil {
|
if conn != nil {
|
||||||
_ = quicConn.CloseWithError(closeErrCodeProtocolError, "")
|
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
|
||||||
}
|
}
|
||||||
|
_ = tr.Close()
|
||||||
_ = pktConn.Close()
|
_ = pktConn.Close()
|
||||||
return errors.New("RoundTrip err").Base(err)
|
return err
|
||||||
}
|
}
|
||||||
if resp.StatusCode != StatusAuthOK {
|
if resp.StatusCode != StatusAuthOK {
|
||||||
_ = quicConn.CloseWithError(closeErrCodeProtocolError, "")
|
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
|
||||||
|
_ = tr.Close()
|
||||||
_ = pktConn.Close()
|
_ = pktConn.Close()
|
||||||
return errors.New("auth failed")
|
return errors.New("auth failed code ", resp.StatusCode)
|
||||||
}
|
}
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
|
|
||||||
serverUdp, _ := strconv.ParseBool(resp.Header.Get(ResponseHeaderUDPEnabled))
|
// udp, _ := strconv.ParseBool(resp.Header.Get(ResponseHeaderUDPEnabled))
|
||||||
serverAuto := resp.Header.Get(CommonHeaderCCRX)
|
down, _ := strconv.ParseUint(resp.Header.Get(CommonHeaderCCRX), 10, 64)
|
||||||
serverDown, _ := strconv.ParseUint(serverAuto, 10, 64)
|
|
||||||
|
|
||||||
switch quicParams.Congestion {
|
switch quicParams.Congestion {
|
||||||
case "reno":
|
case "reno":
|
||||||
errors.LogDebug(c.ctx, "congestion reno")
|
|
||||||
case "bbr":
|
case "bbr":
|
||||||
errors.LogDebug(c.ctx, "congestion bbr ", quicParams.BbrProfile)
|
congestion.UseBBR(conn, bbr.Profile(quicParams.BbrProfile))
|
||||||
congestion.UseBBR(quicConn, bbr.Profile(quicParams.BbrProfile))
|
case "", "brutal":
|
||||||
case "brutal", "":
|
if quicParams.BrutalUp == 0 || down == 0 {
|
||||||
if serverAuto == "auto" || quicParams.BrutalUp == 0 || serverDown == 0 {
|
congestion.UseBBR(conn, bbr.Profile(quicParams.BbrProfile))
|
||||||
errors.LogDebug(c.ctx, "congestion bbr ", quicParams.BbrProfile)
|
|
||||||
congestion.UseBBR(quicConn, bbr.Profile(quicParams.BbrProfile))
|
|
||||||
} else {
|
} else {
|
||||||
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", min(quicParams.BrutalUp, serverDown))
|
congestion.UseBrutal(conn, min(quicParams.BrutalUp, down))
|
||||||
congestion.UseBrutal(quicConn, min(quicParams.BrutalUp, serverDown))
|
|
||||||
}
|
}
|
||||||
case "force-brutal":
|
case "force-brutal":
|
||||||
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", quicParams.BrutalUp)
|
congestion.UseBrutal(conn, quicParams.BrutalUp)
|
||||||
congestion.UseBrutal(quicConn, quicParams.BrutalUp)
|
|
||||||
default:
|
default:
|
||||||
errors.LogDebug(c.ctx, "congestion reno")
|
panic(quicParams.Congestion)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.pktConn = pktConn
|
c.pktConn = pktConn
|
||||||
c.conn = quicConn
|
c.tr = tr
|
||||||
if serverUdp {
|
c.conn = conn
|
||||||
c.udpSM = &udpSessionManagerClient{
|
c.udpSM = &udpSessionManager{
|
||||||
conn: quicConn,
|
conn: conn,
|
||||||
m: make(map[uint32]*InterUdpConn),
|
m: make(map[uint32]*InterConn),
|
||||||
next: 1,
|
next: 1,
|
||||||
}
|
|
||||||
go c.udpSM.run()
|
|
||||||
}
|
}
|
||||||
|
go c.udpSM.run()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) clean() {
|
func (c *client) tcp(ctx context.Context) (stat.Connection, error) {
|
||||||
c.mutex.Lock()
|
c.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
if c.status() == StatusInactive {
|
err := c.dial(ctx)
|
||||||
c.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) tcp() (stat.Connection, error) {
|
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
|
|
||||||
err := c.dial()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -362,63 +276,24 @@ func (c *client) tcp() (stat.Connection, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) udp() (stat.Connection, error) {
|
func (c *client) udp(ctx context.Context) (stat.Connection, error) {
|
||||||
c.mutex.Lock()
|
c.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
err := c.dial()
|
err := c.dial(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.udpSM == nil {
|
|
||||||
return nil, errors.New("server does not support udp")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.udpSM.udp()
|
return c.udpSM.udp()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) setCtx(ctx context.Context) {
|
func (c *client) clean() {
|
||||||
c.mutex.Lock()
|
c.Lock()
|
||||||
defer c.mutex.Unlock()
|
if c.status() == StatusInactive {
|
||||||
|
c.close()
|
||||||
c.ctx = ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) udphopDialer(addr *net.UDPAddr) (net.PacketConn, error) {
|
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
|
|
||||||
if c.status() != StatusActive {
|
|
||||||
errors.LogDebug(context.Background(), "skip hop: disconnected QUIC")
|
|
||||||
return nil, errors.New()
|
|
||||||
}
|
}
|
||||||
|
c.Unlock()
|
||||||
raw, err := internet.DialSystem(c.ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogDebug(context.Background(), "skip hop: failed to dial to dest")
|
|
||||||
raw.Close()
|
|
||||||
return nil, errors.New()
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
|
||||||
|
|
||||||
switch conn := raw.(type) {
|
|
||||||
case *internet.PacketConnWrapper:
|
|
||||||
pktConn = conn.PacketConn
|
|
||||||
case *net.UDPConn:
|
|
||||||
pktConn = conn
|
|
||||||
case *cnc.Connection:
|
|
||||||
errors.LogDebug(context.Background(), "skip hop: udphop requires being at the outermost level")
|
|
||||||
raw.Close()
|
|
||||||
return nil, errors.New()
|
|
||||||
default:
|
|
||||||
errors.LogDebug(context.Background(), "skip hop: unknown conn ", reflect.TypeOf(conn))
|
|
||||||
raw.Close()
|
|
||||||
return nil, errors.New()
|
|
||||||
}
|
|
||||||
|
|
||||||
return pktConn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type dialerConf struct {
|
type dialerConf struct {
|
||||||
@@ -427,16 +302,18 @@ type dialerConf struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type clientManager struct {
|
type clientManager struct {
|
||||||
m map[dialerConf]*client
|
sync.RWMutex
|
||||||
mutex sync.Mutex
|
m map[dialerConf]*client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *clientManager) clean() {
|
func (m *clientManager) clean() {
|
||||||
m.mutex.Lock()
|
ticker := time.NewTicker(idleCleanupInterval)
|
||||||
defer m.mutex.Unlock()
|
for range ticker.C {
|
||||||
|
m.RLock()
|
||||||
for _, c := range m.m {
|
for _, c := range m.m {
|
||||||
c.clean()
|
c.clean()
|
||||||
|
}
|
||||||
|
m.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,44 +326,41 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
|||||||
return nil, errors.New("tls config is nil")
|
return nil, errors.New("tls config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
requireDatagram := hyCtx.RequireDatagramFromContext(ctx)
|
datagram := DatagramFromContext(ctx)
|
||||||
dest.Network = net.Network_UDP
|
dest.Network = net.Network_UDP
|
||||||
config := streamSettings.ProtocolSettings.(*Config)
|
|
||||||
|
|
||||||
initmanager.Do(func() {
|
initmanager.Do(func() {
|
||||||
manager = &clientManager{
|
manager = &clientManager{
|
||||||
m: make(map[dialerConf]*client),
|
m: make(map[dialerConf]*client),
|
||||||
}
|
}
|
||||||
(&task.Periodic{
|
go manager.clean()
|
||||||
Interval: 30 * time.Second,
|
|
||||||
Execute: func() error {
|
|
||||||
manager.clean()
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}).Start()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.mutex.Lock()
|
manager.RLock()
|
||||||
c, ok := manager.m[dialerConf{Destination: dest, MemoryStreamConfig: streamSettings}]
|
c := manager.m[dialerConf{dest, streamSettings}]
|
||||||
if !ok {
|
manager.RUnlock()
|
||||||
c = &client{
|
|
||||||
ctx: ctx,
|
|
||||||
dest: dest,
|
|
||||||
config: config,
|
|
||||||
tlsConfig: tlsConfig.GetTLSConfig(),
|
|
||||||
socketConfig: streamSettings.SocketSettings,
|
|
||||||
udpmaskManager: streamSettings.UdpmaskManager,
|
|
||||||
quicParams: streamSettings.QuicParams,
|
|
||||||
}
|
|
||||||
manager.m[dialerConf{Destination: dest, MemoryStreamConfig: streamSettings}] = c
|
|
||||||
}
|
|
||||||
c.setCtx(ctx)
|
|
||||||
manager.mutex.Unlock()
|
|
||||||
|
|
||||||
if requireDatagram {
|
if c == nil {
|
||||||
return c.udp()
|
manager.Lock()
|
||||||
|
c = manager.m[dialerConf{dest, streamSettings}]
|
||||||
|
if c == nil {
|
||||||
|
c = &client{
|
||||||
|
dest: dest,
|
||||||
|
config: streamSettings.ProtocolSettings.(*Config),
|
||||||
|
tlsConfig: tlsConfig.GetTLSConfig(),
|
||||||
|
socketConfig: streamSettings.SocketSettings,
|
||||||
|
udpmaskManager: streamSettings.UdpmaskManager,
|
||||||
|
quicParams: streamSettings.QuicParams,
|
||||||
|
}
|
||||||
|
manager.m[dialerConf{dest, streamSettings}] = c
|
||||||
|
}
|
||||||
|
manager.Unlock()
|
||||||
}
|
}
|
||||||
return c.tcp()
|
|
||||||
|
if datagram {
|
||||||
|
return c.udp(ctx)
|
||||||
|
}
|
||||||
|
return c.tcp(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package hysteria
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
gotls "crypto/tls"
|
gotls "crypto/tls"
|
||||||
"encoding/binary"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -20,158 +20,41 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/proxy/hysteria/account"
|
"github.com/xtls/xray-core/proxy/hysteria/account"
|
||||||
hyCtx "github.com/xtls/xray-core/proxy/hysteria/ctx"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
|
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
type udpSessionManagerServer struct {
|
type httpHandler struct {
|
||||||
conn *quic.Conn
|
sync.Mutex
|
||||||
m map[uint32]*InterUdpConn
|
|
||||||
addConn internet.ConnHandler
|
|
||||||
stopCh chan struct{}
|
|
||||||
udpIdleTimeout time.Duration
|
|
||||||
mutex sync.RWMutex
|
|
||||||
|
|
||||||
|
validator *account.Validator
|
||||||
|
config *Config
|
||||||
|
masqHandler http.Handler
|
||||||
|
quicParams *internet.QuicParams
|
||||||
|
addConn internet.ConnHandler
|
||||||
|
conn *quic.Conn
|
||||||
|
|
||||||
|
auth bool
|
||||||
user *protocol.MemoryUser
|
user *protocol.MemoryUser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *udpSessionManagerServer) close(udpConn *InterUdpConn) {
|
func (h *httpHandler) AuthHTTP(w http.ResponseWriter, r *http.Request) bool {
|
||||||
if !udpConn.closed {
|
|
||||||
udpConn.closed = true
|
|
||||||
close(udpConn.ch)
|
|
||||||
delete(m.m, udpConn.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerServer) clean() {
|
|
||||||
ticker := time.NewTicker(idleCleanupInterval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
m.mutex.RLock()
|
|
||||||
now := time.Now()
|
|
||||||
timeoutConn := make([]*InterUdpConn, 0, len(m.m))
|
|
||||||
for _, udpConn := range m.m {
|
|
||||||
if now.Sub(udpConn.GetLast()) > m.udpIdleTimeout {
|
|
||||||
timeoutConn = append(timeoutConn, udpConn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.mutex.RUnlock()
|
|
||||||
|
|
||||||
for _, udpConn := range timeoutConn {
|
|
||||||
m.mutex.Lock()
|
|
||||||
m.close(udpConn)
|
|
||||||
m.mutex.Unlock()
|
|
||||||
}
|
|
||||||
case <-m.stopCh:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerServer) run() {
|
|
||||||
for {
|
|
||||||
d, err := m.conn.ReceiveDatagram(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(d) < 4 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
id := binary.BigEndian.Uint32(d[:4])
|
|
||||||
|
|
||||||
m.feed(id, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
close(m.stopCh)
|
|
||||||
|
|
||||||
for _, udpConn := range m.m {
|
|
||||||
m.close(udpConn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *udpSessionManagerServer) feed(id uint32, d []byte) {
|
|
||||||
m.mutex.RLock()
|
|
||||||
udpConn, ok := m.m[id]
|
|
||||||
if ok {
|
|
||||||
select {
|
|
||||||
case udpConn.ch <- d:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
m.mutex.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.mutex.RUnlock()
|
|
||||||
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
udpConn, ok = m.m[id]
|
|
||||||
if !ok {
|
|
||||||
udpConn = &InterUdpConn{
|
|
||||||
conn: m.conn,
|
|
||||||
local: m.conn.LocalAddr(),
|
|
||||||
remote: m.conn.RemoteAddr(),
|
|
||||||
|
|
||||||
id: id,
|
|
||||||
ch: make(chan []byte, udpMessageChanSize),
|
|
||||||
last: time.Now(),
|
|
||||||
|
|
||||||
user: m.user,
|
|
||||||
}
|
|
||||||
udpConn.closeFunc = func() {
|
|
||||||
m.mutex.Lock()
|
|
||||||
m.close(udpConn)
|
|
||||||
m.mutex.Unlock()
|
|
||||||
}
|
|
||||||
m.m[id] = udpConn
|
|
||||||
m.addConn(udpConn)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case udpConn.ch <- d:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpHandler struct {
|
|
||||||
ctx context.Context
|
|
||||||
conn *quic.Conn
|
|
||||||
addConn internet.ConnHandler
|
|
||||||
|
|
||||||
config *Config
|
|
||||||
quicParams *internet.QuicParams
|
|
||||||
validator *account.Validator
|
|
||||||
masqHandler http.Handler
|
|
||||||
|
|
||||||
auth bool
|
|
||||||
mutex sync.Mutex
|
|
||||||
user *protocol.MemoryUser
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method == http.MethodPost && r.Host == URLHost && r.URL.Path == URLPath {
|
if r.Method == http.MethodPost && r.Host == URLHost && r.URL.Path == URLPath {
|
||||||
h.mutex.Lock()
|
h.Lock()
|
||||||
defer h.mutex.Unlock()
|
defer h.Unlock()
|
||||||
|
|
||||||
if h.auth {
|
if h.auth {
|
||||||
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx)))
|
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(h.validator != nil))
|
||||||
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
|
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
|
||||||
w.Header().Set(CommonHeaderPadding, authResponsePadding.String())
|
w.Header().Set(CommonHeaderPadding, AuthResponsePadding.String())
|
||||||
w.WriteHeader(StatusAuthOK)
|
w.WriteHeader(StatusAuthOK)
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := r.Header.Get(RequestHeaderAuth)
|
auth := r.Header.Get(RequestHeaderAuth)
|
||||||
clientDown, _ := strconv.ParseUint(r.Header.Get(CommonHeaderCCRX), 10, 64)
|
down, _ := strconv.ParseUint(r.Header.Get(CommonHeaderCCRX), 10, 64)
|
||||||
|
|
||||||
var user *protocol.MemoryUser
|
var user *protocol.MemoryUser
|
||||||
var ok bool
|
var ok bool
|
||||||
@@ -185,49 +68,51 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
h.auth = true
|
h.auth = true
|
||||||
h.user = user
|
h.user = user
|
||||||
|
|
||||||
switch h.quicParams.Congestion {
|
conn := h.conn
|
||||||
|
quicParams := h.quicParams
|
||||||
|
switch quicParams.Congestion {
|
||||||
case "reno":
|
case "reno":
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno")
|
|
||||||
case "bbr":
|
case "bbr":
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr ", h.quicParams.BbrProfile)
|
congestion.UseBBR(conn, bbr.Profile(quicParams.BbrProfile))
|
||||||
congestion.UseBBR(h.conn, bbr.Profile(h.quicParams.BbrProfile))
|
case "", "brutal":
|
||||||
case "brutal", "":
|
if quicParams.BrutalUp == 0 || down == 0 {
|
||||||
if h.quicParams.BrutalUp == 0 || clientDown == 0 {
|
congestion.UseBBR(conn, bbr.Profile(quicParams.BbrProfile))
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr ", h.quicParams.BbrProfile)
|
|
||||||
congestion.UseBBR(h.conn, bbr.Profile(h.quicParams.BbrProfile))
|
|
||||||
} else {
|
} else {
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", min(h.quicParams.BrutalUp, clientDown))
|
congestion.UseBrutal(conn, min(quicParams.BrutalUp, down))
|
||||||
congestion.UseBrutal(h.conn, min(h.quicParams.BrutalUp, clientDown))
|
|
||||||
}
|
}
|
||||||
case "force-brutal":
|
case "force-brutal":
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", h.quicParams.BrutalUp)
|
congestion.UseBrutal(conn, quicParams.BrutalUp)
|
||||||
congestion.UseBrutal(h.conn, h.quicParams.BrutalUp)
|
|
||||||
default:
|
default:
|
||||||
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno")
|
panic(quicParams.Congestion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hyCtx.RequireDatagramFromContext(h.ctx) {
|
if h.validator != nil {
|
||||||
udpSM := &udpSessionManagerServer{
|
udpSM := &udpSessionManager{
|
||||||
conn: h.conn,
|
conn: h.conn,
|
||||||
m: make(map[uint32]*InterUdpConn),
|
m: make(map[uint32]*InterConn),
|
||||||
addConn: h.addConn,
|
|
||||||
stopCh: make(chan struct{}),
|
|
||||||
udpIdleTimeout: time.Duration(h.config.UdpIdleTimeout) * time.Second,
|
|
||||||
|
|
||||||
user: h.user,
|
addConn: h.addConn,
|
||||||
|
udpIdleTimeout: time.Duration(h.config.UdpIdleTimeout) * time.Second,
|
||||||
|
user: h.user,
|
||||||
}
|
}
|
||||||
go udpSM.clean()
|
go udpSM.clean()
|
||||||
go udpSM.run()
|
go udpSM.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx)))
|
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(h.validator != nil))
|
||||||
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
|
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
|
||||||
w.Header().Set(CommonHeaderPadding, authResponsePadding.String())
|
w.Header().Set(CommonHeaderPadding, AuthResponsePadding.String())
|
||||||
w.WriteHeader(StatusAuthOK)
|
w.WriteHeader(StatusAuthOK)
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if h.AuthHTTP(w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
h.masqHandler.ServeHTTP(w, r)
|
h.masqHandler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,42 +141,41 @@ func (h *httpHandler) StreamDispatcher(ft http3.FrameType, stream *quic.Stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
ctx context.Context
|
|
||||||
pktConn net.PacketConn
|
|
||||||
listener *quic.Listener
|
|
||||||
addConn internet.ConnHandler
|
|
||||||
|
|
||||||
config *Config
|
|
||||||
quicParams *internet.QuicParams
|
|
||||||
validator *account.Validator
|
validator *account.Validator
|
||||||
|
config *Config
|
||||||
masqHandler http.Handler
|
masqHandler http.Handler
|
||||||
|
quicParams *internet.QuicParams
|
||||||
|
addConn internet.ConnHandler
|
||||||
|
|
||||||
|
pktConn net.PacketConn
|
||||||
|
tr *quic.Transport
|
||||||
|
listener *quic.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) handleClient(conn *quic.Conn) {
|
func (l *Listener) handleClient(conn *quic.Conn) {
|
||||||
handler := &httpHandler{
|
handler := &httpHandler{
|
||||||
ctx: l.ctx,
|
|
||||||
conn: conn,
|
|
||||||
addConn: l.addConn,
|
|
||||||
|
|
||||||
config: l.config,
|
|
||||||
quicParams: l.quicParams,
|
|
||||||
validator: l.validator,
|
validator: l.validator,
|
||||||
|
config: l.config,
|
||||||
masqHandler: l.masqHandler,
|
masqHandler: l.masqHandler,
|
||||||
|
quicParams: l.quicParams,
|
||||||
|
addConn: l.addConn,
|
||||||
|
conn: conn,
|
||||||
}
|
}
|
||||||
h3 := http3.Server{
|
h3s := http3.Server{
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
StreamDispatcher: handler.StreamDispatcher,
|
StreamDispatcher: handler.StreamDispatcher,
|
||||||
}
|
}
|
||||||
err := h3.ServeQUICConn(conn)
|
_ = h3s.ServeQUICConn(conn)
|
||||||
_ = conn.CloseWithError(closeErrCodeOK, "")
|
_ = conn.CloseWithError(closeErrCodeOK, "")
|
||||||
errors.LogDebug(context.Background(), conn.RemoteAddr(), " disconnected with err ", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) keepAccepting() {
|
func (l *Listener) keepAccepting() {
|
||||||
for {
|
for {
|
||||||
conn, err := l.listener.Accept(context.Background())
|
conn, err := l.listener.Accept(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to accept QUIC connection")
|
if err != quic.ErrServerClosed {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "failed to serve hysteria")
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
go l.handleClient(conn)
|
go l.handleClient(conn)
|
||||||
@@ -303,9 +187,7 @@ func (l *Listener) Addr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Close() error {
|
func (l *Listener) Close() error {
|
||||||
err := l.listener.Close()
|
return errors.Combine(l.listener.Close(), l.tr.Close(), l.pktConn.Close())
|
||||||
_ = l.pktConn.Close()
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
|
func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
|
||||||
@@ -318,11 +200,10 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
return nil, errors.New("tls config is nil")
|
return nil, errors.New("tls config is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validator := ValidatorFromContext(ctx)
|
||||||
config := streamSettings.ProtocolSettings.(*Config)
|
config := streamSettings.ProtocolSettings.(*Config)
|
||||||
|
|
||||||
validator := hyCtx.ValidatorFromContext(ctx)
|
if validator == nil && config.Auth == "" {
|
||||||
|
|
||||||
if config.Auth == "" && validator == nil {
|
|
||||||
return nil, errors.New("validator is nil")
|
return nil, errors.New("validator is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,22 +253,6 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
return nil, errors.New("unknown masq type")
|
return nil, errors.New("unknown masq type")
|
||||||
}
|
}
|
||||||
|
|
||||||
raw, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
|
||||||
pktConn = raw
|
|
||||||
|
|
||||||
if streamSettings.UdpmaskManager != nil {
|
|
||||||
pktConn, err = streamSettings.UdpmaskManager.WrapPacketConnServer(raw)
|
|
||||||
if err != nil {
|
|
||||||
raw.Close()
|
|
||||||
return nil, errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quicParams := streamSettings.QuicParams
|
quicParams := streamSettings.QuicParams
|
||||||
if quicParams == nil {
|
if quicParams == nil {
|
||||||
quicParams = &internet.QuicParams{
|
quicParams = &internet.QuicParams{
|
||||||
@@ -403,9 +268,10 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
|
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
|
||||||
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
|
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
|
||||||
MaxIncomingStreams: quicParams.MaxIncomingStreams,
|
MaxIncomingStreams: quicParams.MaxIncomingStreams,
|
||||||
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
|
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery || (runtime.GOOS != "linux" && runtime.GOOS != "windows" && runtime.GOOS != "darwin"),
|
||||||
EnableDatagrams: true,
|
EnableDatagrams: true,
|
||||||
MaxDatagramFrameSize: MaxDatagramFrameSize,
|
MaxDatagramFrameSize: MaxDatagramFrameSize,
|
||||||
|
AssumePeerMaxDatagramFrameSize: MaxDatagramFrameSize,
|
||||||
DisablePathManager: true,
|
DisablePathManager: true,
|
||||||
}
|
}
|
||||||
if quicParams.InitStreamReceiveWindow == 0 {
|
if quicParams.InitStreamReceiveWindow == 0 {
|
||||||
@@ -427,27 +293,44 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
|
|||||||
quicConfig.MaxIncomingStreams = 1024
|
quicConfig.MaxIncomingStreams = 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
qListener, err := quic.Listen(pktConn, tlsConfig.GetTLSConfig(), quicConfig)
|
pktConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: address.IP(), Port: int(port)}, streamSettings.SocketSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if streamSettings.UdpmaskManager != nil {
|
||||||
|
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnServer(pktConn)
|
||||||
|
if err != nil {
|
||||||
|
pktConn.Close()
|
||||||
|
return nil, errors.New("mask err").Base(err)
|
||||||
|
}
|
||||||
|
pktConn = newConn
|
||||||
|
}
|
||||||
|
|
||||||
|
tr := &quic.Transport{Conn: pktConn}
|
||||||
|
|
||||||
|
listener, err := tr.Listen(tlsConfig.GetTLSConfig(), quicConfig)
|
||||||
|
if err != nil {
|
||||||
|
_ = tr.Close()
|
||||||
_ = pktConn.Close()
|
_ = pktConn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
listener := &Listener{
|
l := &Listener{
|
||||||
ctx: ctx,
|
|
||||||
pktConn: pktConn,
|
|
||||||
listener: qListener,
|
|
||||||
addConn: handler,
|
|
||||||
|
|
||||||
config: config,
|
|
||||||
quicParams: quicParams,
|
|
||||||
validator: validator,
|
validator: validator,
|
||||||
|
config: config,
|
||||||
masqHandler: masqHandler,
|
masqHandler: masqHandler,
|
||||||
|
quicParams: quicParams,
|
||||||
|
addConn: handler,
|
||||||
|
|
||||||
|
pktConn: pktConn,
|
||||||
|
tr: tr,
|
||||||
|
listener: listener,
|
||||||
}
|
}
|
||||||
|
|
||||||
go listener.keepAccepting()
|
go l.keepAccepting()
|
||||||
|
|
||||||
return listener, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package padding
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
paddingChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
||||||
)
|
|
||||||
|
|
||||||
// padding specifies a half-open range [Min, Max).
|
|
||||||
type Padding struct {
|
|
||||||
Min int
|
|
||||||
Max int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Padding) String() string {
|
|
||||||
n := p.Min + rand.Intn(p.Max-p.Min)
|
|
||||||
bs := make([]byte, n)
|
|
||||||
for i := range bs {
|
|
||||||
bs[i] = paddingChars[rand.Intn(len(paddingChars))]
|
|
||||||
}
|
|
||||||
return string(bs)
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package udphop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InvalidPortError struct {
|
|
||||||
PortStr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e InvalidPortError) Error() string {
|
|
||||||
return fmt.Sprintf("%s is not a valid port number or range", e.PortStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UDPHopAddr contains an IP address and a list of ports.
|
|
||||||
type UDPHopAddr struct {
|
|
||||||
IP net.IP
|
|
||||||
Ports []uint32
|
|
||||||
PortStr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *UDPHopAddr) Network() string {
|
|
||||||
return "udphop"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *UDPHopAddr) String() string {
|
|
||||||
return net.JoinHostPort(a.IP.String(), a.PortStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addrs returns a list of net.Addr's, one for each port.
|
|
||||||
func (a *UDPHopAddr) addrs() ([]net.Addr, error) {
|
|
||||||
var addrs []net.Addr
|
|
||||||
for _, port := range a.Ports {
|
|
||||||
addr := &net.UDPAddr{
|
|
||||||
IP: a.IP,
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
addrs = append(addrs, addr)
|
|
||||||
}
|
|
||||||
return addrs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// func ResolveUDPHopAddr(addr string) (*UDPHopAddr, error) {
|
|
||||||
// host, portStr, err := net.SplitHostPort(addr)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// ip, err := net.ResolveIPAddr("ip", host)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// result := &UDPHopAddr{
|
|
||||||
// IP: ip.IP,
|
|
||||||
// PortStr: portStr,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pu := utils.ParsePortUnion(portStr)
|
|
||||||
// if pu == nil {
|
|
||||||
// return nil, InvalidPortError{portStr}
|
|
||||||
// }
|
|
||||||
// result.Ports = pu.Ports()
|
|
||||||
|
|
||||||
// return result, nil
|
|
||||||
// }
|
|
||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/crypto"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,19 +19,19 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UdpHopPacketConn struct {
|
type UdpHopPacketConn struct {
|
||||||
Addr net.Addr
|
|
||||||
Addrs []net.Addr
|
Addrs []net.Addr
|
||||||
HopIntervalMin int64
|
HopIntervalMin time.Duration
|
||||||
HopIntervalMax int64
|
HopIntervalMax time.Duration
|
||||||
ListenUDPFunc ListenUDPFunc
|
ListenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error)
|
||||||
|
|
||||||
connMutex sync.RWMutex
|
connMutex sync.RWMutex
|
||||||
prevConn net.PacketConn
|
prevConn net.PacketConn
|
||||||
currentConn net.PacketConn
|
currentConn net.PacketConn
|
||||||
addrIndex int
|
addrIndex int
|
||||||
|
|
||||||
readBufferSize int
|
deadline time.Time
|
||||||
writeBufferSize int
|
readDeadline time.Time
|
||||||
|
writeDeadline time.Time
|
||||||
|
|
||||||
recvQueue chan *udpPacket
|
recvQueue chan *udpPacket
|
||||||
closeChan chan struct{}
|
closeChan chan struct{}
|
||||||
@@ -48,41 +47,36 @@ type udpPacket struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenUDPFunc = func(*net.UDPAddr) (net.PacketConn, error)
|
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
|
||||||
|
if len(addrs) == 0 {
|
||||||
func NewUDPHopPacketConn(addr *UDPHopAddr, index int, intervalMin int64, intervalMax int64, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn) (net.PacketConn, error) {
|
panic("len(addrs) == 0")
|
||||||
if intervalMin == 0 || intervalMax == 0 {
|
|
||||||
intervalMin = int64(defaultHopInterval)
|
|
||||||
intervalMax = int64(defaultHopInterval)
|
|
||||||
}
|
}
|
||||||
if intervalMin < 5 || intervalMax < 5 {
|
if hopIntervalMin == 0 {
|
||||||
return nil, errors.New("hop interval must be at least 5 seconds")
|
hopIntervalMin = defaultHopInterval
|
||||||
|
}
|
||||||
|
if hopIntervalMax == 0 {
|
||||||
|
hopIntervalMax = defaultHopInterval
|
||||||
|
}
|
||||||
|
if hopIntervalMin < 5*time.Second {
|
||||||
|
panic("hopIntervalMin < 5*time.Second")
|
||||||
|
}
|
||||||
|
if hopIntervalMax < 5*time.Second {
|
||||||
|
panic("hopIntervalMax < 5*time.Second")
|
||||||
|
}
|
||||||
|
if hopIntervalMax < hopIntervalMin {
|
||||||
|
panic("hopIntervalMax < hopIntervalMin")
|
||||||
}
|
}
|
||||||
// if listenUDPFunc == nil {
|
|
||||||
// listenUDPFunc = func() (net.PacketConn, error) {
|
|
||||||
// return net.ListenUDP("udp", nil)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if listenUDPFunc == nil {
|
if listenUDPFunc == nil {
|
||||||
return nil, errors.New("nil listenUDPFunc")
|
panic("listenUDPFunc is nil")
|
||||||
}
|
}
|
||||||
addrs, err := addr.addrs()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// curConn, err := listenUDPFunc()
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
hConn := &UdpHopPacketConn{
|
hConn := &UdpHopPacketConn{
|
||||||
Addr: addr,
|
|
||||||
Addrs: addrs,
|
Addrs: addrs,
|
||||||
HopIntervalMin: intervalMin,
|
HopIntervalMin: hopIntervalMin,
|
||||||
HopIntervalMax: intervalMax,
|
HopIntervalMax: hopIntervalMax,
|
||||||
ListenUDPFunc: listenUDPFunc,
|
ListenUDPFunc: listenUDPFunc,
|
||||||
prevConn: nil,
|
prevConn: nil,
|
||||||
currentConn: pktConn,
|
currentConn: currentConn,
|
||||||
addrIndex: index,
|
addrIndex: addrIndex,
|
||||||
recvQueue: make(chan *udpPacket, packetQueueSize),
|
recvQueue: make(chan *udpPacket, packetQueueSize),
|
||||||
closeChan: make(chan struct{}),
|
closeChan: make(chan struct{}),
|
||||||
bufPool: sync.Pool{
|
bufPool: sync.Pool{
|
||||||
@@ -91,9 +85,9 @@ func NewUDPHopPacketConn(addr *UDPHopAddr, index int, intervalMin int64, interva
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
go hConn.recvLoop(pktConn)
|
go hConn.recvLoop(hConn.currentConn)
|
||||||
go hConn.hopLoop()
|
go hConn.hopLoop()
|
||||||
return hConn, nil
|
return hConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
||||||
@@ -104,69 +98,64 @@ func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
|||||||
u.bufPool.Put(buf)
|
u.bufPool.Put(buf)
|
||||||
var netErr net.Error
|
var netErr net.Error
|
||||||
if errors.As(err, &netErr) && netErr.Timeout() {
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
// Only pass through timeout errors here, not permanent errors
|
|
||||||
// like connection closed. Connection close is normal as we close
|
|
||||||
// the old connection to exit this loop every time we hop.
|
|
||||||
u.recvQueue <- &udpPacket{nil, 0, nil, netErr}
|
u.recvQueue <- &udpPacket{nil, 0, nil, netErr}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case u.recvQueue <- &udpPacket{buf, n, addr, nil}:
|
case u.recvQueue <- &udpPacket{buf, n, addr, nil}:
|
||||||
// Packet successfully queued
|
|
||||||
default:
|
default:
|
||||||
// Queue is full, drop the packet
|
|
||||||
u.bufPool.Put(buf)
|
u.bufPool.Put(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) hopLoop() {
|
func (u *UdpHopPacketConn) hopLoop() {
|
||||||
ticker := time.NewTicker(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
|
timer := time.NewTimer(u.nextHopInterval())
|
||||||
defer ticker.Stop()
|
defer timer.Stop()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-timer.C:
|
||||||
u.hop()
|
u.hop()
|
||||||
ticker.Reset(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
|
timer.Reset(u.nextHopInterval())
|
||||||
case <-u.closeChan:
|
case <-u.closeChan:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UdpHopPacketConn) nextHopInterval() time.Duration {
|
||||||
|
if u.HopIntervalMin == u.HopIntervalMax {
|
||||||
|
return u.HopIntervalMin
|
||||||
|
}
|
||||||
|
return u.HopIntervalMin + time.Duration(rand.Int63n(int64(u.HopIntervalMax-u.HopIntervalMin)+1))
|
||||||
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) hop() {
|
func (u *UdpHopPacketConn) hop() {
|
||||||
u.connMutex.Lock()
|
u.connMutex.Lock()
|
||||||
defer u.connMutex.Unlock()
|
defer u.connMutex.Unlock()
|
||||||
if u.closed {
|
if u.closed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Update addrIndex to a new random value
|
|
||||||
u.addrIndex = rand.Intn(len(u.Addrs))
|
u.addrIndex = rand.Intn(len(u.Addrs))
|
||||||
newConn, err := u.ListenUDPFunc(u.Addrs[u.addrIndex].(*net.UDPAddr))
|
newConn, err := u.ListenUDPFunc(u.Addrs[u.addrIndex].(*net.UDPAddr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Could be temporary, just skip this hop
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// We need to keep receiving packets from the previous connection,
|
|
||||||
// because otherwise there will be packet loss due to the time gap
|
|
||||||
// between we hop to a new port and the server acknowledges this change.
|
|
||||||
// So we do the following:
|
|
||||||
// Close prevConn,
|
|
||||||
// move currentConn to prevConn,
|
|
||||||
// set newConn as currentConn,
|
|
||||||
// start recvLoop on newConn.
|
|
||||||
if u.prevConn != nil {
|
if u.prevConn != nil {
|
||||||
_ = u.prevConn.Close() // recvLoop for this conn will exit
|
_ = u.prevConn.Close()
|
||||||
}
|
}
|
||||||
u.prevConn = u.currentConn
|
u.prevConn = u.currentConn
|
||||||
u.currentConn = newConn
|
u.currentConn = newConn
|
||||||
// Set buffer sizes if previously set
|
if !u.deadline.IsZero() {
|
||||||
if u.readBufferSize > 0 {
|
_ = u.currentConn.SetDeadline(u.deadline)
|
||||||
_ = trySetReadBuffer(u.currentConn, u.readBufferSize)
|
|
||||||
}
|
}
|
||||||
if u.writeBufferSize > 0 {
|
if !u.readDeadline.IsZero() {
|
||||||
_ = trySetWriteBuffer(u.currentConn, u.writeBufferSize)
|
_ = u.currentConn.SetReadDeadline(u.readDeadline)
|
||||||
|
}
|
||||||
|
if !u.writeDeadline.IsZero() {
|
||||||
|
_ = u.currentConn.SetWriteDeadline(u.writeDeadline)
|
||||||
}
|
}
|
||||||
go u.recvLoop(newConn)
|
go u.recvLoop(newConn)
|
||||||
}
|
}
|
||||||
@@ -178,11 +167,9 @@ func (u *UdpHopPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error)
|
|||||||
if p.Err != nil {
|
if p.Err != nil {
|
||||||
return 0, nil, p.Err
|
return 0, nil, p.Err
|
||||||
}
|
}
|
||||||
// Currently we do not check whether the packet is from
|
|
||||||
// the server or not due to performance reasons.
|
|
||||||
n := copy(b, p.Buf[:p.N])
|
n := copy(b, p.Buf[:p.N])
|
||||||
u.bufPool.Put(p.Buf)
|
u.bufPool.Put(p.Buf)
|
||||||
return n, u.Addr, nil
|
return n, p.Addr, nil
|
||||||
case <-u.closeChan:
|
case <-u.closeChan:
|
||||||
return 0, nil, net.ErrClosed
|
return 0, nil, net.ErrClosed
|
||||||
}
|
}
|
||||||
@@ -195,8 +182,6 @@ func (u *UdpHopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
if u.closed {
|
if u.closed {
|
||||||
return 0, net.ErrClosed
|
return 0, net.ErrClosed
|
||||||
}
|
}
|
||||||
// Skip the check for now, always write to the server,
|
|
||||||
// for the same reason as in ReadFrom.
|
|
||||||
return u.currentConn.WriteTo(b, u.Addrs[u.addrIndex])
|
return u.currentConn.WriteTo(b, u.Addrs[u.addrIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,16 +191,13 @@ func (u *UdpHopPacketConn) Close() error {
|
|||||||
if u.closed {
|
if u.closed {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Close prevConn and currentConn
|
|
||||||
// Close closeChan to unblock ReadFrom & hopLoop
|
|
||||||
// Set closed flag to true to prevent double close
|
|
||||||
if u.prevConn != nil {
|
if u.prevConn != nil {
|
||||||
_ = u.prevConn.Close()
|
_ = u.prevConn.Close()
|
||||||
}
|
}
|
||||||
err := u.currentConn.Close()
|
err := u.currentConn.Close()
|
||||||
close(u.closeChan)
|
close(u.closeChan)
|
||||||
u.closed = true
|
u.closed = true
|
||||||
u.Addrs = nil // For GC
|
u.Addrs = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,8 +208,11 @@ func (u *UdpHopPacketConn) LocalAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetDeadline(t time.Time) error {
|
func (u *UdpHopPacketConn) SetDeadline(t time.Time) error {
|
||||||
u.connMutex.RLock()
|
u.connMutex.Lock()
|
||||||
defer u.connMutex.RUnlock()
|
defer u.connMutex.Unlock()
|
||||||
|
u.deadline = t
|
||||||
|
u.readDeadline = t
|
||||||
|
u.writeDeadline = t
|
||||||
if u.prevConn != nil {
|
if u.prevConn != nil {
|
||||||
_ = u.prevConn.SetDeadline(t)
|
_ = u.prevConn.SetDeadline(t)
|
||||||
}
|
}
|
||||||
@@ -235,8 +220,10 @@ func (u *UdpHopPacketConn) SetDeadline(t time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetReadDeadline(t time.Time) error {
|
func (u *UdpHopPacketConn) SetReadDeadline(t time.Time) error {
|
||||||
u.connMutex.RLock()
|
u.connMutex.Lock()
|
||||||
defer u.connMutex.RUnlock()
|
defer u.connMutex.Unlock()
|
||||||
|
u.deadline = time.Time{}
|
||||||
|
u.readDeadline = t
|
||||||
if u.prevConn != nil {
|
if u.prevConn != nil {
|
||||||
_ = u.prevConn.SetReadDeadline(t)
|
_ = u.prevConn.SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
@@ -244,36 +231,16 @@ func (u *UdpHopPacketConn) SetReadDeadline(t time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetWriteDeadline(t time.Time) error {
|
func (u *UdpHopPacketConn) SetWriteDeadline(t time.Time) error {
|
||||||
u.connMutex.RLock()
|
u.connMutex.Lock()
|
||||||
defer u.connMutex.RUnlock()
|
defer u.connMutex.Unlock()
|
||||||
|
u.deadline = time.Time{}
|
||||||
|
u.writeDeadline = t
|
||||||
if u.prevConn != nil {
|
if u.prevConn != nil {
|
||||||
_ = u.prevConn.SetWriteDeadline(t)
|
_ = u.prevConn.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
return u.currentConn.SetWriteDeadline(t)
|
return u.currentConn.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UDP-specific methods below
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetReadBuffer(bytes int) error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
u.readBufferSize = bytes
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = trySetReadBuffer(u.prevConn, bytes)
|
|
||||||
}
|
|
||||||
return trySetReadBuffer(u.currentConn, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SetWriteBuffer(bytes int) error {
|
|
||||||
u.connMutex.Lock()
|
|
||||||
defer u.connMutex.Unlock()
|
|
||||||
u.writeBufferSize = bytes
|
|
||||||
if u.prevConn != nil {
|
|
||||||
_ = trySetWriteBuffer(u.prevConn, bytes)
|
|
||||||
}
|
|
||||||
return trySetWriteBuffer(u.currentConn, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) SyscallConn() (syscall.RawConn, error) {
|
func (u *UdpHopPacketConn) SyscallConn() (syscall.RawConn, error) {
|
||||||
u.connMutex.RLock()
|
u.connMutex.RLock()
|
||||||
defer u.connMutex.RUnlock()
|
defer u.connMutex.RUnlock()
|
||||||
@@ -284,22 +251,14 @@ func (u *UdpHopPacketConn) SyscallConn() (syscall.RawConn, error) {
|
|||||||
return sc.SyscallConn()
|
return sc.SyscallConn()
|
||||||
}
|
}
|
||||||
|
|
||||||
func trySetReadBuffer(pc net.PacketConn, bytes int) error {
|
func ToAddrs(ip net.IP, ports []uint32) []net.Addr {
|
||||||
sc, ok := pc.(interface {
|
var addrs []net.Addr
|
||||||
SetReadBuffer(bytes int) error
|
for _, port := range ports {
|
||||||
})
|
addr := &net.UDPAddr{
|
||||||
if ok {
|
IP: ip,
|
||||||
return sc.SetReadBuffer(bytes)
|
Port: int(port),
|
||||||
|
}
|
||||||
|
addrs = append(addrs, addr)
|
||||||
}
|
}
|
||||||
return nil
|
return addrs
|
||||||
}
|
|
||||||
|
|
||||||
func trySetWriteBuffer(pc net.PacketConn, bytes int) error {
|
|
||||||
sc, ok := pc.(interface {
|
|
||||||
SetWriteBuffer(bytes int) error
|
|
||||||
})
|
|
||||||
if ok {
|
|
||||||
return sc.SetWriteBuffer(bytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,41 +57,27 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
}
|
}
|
||||||
|
|
||||||
if streamSettings.UdpmaskManager != nil {
|
if streamSettings.UdpmaskManager != nil {
|
||||||
|
var pktConn net.PacketConn
|
||||||
|
var udpAddr *net.UDPAddr
|
||||||
switch c := conn.(type) {
|
switch c := conn.(type) {
|
||||||
case *internet.PacketConnWrapper:
|
case *internet.PacketConnWrapper:
|
||||||
pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(c.PacketConn)
|
pktConn = c.PacketConn
|
||||||
if err != nil {
|
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
c.PacketConn = pktConn
|
|
||||||
case *net.UDPConn:
|
|
||||||
pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(c)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
conn = &internet.PacketConnWrapper{
|
|
||||||
PacketConn: pktConn,
|
|
||||||
Dest: c.RemoteAddr().(*net.UDPAddr),
|
|
||||||
}
|
|
||||||
case *cnc.Connection:
|
case *cnc.Connection:
|
||||||
fakeConn := &internet.FakePacketConn{Conn: c}
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(fakeConn)
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
conn = &internet.PacketConnWrapper{
|
|
||||||
PacketConn: pktConn,
|
|
||||||
Dest: &net.UDPAddr{
|
|
||||||
IP: []byte{0, 0, 0, 0},
|
|
||||||
Port: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
conn.Close()
|
panic(reflect.TypeOf(c))
|
||||||
return nil, errors.New("unknown conn ", reflect.TypeOf(c))
|
}
|
||||||
|
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
|
||||||
|
if err != nil {
|
||||||
|
pktConn.Close()
|
||||||
|
return nil, errors.New("mask err").Base(err)
|
||||||
|
}
|
||||||
|
pktConn = newConn
|
||||||
|
conn = &internet.PacketConnWrapper{
|
||||||
|
PacketConn: pktConn,
|
||||||
|
Dest: udpAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -288,32 +288,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, address []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr unix.Sockaddr
|
|
||||||
|
|
||||||
switch len(address) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &unix.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], address)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &unix.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], address)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return unix.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
||||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||||
|
|||||||
@@ -222,32 +222,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr syscall.Sockaddr
|
|
||||||
|
|
||||||
switch len(ip) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &syscall.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], ip)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &syscall.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], ip)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return syscall.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -12,32 +11,6 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr syscall.Sockaddr
|
|
||||||
|
|
||||||
switch len(ip) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &syscall.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], ip)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &syscall.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], ip)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return syscall.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyOutboundSocketOptions applies socket options for outbound connection.
|
// applyOutboundSocketOptions applies socket options for outbound connection.
|
||||||
// note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
|
// note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
|
||||||
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user