feat: wireguard add remote-dns-resolve
and dns
settings
This commit is contained in:
parent
fee9cb7bc8
commit
72447a529d
8 changed files with 121 additions and 56 deletions
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/Dreamacro/clash/component/proxydialer"
|
"github.com/Dreamacro/clash/component/proxydialer"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/dns"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
wireguard "github.com/metacubex/sing-wireguard"
|
wireguard "github.com/metacubex/sing-wireguard"
|
||||||
|
@ -38,6 +39,7 @@ type WireGuard struct {
|
||||||
dialer *wgSingDialer
|
dialer *wgSingDialer
|
||||||
startOnce sync.Once
|
startOnce sync.Once
|
||||||
startErr error
|
startErr error
|
||||||
|
resolver *dns.Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
type WireGuardOption struct {
|
type WireGuardOption struct {
|
||||||
|
@ -51,6 +53,9 @@ type WireGuardOption struct {
|
||||||
PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"`
|
PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"`
|
||||||
|
|
||||||
Peers []WireGuardPeerOption `proxy:"peers,omitempty"`
|
Peers []WireGuardPeerOption `proxy:"peers,omitempty"`
|
||||||
|
|
||||||
|
RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"`
|
||||||
|
Dns []string `proxy:"dns,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WireGuardPeerOption struct {
|
type WireGuardPeerOption struct {
|
||||||
|
@ -298,6 +303,29 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) {
|
||||||
return nil, E.Cause(err, "setup wireguard")
|
return nil, E.Cause(err, "setup wireguard")
|
||||||
}
|
}
|
||||||
//err = outbound.tunDevice.Start()
|
//err = outbound.tunDevice.Start()
|
||||||
|
|
||||||
|
var has6 bool
|
||||||
|
for _, address := range localPrefixes {
|
||||||
|
if !address.Addr().Unmap().Is4() {
|
||||||
|
has6 = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.RemoteDnsResolve && len(option.Dns) > 0 {
|
||||||
|
nss, err := dns.ParseNameServer(option.Dns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range nss {
|
||||||
|
nss[i].ProxyAdapter = outbound
|
||||||
|
}
|
||||||
|
outbound.resolver = dns.NewResolver(dns.Config{
|
||||||
|
Main: nss,
|
||||||
|
IPv6: has6,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,8 +346,12 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts
|
||||||
if w.startErr != nil {
|
if w.startErr != nil {
|
||||||
return nil, w.startErr
|
return nil, w.startErr
|
||||||
}
|
}
|
||||||
if !metadata.Resolved() {
|
if !metadata.Resolved() || w.resolver != nil {
|
||||||
options = append(options, dialer.WithResolver(resolver.DefaultResolver))
|
r := resolver.DefaultResolver
|
||||||
|
if w.resolver != nil {
|
||||||
|
r = w.resolver
|
||||||
|
}
|
||||||
|
options = append(options, dialer.WithResolver(r))
|
||||||
options = append(options, dialer.WithNetDialer(wgNetDialer{tunDevice: w.tunDevice}))
|
options = append(options, dialer.WithNetDialer(wgNetDialer{tunDevice: w.tunDevice}))
|
||||||
conn, err = dialer.NewDialer(options...).DialContext(ctx, "tcp", metadata.RemoteAddress())
|
conn, err = dialer.NewDialer(options...).DialContext(ctx, "tcp", metadata.RemoteAddress())
|
||||||
} else {
|
} else {
|
||||||
|
@ -348,8 +380,12 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !metadata.Resolved() {
|
if (!metadata.Resolved() || w.resolver != nil) && metadata.Host != "" {
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
r := resolver.DefaultResolver
|
||||||
|
if w.resolver != nil {
|
||||||
|
r = w.resolver
|
||||||
|
}
|
||||||
|
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("can't resolve ip")
|
return nil, errors.New("can't resolve ip")
|
||||||
}
|
}
|
||||||
|
|
|
@ -896,7 +896,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
||||||
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
|
return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyAdapter := u.Fragment
|
proxyName := u.Fragment
|
||||||
|
|
||||||
var addr, dnsNetType string
|
var addr, dnsNetType string
|
||||||
params := map[string]string{}
|
params := map[string]string{}
|
||||||
|
@ -913,7 +913,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
||||||
case "https":
|
case "https":
|
||||||
addr, err = hostWithDefaultPort(u.Host, "443")
|
addr, err = hostWithDefaultPort(u.Host, "443")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
proxyAdapter = ""
|
proxyName = ""
|
||||||
clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path}
|
clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path}
|
||||||
addr = clearURL.String()
|
addr = clearURL.String()
|
||||||
dnsNetType = "https" // DNS over HTTPS
|
dnsNetType = "https" // DNS over HTTPS
|
||||||
|
@ -923,7 +923,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
||||||
if len(arr) == 0 {
|
if len(arr) == 0 {
|
||||||
continue
|
continue
|
||||||
} else if len(arr) == 1 {
|
} else if len(arr) == 1 {
|
||||||
proxyAdapter = arr[0]
|
proxyName = arr[0]
|
||||||
} else if len(arr) == 2 {
|
} else if len(arr) == 2 {
|
||||||
params[arr[0]] = arr[1]
|
params[arr[0]] = arr[1]
|
||||||
} else {
|
} else {
|
||||||
|
@ -951,7 +951,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
||||||
dns.NameServer{
|
dns.NameServer{
|
||||||
Net: dnsNetType,
|
Net: dnsNetType,
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
ProxyAdapter: proxyAdapter,
|
ProxyName: proxyName,
|
||||||
Interface: dialer.DefaultInterface,
|
Interface: dialer.DefaultInterface,
|
||||||
Params: params,
|
Params: params,
|
||||||
PreferH3: preferH3,
|
PreferH3: preferH3,
|
||||||
|
@ -961,6 +961,12 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
||||||
return nameservers, nil
|
return nameservers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dns.ParseNameServer = func(servers []string) ([]dns.NameServer, error) { // using by wireguard
|
||||||
|
return parseNameServer(servers, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func parsePureDNSServer(server string) string {
|
func parsePureDNSServer(server string) string {
|
||||||
addPre := func(server string) string {
|
addPre := func(server string) string {
|
||||||
return "udp://" + server
|
return "udp://" + server
|
||||||
|
|
|
@ -8,14 +8,14 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
|
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
"github.com/zhangyunhao116/fastrand"
|
"github.com/zhangyunhao116/fastrand"
|
||||||
|
"go.uber.org/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
|
@ -24,7 +24,8 @@ type client struct {
|
||||||
port string
|
port string
|
||||||
host string
|
host string
|
||||||
iface *atomic.String
|
iface *atomic.String
|
||||||
proxyAdapter string
|
proxyAdapter C.ProxyAdapter
|
||||||
|
proxyName string
|
||||||
addr string
|
addr string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
|
||||||
options = append(options, dialer.WithInterface(c.iface.Load()))
|
options = append(options, dialer.WithInterface(c.iface.Load()))
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := getDialHandler(c.r, c.proxyAdapter, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port))
|
conn, err := getDialHandler(c.r, c.proxyAdapter, c.proxyName, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
14
dns/doh.go
14
dns/doh.go
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/metacubex/quic-go"
|
"github.com/metacubex/quic-go"
|
||||||
"github.com/metacubex/quic-go/http3"
|
"github.com/metacubex/quic-go/http3"
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,7 +64,8 @@ type dnsOverHTTPS struct {
|
||||||
url *url.URL
|
url *url.URL
|
||||||
r *Resolver
|
r *Resolver
|
||||||
httpVersions []C.HTTPVersion
|
httpVersions []C.HTTPVersion
|
||||||
proxyAdapter string
|
proxyAdapter C.ProxyAdapter
|
||||||
|
proxyName string
|
||||||
addr string
|
addr string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ type dnsOverHTTPS struct {
|
||||||
var _ dnsClient = (*dnsOverHTTPS)(nil)
|
var _ dnsClient = (*dnsOverHTTPS)(nil)
|
||||||
|
|
||||||
// newDoH returns the DNS-over-HTTPS Upstream.
|
// newDoH returns the DNS-over-HTTPS Upstream.
|
||||||
func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[string]string, proxyAdapter string) dnsClient {
|
func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[string]string, proxyAdapter C.ProxyAdapter, proxyName string) dnsClient {
|
||||||
u, _ := url.Parse(urlString)
|
u, _ := url.Parse(urlString)
|
||||||
httpVersions := DefaultHTTPVersions
|
httpVersions := DefaultHTTPVersions
|
||||||
if preferH3 {
|
if preferH3 {
|
||||||
|
@ -87,6 +89,7 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin
|
||||||
addr: u.String(),
|
addr: u.String(),
|
||||||
r: r,
|
r: r,
|
||||||
proxyAdapter: proxyAdapter,
|
proxyAdapter: proxyAdapter,
|
||||||
|
proxyName: proxyName,
|
||||||
quicConfig: &quic.Config{
|
quicConfig: &quic.Config{
|
||||||
KeepAlivePeriod: QUICKeepAlivePeriod,
|
KeepAlivePeriod: QUICKeepAlivePeriod,
|
||||||
TokenStore: newQUICTokenStore(),
|
TokenStore: newQUICTokenStore(),
|
||||||
|
@ -390,7 +393,9 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp
|
||||||
nextProtos = append(nextProtos, string(v))
|
nextProtos = append(nextProtos, string(v))
|
||||||
}
|
}
|
||||||
tlsConfig.NextProtos = nextProtos
|
tlsConfig.NextProtos = nextProtos
|
||||||
dialContext := getDialHandler(doh.r, doh.proxyAdapter)
|
dialContext := getDialHandler(doh.r, doh.proxyAdapter, doh.proxyName)
|
||||||
|
|
||||||
|
if slices.Contains(doh.httpVersions, C.HTTPVersion3) {
|
||||||
// First, we attempt to create an HTTP3 transport. If the probe QUIC
|
// First, we attempt to create an HTTP3 transport. If the probe QUIC
|
||||||
// connection is established successfully, we'll be using HTTP3 for this
|
// connection is established successfully, we'll be using HTTP3 for this
|
||||||
// upstream.
|
// upstream.
|
||||||
|
@ -399,6 +404,7 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp
|
||||||
log.Debugln("[%s] using HTTP/3 for this upstream: QUIC was faster", doh.url.String())
|
log.Debugln("[%s] using HTTP/3 for this upstream: QUIC was faster", doh.url.String())
|
||||||
return transportH3, nil
|
return transportH3, nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugln("[%s] using HTTP/2 for this upstream: %v", doh.url.String(), err)
|
log.Debugln("[%s] using HTTP/2 for this upstream: %v", doh.url.String(), err)
|
||||||
|
|
||||||
|
@ -533,7 +539,7 @@ func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls.
|
||||||
IP: net.ParseIP(ip),
|
IP: net.ParseIP(ip),
|
||||||
Port: portInt,
|
Port: portInt,
|
||||||
}
|
}
|
||||||
conn, err := listenPacket(ctx, doh.proxyAdapter, "udp", addr, doh.r)
|
conn, err := listenPacket(ctx, doh.proxyAdapter, doh.proxyName, "udp", addr, doh.r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
15
dns/doq.go
15
dns/doq.go
|
@ -13,9 +13,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/metacubex/quic-go"
|
"github.com/metacubex/quic-go"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,7 +61,8 @@ type dnsOverQUIC struct {
|
||||||
bytesPoolGuard sync.Mutex
|
bytesPoolGuard sync.Mutex
|
||||||
|
|
||||||
addr string
|
addr string
|
||||||
proxyAdapter string
|
proxyAdapter C.ProxyAdapter
|
||||||
|
proxyName string
|
||||||
r *Resolver
|
r *Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +70,11 @@ type dnsOverQUIC struct {
|
||||||
var _ dnsClient = (*dnsOverQUIC)(nil)
|
var _ dnsClient = (*dnsOverQUIC)(nil)
|
||||||
|
|
||||||
// newDoQ returns the DNS-over-QUIC Upstream.
|
// newDoQ returns the DNS-over-QUIC Upstream.
|
||||||
func newDoQ(resolver *Resolver, addr string, adapter string) (dnsClient, error) {
|
func newDoQ(resolver *Resolver, addr string, proxyAdapter C.ProxyAdapter, proxyName string) (dnsClient, error) {
|
||||||
doq := &dnsOverQUIC{
|
doq := &dnsOverQUIC{
|
||||||
addr: addr,
|
addr: addr,
|
||||||
proxyAdapter: adapter,
|
proxyAdapter: proxyAdapter,
|
||||||
|
proxyName: proxyName,
|
||||||
r: resolver,
|
r: resolver,
|
||||||
quicConfig: &quic.Config{
|
quicConfig: &quic.Config{
|
||||||
KeepAlivePeriod: QUICKeepAlivePeriod,
|
KeepAlivePeriod: QUICKeepAlivePeriod,
|
||||||
|
@ -310,7 +313,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio
|
||||||
// we're using bootstrapped address instead of what's passed to the function
|
// we're using bootstrapped address instead of what's passed to the function
|
||||||
// it does not create an actual connection, but it helps us determine
|
// it does not create an actual connection, but it helps us determine
|
||||||
// what IP is actually reachable (when there're v4/v6 addresses).
|
// what IP is actually reachable (when there're v4/v6 addresses).
|
||||||
rawConn, err := getDialHandler(doq.r, doq.proxyAdapter)(ctx, "udp", doq.addr)
|
rawConn, err := getDialHandler(doq.r, doq.proxyAdapter, doq.proxyName)(ctx, "udp", doq.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to open a QUIC connection: %w", err)
|
return nil, fmt.Errorf("failed to open a QUIC connection: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -325,7 +328,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio
|
||||||
|
|
||||||
p, err := strconv.Atoi(port)
|
p, err := strconv.Atoi(port)
|
||||||
udpAddr := net.UDPAddr{IP: net.ParseIP(ip), Port: p}
|
udpAddr := net.UDPAddr{IP: net.ParseIP(ip), Port: p}
|
||||||
udp, err := listenPacket(ctx, doq.proxyAdapter, "udp", addr, doq.r)
|
udp, err := listenPacket(ctx, doq.proxyAdapter, doq.proxyName, "udp", addr, doq.r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr,
|
||||||
|
|
||||||
ips, err = r.lookupIP(ctx, host, D.TypeA)
|
ips, err = r.lookupIP(ctx, host, D.TypeA)
|
||||||
var waitIPv6 *time.Timer
|
var waitIPv6 *time.Timer
|
||||||
if r != nil {
|
if r != nil && r.ipv6Timeout > 0 {
|
||||||
waitIPv6 = time.NewTimer(r.ipv6Timeout)
|
waitIPv6 = time.NewTimer(r.ipv6Timeout)
|
||||||
} else {
|
} else {
|
||||||
waitIPv6 = time.NewTimer(100 * time.Millisecond)
|
waitIPv6 = time.NewTimer(100 * time.Millisecond)
|
||||||
|
@ -421,7 +421,8 @@ type NameServer struct {
|
||||||
Net string
|
Net string
|
||||||
Addr string
|
Addr string
|
||||||
Interface *atomic.String
|
Interface *atomic.String
|
||||||
ProxyAdapter string
|
ProxyAdapter C.ProxyAdapter
|
||||||
|
ProxyName string
|
||||||
Params map[string]string
|
Params map[string]string
|
||||||
PreferH3 bool
|
PreferH3 bool
|
||||||
}
|
}
|
||||||
|
@ -544,3 +545,5 @@ func NewProxyServerHostResolver(old *Resolver) *Resolver {
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ParseNameServer func(servers []string) ([]NameServer, error) // define in config/config.go
|
||||||
|
|
44
dns/util.go
44
dns/util.go
|
@ -74,13 +74,13 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
|
||||||
for _, s := range servers {
|
for _, s := range servers {
|
||||||
switch s.Net {
|
switch s.Net {
|
||||||
case "https":
|
case "https":
|
||||||
ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter))
|
ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName))
|
||||||
continue
|
continue
|
||||||
case "dhcp":
|
case "dhcp":
|
||||||
ret = append(ret, newDHCPClient(s.Addr))
|
ret = append(ret, newDHCPClient(s.Addr))
|
||||||
continue
|
continue
|
||||||
case "quic":
|
case "quic":
|
||||||
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter); err == nil {
|
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil {
|
||||||
ret = append(ret, doq)
|
ret = append(ret, doq)
|
||||||
} else {
|
} else {
|
||||||
log.Fatalln("DoQ format error: %v", err)
|
log.Fatalln("DoQ format error: %v", err)
|
||||||
|
@ -103,6 +103,7 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
|
||||||
iface: s.Interface,
|
iface: s.Interface,
|
||||||
r: resolver,
|
r: resolver,
|
||||||
proxyAdapter: s.ProxyAdapter,
|
proxyAdapter: s.ProxyAdapter,
|
||||||
|
proxyName: s.ProxyName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
@ -144,9 +145,9 @@ func msgToDomain(msg *D.Msg) string {
|
||||||
|
|
||||||
type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error)
|
type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
|
||||||
func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dialHandler {
|
func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) dialHandler {
|
||||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
if len(proxyAdapter) == 0 {
|
if len(proxyName) == 0 && proxyAdapter == nil {
|
||||||
opts = append(opts, dialer.WithResolver(r))
|
opts = append(opts, dialer.WithResolver(r))
|
||||||
return dialer.DialContext(ctx, network, addr, opts...)
|
return dialer.DialContext(ctx, network, addr, opts...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,10 +155,14 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
adapter, ok := tunnel.Proxies()[proxyAdapter]
|
if proxyAdapter == nil {
|
||||||
|
var ok bool
|
||||||
|
proxyAdapter, ok = tunnel.Proxies()[proxyName]
|
||||||
if !ok {
|
if !ok {
|
||||||
opts = append(opts, dialer.WithInterface(proxyAdapter))
|
opts = append(opts, dialer.WithInterface(proxyName))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(network, "tcp") {
|
if strings.Contains(network, "tcp") {
|
||||||
// tcp can resolve host by remote
|
// tcp can resolve host by remote
|
||||||
metadata := &C.Metadata{
|
metadata := &C.Metadata{
|
||||||
|
@ -165,8 +170,8 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia
|
||||||
Host: host,
|
Host: host,
|
||||||
DstPort: port,
|
DstPort: port,
|
||||||
}
|
}
|
||||||
if ok {
|
if proxyAdapter != nil {
|
||||||
return adapter.DialContext(ctx, metadata, opts...)
|
return proxyAdapter.DialContext(ctx, metadata, opts...)
|
||||||
}
|
}
|
||||||
opts = append(opts, dialer.WithResolver(r))
|
opts = append(opts, dialer.WithResolver(r))
|
||||||
return dialer.DialContext(ctx, network, addr, opts...)
|
return dialer.DialContext(ctx, network, addr, opts...)
|
||||||
|
@ -182,15 +187,15 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia
|
||||||
DstIP: dstIP,
|
DstIP: dstIP,
|
||||||
DstPort: port,
|
DstPort: port,
|
||||||
}
|
}
|
||||||
if !ok {
|
if proxyAdapter == nil {
|
||||||
return dialer.DialContext(ctx, network, addr, opts...)
|
return dialer.DialContext(ctx, network, addr, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !adapter.SupportUDP() {
|
if !proxyAdapter.SupportUDP() {
|
||||||
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...)
|
packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -201,14 +206,17 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listenPacket(ctx context.Context, proxyAdapter string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) {
|
func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) {
|
||||||
host, port, err := net.SplitHostPort(addr)
|
host, port, err := net.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
adapter, ok := tunnel.Proxies()[proxyAdapter]
|
if proxyAdapter == nil {
|
||||||
if !ok && len(proxyAdapter) != 0 {
|
var ok bool
|
||||||
opts = append(opts, dialer.WithInterface(proxyAdapter))
|
proxyAdapter, ok = tunnel.Proxies()[proxyName]
|
||||||
|
if !ok {
|
||||||
|
opts = append(opts, dialer.WithInterface(proxyName))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// udp must resolve host first
|
// udp must resolve host first
|
||||||
|
@ -222,15 +230,15 @@ func listenPacket(ctx context.Context, proxyAdapter string, network string, addr
|
||||||
DstIP: dstIP,
|
DstIP: dstIP,
|
||||||
DstPort: port,
|
DstPort: port,
|
||||||
}
|
}
|
||||||
if !ok {
|
if proxyAdapter == nil {
|
||||||
return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...)
|
return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !adapter.SupportUDP() {
|
if !proxyAdapter.SupportUDP() {
|
||||||
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapter.ListenPacketContext(ctx, metadata, opts...)
|
return proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
|
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
|
||||||
|
|
|
@ -631,6 +631,8 @@ proxies: # socks5
|
||||||
# reserved: [209,98,59]
|
# reserved: [209,98,59]
|
||||||
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接
|
# 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接
|
||||||
# dialer-proxy: "ss1"
|
# dialer-proxy: "ss1"
|
||||||
|
# remote-dns-resolve: true # 强制dns远程解析,默认值为false
|
||||||
|
# dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在remote-dns-resolve为true时生效
|
||||||
# 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定
|
# 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定
|
||||||
# peers:
|
# peers:
|
||||||
# - server: 162.159.192.1
|
# - server: 162.159.192.1
|
||||||
|
|
Loading…
Reference in a new issue