Merge pull request #274 from HyNetwork/resolve-preference

feat: resolve preference
This commit is contained in:
Toby 2022-03-27 15:15:20 -07:00 committed by GitHub
commit 614faf75a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 12 deletions

View File

@ -97,6 +97,18 @@ func client(config *clientConfig) {
if len(config.Obfs) > 0 {
obfuscator = obfs.NewXPlusObfuscator([]byte(config.Obfs))
}
// Resolve preference
if len(config.ResolvePreference) > 0 {
pref, excl, err := transport.ResolvePreferenceFromString(config.ResolvePreference)
if err != nil {
logrus.WithFields(logrus.Fields{
"error": err,
}).Fatal("Failed to parse the resolve preference")
}
transport.DefaultClientTransport.PrefEnabled = true
transport.DefaultClientTransport.PrefIPv6 = pref
transport.DefaultClientTransport.PrefExclusive = excl
}
// ACL
var aclEngine *acl.Engine
if len(config.ACL) > 0 {

View File

@ -50,8 +50,8 @@ type serverConfig struct {
ReceiveWindowClient uint64 `json:"recv_window_client"`
MaxConnClient int `json:"max_conn_client"`
DisableMTUDiscovery bool `json:"disable_mtu_discovery"`
IPv6Only bool `json:"ipv6_only"`
Resolver string `json:"resolver"`
ResolvePreference string `json:"resolve_preference"`
SOCKS5Outbound struct {
Server string `json:"server"`
User string `json:"user"`
@ -159,6 +159,7 @@ type clientConfig struct {
ReceiveWindow uint64 `json:"recv_window"`
DisableMTUDiscovery bool `json:"disable_mtu_discovery"`
Resolver string `json:"resolver"`
ResolvePreference string `json:"resolve_preference"`
}
func (c *clientConfig) Check() error {

View File

@ -140,9 +140,17 @@ func server(config *serverConfig) {
if len(config.Obfs) > 0 {
obfuscator = obfs.NewXPlusObfuscator([]byte(config.Obfs))
}
// IPv6 only mode
if config.IPv6Only {
transport.DefaultServerTransport.IPv6Only = true
// Resolve preference
if len(config.ResolvePreference) > 0 {
pref, excl, err := transport.ResolvePreferenceFromString(config.ResolvePreference)
if err != nil {
logrus.WithFields(logrus.Fields{
"error": err,
}).Fatal("Failed to parse the resolve preference")
}
transport.DefaultServerTransport.PrefEnabled = true
transport.DefaultServerTransport.PrefIPv6 = pref
transport.DefaultServerTransport.PrefExclusive = excl
}
// SOCKS5 outbound
if config.SOCKS5Outbound.Server != "" {

View File

@ -13,13 +13,17 @@ import (
)
type ClientTransport struct {
Dialer *net.Dialer
Dialer *net.Dialer
PrefEnabled bool
PrefIPv6 bool
PrefExclusive bool
}
var DefaultClientTransport = &ClientTransport{
Dialer: &net.Dialer{
Timeout: 8 * time.Second,
},
PrefEnabled: false,
}
func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfs.Obfuscator) (net.PacketConn, error) {
@ -80,7 +84,11 @@ func (ct *ClientTransport) QUICDial(proto string, server string, tlsConfig *tls.
}
func (ct *ClientTransport) ResolveIPAddr(address string) (*net.IPAddr, error) {
return net.ResolveIPAddr("ip", address)
if ct.PrefEnabled {
return resolveIPAddrWithPreference(address, ct.PrefIPv6, ct.PrefExclusive)
} else {
return net.ResolveIPAddr("ip", address)
}
}
func (ct *ClientTransport) DialTCP(raddr *net.TCPAddr) (*net.TCPConn, error) {

58
pkg/transport/resolve.go Normal file
View File

@ -0,0 +1,58 @@
package transport
import (
"errors"
"fmt"
"net"
)
var (
errNoIPv4Addr = errors.New("no IPv4 address")
errNoIPv6Addr = errors.New("no IPv6 address")
)
func resolveIPAddrWithPreference(address string, preferIPv6 bool, exclusive bool) (*net.IPAddr, error) {
ips, err := net.LookupIP(address)
if err != nil {
return nil, err
}
if preferIPv6 {
for _, ip := range ips {
if ip.To4() == nil {
return &net.IPAddr{IP: ip}, nil
}
}
if exclusive {
return nil, errNoIPv6Addr
} else {
return &net.IPAddr{IP: ips[0]}, nil
}
} else {
// prefer IPv4
for _, ip := range ips {
if ip.To4() != nil {
return &net.IPAddr{IP: ip}, nil
}
}
if exclusive {
return nil, errNoIPv4Addr
} else {
return &net.IPAddr{IP: ips[0]}, nil
}
}
}
func ResolvePreferenceFromString(preference string) (bool, bool, error) {
switch preference {
case "4":
return false, true, nil
case "6":
return true, true, nil
case "46":
return false, false, nil
case "64":
return true, false, nil
default:
return false, false, fmt.Errorf("%s is not a valid preference", preference)
}
}

View File

@ -13,9 +13,11 @@ import (
)
type ServerTransport struct {
Dialer *net.Dialer
IPv6Only bool
SOCKS5Client *SOCKS5Client
Dialer *net.Dialer
SOCKS5Client *SOCKS5Client
PrefEnabled bool
PrefIPv6 bool
PrefExclusive bool
}
type PUDPConn interface {
@ -28,7 +30,7 @@ var DefaultServerTransport = &ServerTransport{
Dialer: &net.Dialer{
Timeout: 8 * time.Second,
},
IPv6Only: false,
PrefEnabled: false,
}
func (st *ServerTransport) quicPacketConn(proto string, laddr string, obfs obfs.Obfuscator) (net.PacketConn, error) {
@ -92,8 +94,8 @@ func (ct *ServerTransport) QUICListen(proto string, listen string, tlsConfig *tl
}
func (ct *ServerTransport) ResolveIPAddr(address string) (*net.IPAddr, error) {
if ct.IPv6Only {
return net.ResolveIPAddr("ip6", address)
if ct.PrefEnabled {
return resolveIPAddrWithPreference(address, ct.PrefIPv6, ct.PrefExclusive)
} else {
return net.ResolveIPAddr("ip", address)
}