Compare commits
18 Commits
host
...
dev-restls
Author | SHA1 | Date | |
---|---|---|---|
c330d2c82c | |||
6f159d0cac | |||
a35e40486b | |||
1bc3ecb027 | |||
c6a329281e | |||
13111081be | |||
5de043acc6 | |||
7d230139a0 | |||
0a6c848c9e | |||
074fee2b48 | |||
7f588935ea | |||
4b72ae7aab | |||
09b4a7ff15 | |||
7944522188 | |||
828cd6463b | |||
5ce6ac0a62 | |||
805b3c4669 | |||
e2d590ca12 |
@ -12,11 +12,13 @@ import (
|
|||||||
"github.com/Dreamacro/clash/common/structure"
|
"github.com/Dreamacro/clash/common/structure"
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/transport/restls"
|
||||||
obfs "github.com/Dreamacro/clash/transport/simple-obfs"
|
obfs "github.com/Dreamacro/clash/transport/simple-obfs"
|
||||||
shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls"
|
shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
|
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
|
||||||
|
|
||||||
|
restlsC "github.com/3andne/restls-client-go"
|
||||||
shadowsocks "github.com/metacubex/sing-shadowsocks"
|
shadowsocks "github.com/metacubex/sing-shadowsocks"
|
||||||
"github.com/metacubex/sing-shadowsocks/shadowimpl"
|
"github.com/metacubex/sing-shadowsocks/shadowimpl"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
@ -34,19 +36,21 @@ type ShadowSocks struct {
|
|||||||
obfsOption *simpleObfsOption
|
obfsOption *simpleObfsOption
|
||||||
v2rayOption *v2rayObfs.Option
|
v2rayOption *v2rayObfs.Option
|
||||||
shadowTLSOption *shadowtls.ShadowTLSOption
|
shadowTLSOption *shadowtls.ShadowTLSOption
|
||||||
|
restlsConfig *restlsC.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShadowSocksOption struct {
|
type ShadowSocksOption struct {
|
||||||
BasicOption
|
BasicOption
|
||||||
Name string `proxy:"name"`
|
Name string `proxy:"name"`
|
||||||
Server string `proxy:"server"`
|
Server string `proxy:"server"`
|
||||||
Port int `proxy:"port"`
|
Port int `proxy:"port"`
|
||||||
Password string `proxy:"password"`
|
Password string `proxy:"password"`
|
||||||
Cipher string `proxy:"cipher"`
|
Cipher string `proxy:"cipher"`
|
||||||
UDP bool `proxy:"udp,omitempty"`
|
UDP bool `proxy:"udp,omitempty"`
|
||||||
Plugin string `proxy:"plugin,omitempty"`
|
Plugin string `proxy:"plugin,omitempty"`
|
||||||
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
|
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
|
||||||
UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"`
|
UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"`
|
||||||
|
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleObfsOption struct {
|
type simpleObfsOption struct {
|
||||||
@ -66,12 +70,18 @@ type v2rayObfsOption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type shadowTLSOption struct {
|
type shadowTLSOption struct {
|
||||||
Password string `obfs:"password"`
|
Password string `obfs:"password"`
|
||||||
Host string `obfs:"host"`
|
Host string `obfs:"host"`
|
||||||
Fingerprint string `obfs:"fingerprint,omitempty"`
|
Fingerprint string `obfs:"fingerprint,omitempty"`
|
||||||
ClientFingerprint string `obfs:"client-fingerprint,omitempty"`
|
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
Version int `obfs:"version,omitempty"`
|
||||||
Version int `obfs:"version,omitempty"`
|
}
|
||||||
|
|
||||||
|
type restlsOption struct {
|
||||||
|
Password string `obfs:"password"`
|
||||||
|
Host string `obfs:"host"`
|
||||||
|
VersionHint string `obfs:"version-hint"`
|
||||||
|
RestlsScript string `obfs:"restls-script,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamConn implements C.ProxyAdapter
|
// StreamConn implements C.ProxyAdapter
|
||||||
@ -86,6 +96,7 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return ss.streamConn(c, metadata)
|
return ss.streamConn(c, metadata)
|
||||||
}
|
}
|
||||||
@ -103,6 +114,12 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
|
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
|
||||||
}
|
}
|
||||||
|
case restls.Mode:
|
||||||
|
var err error
|
||||||
|
c, err = restls.NewRestls(c, ss.restlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s (restls) connect error: %w", ss.addr, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
|
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
|
||||||
if N.NeedHandshake(c) {
|
if N.NeedHandshake(c) {
|
||||||
@ -202,6 +219,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||||||
var v2rayOption *v2rayObfs.Option
|
var v2rayOption *v2rayObfs.Option
|
||||||
var obfsOption *simpleObfsOption
|
var obfsOption *simpleObfsOption
|
||||||
var shadowTLSOpt *shadowtls.ShadowTLSOption
|
var shadowTLSOpt *shadowtls.ShadowTLSOption
|
||||||
|
var restlsConfig *restlsC.Config
|
||||||
obfsMode := ""
|
obfsMode := ""
|
||||||
|
|
||||||
decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true})
|
decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true})
|
||||||
@ -250,10 +268,23 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||||||
Password: opt.Password,
|
Password: opt.Password,
|
||||||
Host: opt.Host,
|
Host: opt.Host,
|
||||||
Fingerprint: opt.Fingerprint,
|
Fingerprint: opt.Fingerprint,
|
||||||
ClientFingerprint: opt.ClientFingerprint,
|
ClientFingerprint: option.ClientFingerprint,
|
||||||
SkipCertVerify: opt.SkipCertVerify,
|
SkipCertVerify: opt.SkipCertVerify,
|
||||||
Version: opt.Version,
|
Version: opt.Version,
|
||||||
}
|
}
|
||||||
|
} else if option.Plugin == restls.Mode {
|
||||||
|
obfsMode = restls.Mode
|
||||||
|
restlsOpt := &restlsOption{}
|
||||||
|
if err := decoder.Decode(option.PluginOpts, restlsOpt); err != nil {
|
||||||
|
return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
restlsConfig, err = restlsC.NewRestlsConfig(restlsOpt.Host, restlsOpt.Password, restlsOpt.VersionHint, restlsOpt.RestlsScript, option.ClientFingerprint)
|
||||||
|
restlsConfig.SessionTicketsDisabled = true
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ShadowSocks{
|
return &ShadowSocks{
|
||||||
@ -274,6 +305,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||||||
v2rayOption: v2rayOption,
|
v2rayOption: v2rayOption,
|
||||||
obfsOption: obfsOption,
|
obfsOption: obfsOption,
|
||||||
shadowTLSOption: shadowTLSOpt,
|
shadowTLSOption: shadowTLSOpt,
|
||||||
|
restlsConfig: restlsConfig,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,11 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
|||||||
switch proxyType {
|
switch proxyType {
|
||||||
case "ss":
|
case "ss":
|
||||||
ssOption := &outbound.ShadowSocksOption{}
|
ssOption := &outbound.ShadowSocksOption{}
|
||||||
|
|
||||||
|
if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 {
|
||||||
|
ssOption.ClientFingerprint = GlobalUtlsClient
|
||||||
|
}
|
||||||
|
|
||||||
err = decoder.Decode(mapping, ssOption)
|
err = decoder.Decode(mapping, ssOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
|
@ -2,12 +2,12 @@ package resolver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"math/rand"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/utils"
|
"github.com/Dreamacro/clash/common/utils"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
|
"github.com/zhangyunhao116/fastrand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hosts struct {
|
type Hosts struct {
|
||||||
@ -20,6 +20,7 @@ func NewHosts(hosts *trie.DomainTrie[HostValue]) Hosts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the search result and whether to match the parameter `isDomain`
|
||||||
func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) {
|
func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) {
|
||||||
value := h.DomainTrie.Search(domain)
|
value := h.DomainTrie.Search(domain)
|
||||||
if value == nil {
|
if value == nil {
|
||||||
@ -108,5 +109,5 @@ func (hv HostValue) RandIP() (netip.Addr, error) {
|
|||||||
if hv.IsDomain {
|
if hv.IsDomain {
|
||||||
return netip.Addr{}, errors.New("value type is error")
|
return netip.Addr{}, errors.New("value type is error")
|
||||||
}
|
}
|
||||||
return hv.IPs[rand.Intn(len(hv.IPs)-1)], nil
|
return hv.IPs[fastrand.Intn(len(hv.IPs))], nil
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ import (
|
|||||||
"container/list"
|
"container/list"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -446,6 +446,11 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
}
|
}
|
||||||
config.General = general
|
config.General = general
|
||||||
|
|
||||||
|
if len(config.General.GlobalClientFingerprint) != 0 {
|
||||||
|
log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint)
|
||||||
|
tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint)
|
||||||
|
}
|
||||||
|
|
||||||
dialer.DefaultInterface.Store(config.General.Interface)
|
dialer.DefaultInterface.Store(config.General.Interface)
|
||||||
proxies, providers, err := parseProxies(rawCfg)
|
proxies, providers, err := parseProxies(rawCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -521,11 +526,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
||||||
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
|
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
|
||||||
|
|
||||||
if len(config.General.GlobalClientFingerprint) != 0 {
|
|
||||||
log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint)
|
|
||||||
tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +845,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) {
|
|||||||
} else {
|
} else {
|
||||||
ips := make([]netip.Addr, 0)
|
ips := make([]netip.Addr, 0)
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok {
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||||
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
||||||
ips = append(ips, ip)
|
ips = append(ips, ip)
|
||||||
}
|
}
|
||||||
@ -985,8 +985,33 @@ func parsePureDNSServer(server string) string {
|
|||||||
}
|
}
|
||||||
func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][]dns.NameServer, error) {
|
func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][]dns.NameServer, error) {
|
||||||
policy := map[string][]dns.NameServer{}
|
policy := map[string][]dns.NameServer{}
|
||||||
|
updatedPolicy := make(map[string]interface{})
|
||||||
|
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
||||||
|
|
||||||
for domain, server := range nsPolicy {
|
for k, v := range nsPolicy {
|
||||||
|
if strings.Contains(k, "geosite:") {
|
||||||
|
subkeys := strings.Split(k, ":")
|
||||||
|
subkeys = subkeys[1:]
|
||||||
|
subkeys = strings.Split(subkeys[0], ",")
|
||||||
|
//log.Infoln("subkeys:%+v", subkeys)
|
||||||
|
for _, subkey := range subkeys {
|
||||||
|
newKey := "geosite:" + subkey
|
||||||
|
//log.Infoln("newKey:%+v", newKey)
|
||||||
|
updatedPolicy[newKey] = v
|
||||||
|
}
|
||||||
|
} else if re.MatchString(k) {
|
||||||
|
subkeys := strings.Split(k, ",")
|
||||||
|
//log.Infoln("subkeys:%+v", subkeys)
|
||||||
|
for _, subkey := range subkeys {
|
||||||
|
updatedPolicy[subkey] = v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updatedPolicy[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//log.Infoln("updatedPolicy:%+v", updatedPolicy)
|
||||||
|
|
||||||
|
for domain, server := range updatedPolicy {
|
||||||
|
|
||||||
servers, err := utils.ToStringSlice(server)
|
servers, err := utils.ToStringSlice(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -231,12 +231,13 @@ dns:
|
|||||||
# - '+.youtube.com'
|
# - '+.youtube.com'
|
||||||
|
|
||||||
# 配置查询域名使用的 DNS 服务器
|
# 配置查询域名使用的 DNS 服务器
|
||||||
nameserver-policy: # 'www.baidu.com': '114.114.114.114'
|
nameserver-policy:
|
||||||
|
# 'www.baidu.com': '114.114.114.114'
|
||||||
# '+.internal.crop.com': '10.0.0.1'
|
# '+.internal.crop.com': '10.0.0.1'
|
||||||
"geosite:cn":
|
"geosite:cn,private,apple":
|
||||||
- https://doh.pub/dns-query
|
- https://doh.pub/dns-query
|
||||||
- https://dns.alidns.com/dns-query
|
- https://dns.alidns.com/dns-query
|
||||||
"www.baidu.com": [https://doh.pub/dns-query, https://dns.alidns.com/dns-query]
|
"www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query]
|
||||||
|
|
||||||
proxies: # socks5
|
proxies: # socks5
|
||||||
- name: "socks"
|
- name: "socks"
|
||||||
@ -330,18 +331,56 @@ proxies: # socks5
|
|||||||
# headers:
|
# headers:
|
||||||
# custom: value
|
# custom: value
|
||||||
|
|
||||||
- name: "ss4"
|
- name: "ss4-shadow-tls"
|
||||||
type: ss
|
type: ss
|
||||||
server: server
|
server: server
|
||||||
port: 443
|
port: 443
|
||||||
cipher: chacha20-ietf-poly1305
|
cipher: chacha20-ietf-poly1305
|
||||||
password: "password"
|
password: "password"
|
||||||
plugin: shadow-tls
|
plugin: shadow-tls
|
||||||
|
client-fingerprint: chrome
|
||||||
plugin-opts:
|
plugin-opts:
|
||||||
host: "cloud.tencent.com"
|
host: "cloud.tencent.com"
|
||||||
password: "shadow_tls_password"
|
password: "shadow_tls_password"
|
||||||
version: 2 # support 1/2/3
|
version: 2 # support 1/2/3
|
||||||
|
|
||||||
|
- name: "ss-restls-tls13"
|
||||||
|
type: ss
|
||||||
|
server: [YOUR_SERVER_IP]
|
||||||
|
port: 443
|
||||||
|
cipher: chacha20-ietf-poly1305
|
||||||
|
password: [YOUR_SS_PASSWORD]
|
||||||
|
client-fingerprint: chrome # One of: chrome, ios, firefox or safari
|
||||||
|
# 可以是chrome, ios, firefox, safari中的一个
|
||||||
|
plugin: restls
|
||||||
|
plugin-opts:
|
||||||
|
host: "www.microsoft.com" # Must be a TLS 1.3 server
|
||||||
|
# 应当是一个TLS 1.3 服务器
|
||||||
|
password: [YOUR_RESTLS_PASSWORD]
|
||||||
|
version-hint: "tls13"
|
||||||
|
# Control your post-handshake traffic through restls-script
|
||||||
|
# Hide proxy behaviors like "tls in tls".
|
||||||
|
# see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md
|
||||||
|
# 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征
|
||||||
|
# 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md
|
||||||
|
restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100"
|
||||||
|
|
||||||
|
- name: "ss-restls-tls12"
|
||||||
|
type: ss
|
||||||
|
server: [YOUR_SERVER_IP]
|
||||||
|
port: 443
|
||||||
|
cipher: chacha20-ietf-poly1305
|
||||||
|
password: [YOUR_SS_PASSWORD]
|
||||||
|
client-fingerprint: chrome # One of: chrome, ios, firefox or safari
|
||||||
|
# 可以是chrome, ios, firefox, safari中的一个
|
||||||
|
plugin: restls
|
||||||
|
plugin-opts:
|
||||||
|
host: "vscode.dev" # Must be a TLS 1.2 server
|
||||||
|
# 应当是一个TLS 1.2 服务器
|
||||||
|
password: [YOUR_RESTLS_PASSWORD]
|
||||||
|
version-hint: "tls12"
|
||||||
|
restls-script: "1000?100<1,500~100,350~100,600~100,400~200"
|
||||||
|
|
||||||
# vmess
|
# vmess
|
||||||
# cipher支持 auto/aes-128-gcm/chacha20-poly1305/none
|
# cipher支持 auto/aes-128-gcm/chacha20-poly1305/none
|
||||||
- name: "vmess"
|
- name: "vmess"
|
||||||
|
8
go.mod
8
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/jpillora/backoff v1.0.0
|
github.com/jpillora/backoff v1.0.0
|
||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7
|
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7
|
||||||
github.com/metacubex/quic-go v0.32.0
|
github.com/metacubex/quic-go v0.33.1
|
||||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947
|
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947
|
||||||
github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3
|
github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3
|
||||||
github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb
|
github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb
|
||||||
@ -51,6 +51,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/3andne/restls-client-go v0.1.4
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
@ -69,9 +70,8 @@ require (
|
|||||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quic-go/qpack v0.4.0 // indirect
|
github.com/quic-go/qpack v0.4.0 // indirect
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
|
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
|
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect
|
github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
|
16
go.sum
16
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU=
|
||||||
|
github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
@ -89,8 +91,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw
|
|||||||
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
|
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
|
||||||
github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 h1:0TEvReK/D6YLszjGj/bdx4d7amQSjQ2X/98r4ZiUbxU=
|
github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 h1:0TEvReK/D6YLszjGj/bdx4d7amQSjQ2X/98r4ZiUbxU=
|
||||||
github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE=
|
github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE=
|
||||||
github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw=
|
github.com/metacubex/quic-go v0.33.1 h1:ZIxZFGivpSLOEZuuNkLy+aPvo1RP4uRBjNg3SAkXwIg=
|
||||||
github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA=
|
github.com/metacubex/quic-go v0.33.1/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA=
|
||||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE=
|
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE=
|
||||||
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w=
|
github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w=
|
||||||
github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI=
|
github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI=
|
||||||
@ -115,12 +117,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
|
||||||
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
|
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||||
|
57
transport/restls/restls.go
Normal file
57
transport/restls/restls.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package restls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
tls "github.com/3andne/restls-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Mode string = "restls"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Restls
|
||||||
|
type Restls struct {
|
||||||
|
net.Conn
|
||||||
|
firstPacketCache []byte
|
||||||
|
firstPacket bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Restls) Read(b []byte) (int, error) {
|
||||||
|
if err := r.Conn.(*tls.UConn).Handshake(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n, err := r.Conn.(*tls.UConn).Read(b)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Restls) Write(b []byte) (int, error) {
|
||||||
|
if r.firstPacket {
|
||||||
|
r.firstPacketCache = append([]byte(nil), b...)
|
||||||
|
r.firstPacket = false
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
if len(r.firstPacketCache) != 0 {
|
||||||
|
b = append(r.firstPacketCache, b...)
|
||||||
|
r.firstPacketCache = nil
|
||||||
|
}
|
||||||
|
n, err := r.Conn.(*tls.UConn).Write(b)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRestls return a Restls Connection
|
||||||
|
func NewRestls(conn net.Conn, config *tls.Config) (net.Conn, error) {
|
||||||
|
if config != nil {
|
||||||
|
clientIDPtr := config.ClientID.Load()
|
||||||
|
if clientIDPtr != nil {
|
||||||
|
return &Restls{
|
||||||
|
Conn: tls.UClient(conn, config, *clientIDPtr),
|
||||||
|
firstPacket: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Restls{
|
||||||
|
Conn: tls.UClient(conn, config, tls.HelloChrome_Auto),
|
||||||
|
firstPacket: true,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -200,7 +200,7 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||||
if len(p) > q.maxUdpRelayPacketSize {
|
if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize {
|
||||||
return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize)
|
return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize)
|
||||||
}
|
}
|
||||||
if q.closed {
|
if q.closed {
|
||||||
@ -215,7 +215,6 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
|||||||
q.deferQuicConnFn(q.quicConn, err)
|
q.deferQuicConnFn(q.quicConn, err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
addr.String()
|
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBuffer(buf)
|
||||||
addrPort, err := netip.ParseAddrPort(addr.String())
|
addrPort, err := netip.ParseAddrPort(addr.String())
|
||||||
@ -239,7 +238,8 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
default: // native
|
default: // native
|
||||||
err = q.quicConn.SendMessage(buf.Bytes())
|
data := buf.Bytes()
|
||||||
|
err = q.quicConn.SendMessage(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -250,7 +250,29 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *quicStreamPacketConn) LocalAddr() net.Addr {
|
func (q *quicStreamPacketConn) LocalAddr() net.Addr {
|
||||||
return q.quicConn.LocalAddr()
|
addr := q.quicConn.LocalAddr()
|
||||||
|
if q.inputConn != nil { // client
|
||||||
|
return &packetAddr{addrStr: q.quicConn.LocalAddr().String(), connId: q.connId, rawAddr: addr}
|
||||||
|
}
|
||||||
|
return addr // server
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ net.PacketConn = &quicStreamPacketConn{}
|
var _ net.PacketConn = &quicStreamPacketConn{}
|
||||||
|
|
||||||
|
type packetAddr struct {
|
||||||
|
addrStr string
|
||||||
|
connId uint32
|
||||||
|
rawAddr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a packetAddr) Network() string {
|
||||||
|
return "tuic"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a packetAddr) String() string {
|
||||||
|
return fmt.Sprintf("%s-%d", a.addrStr, a.connId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a packetAddr) RawAddr() net.Addr {
|
||||||
|
return a.rawAddr
|
||||||
|
}
|
||||||
|
@ -114,9 +114,6 @@ func NewAuthenticate(TKN [32]byte) Authenticate {
|
|||||||
|
|
||||||
func ReadAuthenticateWithHead(head CommandHead, reader BufferedReader) (c Authenticate, err error) {
|
func ReadAuthenticateWithHead(head CommandHead, reader BufferedReader) (c Authenticate, err error) {
|
||||||
c.CommandHead = head
|
c.CommandHead = head
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.CommandHead.TYPE != AuthenticateType {
|
if c.CommandHead.TYPE != AuthenticateType {
|
||||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||||
return
|
return
|
||||||
@ -170,9 +167,6 @@ func NewConnect(ADDR Address) Connect {
|
|||||||
|
|
||||||
func ReadConnectWithHead(head CommandHead, reader BufferedReader) (c Connect, err error) {
|
func ReadConnectWithHead(head CommandHead, reader BufferedReader) (c Connect, err error) {
|
||||||
c.CommandHead = head
|
c.CommandHead = head
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.CommandHead.TYPE != ConnectType {
|
if c.CommandHead.TYPE != ConnectType {
|
||||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||||
return
|
return
|
||||||
@ -228,9 +222,6 @@ func NewPacket(ASSOC_ID uint32, LEN uint16, ADDR Address, DATA []byte) Packet {
|
|||||||
|
|
||||||
func ReadPacketWithHead(head CommandHead, reader BufferedReader) (c Packet, err error) {
|
func ReadPacketWithHead(head CommandHead, reader BufferedReader) (c Packet, err error) {
|
||||||
c.CommandHead = head
|
c.CommandHead = head
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.CommandHead.TYPE != PacketType {
|
if c.CommandHead.TYPE != PacketType {
|
||||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||||
return
|
return
|
||||||
@ -305,9 +296,6 @@ func NewDissociate(ASSOC_ID uint32) Dissociate {
|
|||||||
|
|
||||||
func ReadDissociateWithHead(head CommandHead, reader BufferedReader) (c Dissociate, err error) {
|
func ReadDissociateWithHead(head CommandHead, reader BufferedReader) (c Dissociate, err error) {
|
||||||
c.CommandHead = head
|
c.CommandHead = head
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.CommandHead.TYPE != DissociateType {
|
if c.CommandHead.TYPE != DissociateType {
|
||||||
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE)
|
||||||
return
|
return
|
||||||
@ -476,15 +464,17 @@ func NewAddress(metadata *C.Metadata) Address {
|
|||||||
|
|
||||||
func NewAddressAddrPort(addrPort netip.AddrPort) Address {
|
func NewAddressAddrPort(addrPort netip.AddrPort) Address {
|
||||||
var addrType byte
|
var addrType byte
|
||||||
if addrPort.Addr().Is4() {
|
port := addrPort.Port()
|
||||||
|
addr := addrPort.Addr().Unmap()
|
||||||
|
if addr.Is4() {
|
||||||
addrType = AtypIPv4
|
addrType = AtypIPv4
|
||||||
} else {
|
} else {
|
||||||
addrType = AtypIPv6
|
addrType = AtypIPv6
|
||||||
}
|
}
|
||||||
return Address{
|
return Address{
|
||||||
TYPE: addrType,
|
TYPE: addrType,
|
||||||
ADDR: addrPort.Addr().AsSlice(),
|
ADDR: addr.AsSlice(),
|
||||||
PORT: addrPort.Port(),
|
PORT: port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -154,14 +153,10 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err
|
|||||||
return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{
|
return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{
|
||||||
pc: pc,
|
pc: pc,
|
||||||
packet: &packet,
|
packet: &packet,
|
||||||
rAddr: s.genServerAssocIdAddr(assocId, s.quicConn.RemoteAddr()),
|
rAddr: &packetAddr{addrStr: "tuic-" + s.uuid.String(), connId: assocId, rawAddr: s.quicConn.RemoteAddr()},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serverHandler) genServerAssocIdAddr(assocId uint32, addr net.Addr) net.Addr {
|
|
||||||
return &ServerAssocIdAddr{assocId: fmt.Sprintf("tuic-%s-%d", s.uuid.String(), assocId), addr: addr}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serverHandler) handleStream() (err error) {
|
func (s *serverHandler) handleStream() (err error) {
|
||||||
for {
|
for {
|
||||||
var quicStream quic.Stream
|
var quicStream quic.Stream
|
||||||
@ -276,23 +271,6 @@ func (s *serverHandler) handleUniStream() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerAssocIdAddr struct {
|
|
||||||
assocId string
|
|
||||||
addr net.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a ServerAssocIdAddr) Network() string {
|
|
||||||
return "ServerAssocIdAddr"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a ServerAssocIdAddr) String() string {
|
|
||||||
return a.assocId
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a ServerAssocIdAddr) RawAddr() net.Addr {
|
|
||||||
return a.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
type serverUDPPacket struct {
|
type serverUDPPacket struct {
|
||||||
pc *quicStreamPacketConn
|
pc *quicStreamPacketConn
|
||||||
packet *Packet
|
packet *Packet
|
||||||
|
@ -3,7 +3,6 @@ package vless
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/buf"
|
"github.com/Dreamacro/clash/common/buf"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
@ -20,12 +19,9 @@ const (
|
|||||||
commandPaddingDirect byte = 0x02
|
commandPaddingDirect byte = 0x02
|
||||||
)
|
)
|
||||||
|
|
||||||
var mutex sync.RWMutex
|
|
||||||
|
|
||||||
func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
||||||
contentLen := int32(len(p))
|
contentLen := int32(len(p))
|
||||||
var paddingLen int32
|
var paddingLen int32
|
||||||
mutex.Lock()
|
|
||||||
if contentLen < 900 {
|
if contentLen < 900 {
|
||||||
if paddingTLS {
|
if paddingTLS {
|
||||||
//log.Debugln("long padding")
|
//log.Debugln("long padding")
|
||||||
@ -34,8 +30,7 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid
|
|||||||
paddingLen = fastrand.Int31n(256)
|
paddingLen = fastrand.Int31n(256)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex.Unlock()
|
if userUUID != nil {
|
||||||
if userUUID != nil { // unnecessary, but keep the same with Xray
|
|
||||||
buffer.Write(userUUID.Bytes())
|
buffer.Write(userUUID.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +46,6 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid
|
|||||||
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) {
|
||||||
contentLen := int32(buffer.Len())
|
contentLen := int32(buffer.Len())
|
||||||
var paddingLen int32
|
var paddingLen int32
|
||||||
mutex.Lock()
|
|
||||||
if contentLen < 900 {
|
if contentLen < 900 {
|
||||||
if paddingTLS {
|
if paddingTLS {
|
||||||
//log.Debugln("long padding")
|
//log.Debugln("long padding")
|
||||||
@ -60,12 +54,11 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding
|
|||||||
paddingLen = fastrand.Int31n(256)
|
paddingLen = fastrand.Int31n(256)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex.Unlock()
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen))
|
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen))
|
||||||
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen))
|
binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen))
|
||||||
buffer.ExtendHeader(1)[0] = command
|
buffer.ExtendHeader(1)[0] = command
|
||||||
if userUUID != nil { // unnecessary, but keep the same with Xray
|
if userUUID != nil {
|
||||||
copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes())
|
copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fromUDPAddr := from.(*net.UDPAddr)
|
fromUDPAddr := from.(*net.UDPAddr)
|
||||||
fromUDPAddr = &(*fromUDPAddr) // make a copy
|
_fromUDPAddr := *fromUDPAddr
|
||||||
|
fromUDPAddr = &_fromUDPAddr // make a copy
|
||||||
if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok {
|
if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok {
|
||||||
if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) {
|
if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) {
|
||||||
fromUDPAddr.IP = fAddr.Unmap().AsSlice()
|
fromUDPAddr.IP = fAddr.Unmap().AsSlice()
|
||||||
|
Reference in New Issue
Block a user