Merge from remote branch

This commit is contained in:
yaling888
2021-11-09 21:11:38 +08:00
35 changed files with 514 additions and 296 deletions

View File

@ -58,15 +58,15 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
return nil
}
local := 0
local := int64(0)
if dialer.LocalAddr != nil {
_, port, err := net.SplitHostPort(dialer.LocalAddr.String())
if err == nil {
local, _ = strconv.Atoi(port)
local, _ = strconv.ParseInt(port, 10, 16)
}
}
addr, err := lookupLocalAddr(ifaceName, network, destination, local)
addr, err := lookupLocalAddr(ifaceName, network, destination, int(local))
if err != nil {
return err
}
@ -82,9 +82,9 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
port = "0"
}
local, _ := strconv.Atoi(port)
local, _ := strconv.ParseInt(port, 10, 16)
addr, err := lookupLocalAddr(ifaceName, network, nil, local)
addr, err := lookupLocalAddr(ifaceName, network, nil, int(local))
if err != nil {
return "", err
}

View File

@ -9,16 +9,12 @@ import (
)
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
opt := &config{}
for _, o := range options {
o(opt)
opt := &option{
interfaceName: DefaultInterface.Load(),
}
if !opt.skipDefault {
for _, o := range DefaultOptions {
o(opt)
}
for _, o := range DefaultOptions {
o(opt)
}
for _, o := range options {
@ -60,16 +56,12 @@ func DialContext(ctx context.Context, network, address string, options ...Option
}
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
cfg := &config{}
for _, o := range options {
o(cfg)
cfg := &option{
interfaceName: DefaultInterface.Load(),
}
if !cfg.skipDefault {
for _, o := range DefaultOptions {
o(cfg)
}
for _, o := range DefaultOptions {
o(cfg)
}
for _, o := range options {
@ -87,22 +79,28 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
if cfg.addrReuse {
addrReuseToListenConfig(lc)
}
if cfg.routingMark != 0 {
bindMarkToListenConfig(cfg.routingMark, lc, network, address)
}
return lc.ListenPacket(ctx, network, address)
}
func dialContext(ctx context.Context, network string, destination net.IP, port string, opt *config) (net.Conn, error) {
func dialContext(ctx context.Context, network string, destination net.IP, port string, opt *option) (net.Conn, error) {
dialer := &net.Dialer{}
if opt.interfaceName != "" {
if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil {
return nil, err
}
}
if opt.routingMark != 0 {
bindMarkToDialer(opt.routingMark, dialer, network, destination)
}
return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
}
func dualStackDialContext(ctx context.Context, network, address string, opt *config) (net.Conn, error) {
func dualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return nil, err

View File

@ -0,0 +1,44 @@
//go:build linux
// +build linux
package dialer
import (
"net"
"syscall"
)
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
dialer.Control = bindMarkToControl(mark, dialer.Control)
}
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
lc.Control = bindMarkToControl(mark, lc.Control)
}
func bindMarkToControl(mark int, chain controlFn) controlFn {
return func(network, address string, c syscall.RawConn) (err error) {
defer func() {
if err == nil && chain != nil {
err = chain(network, address, c)
}
}()
ipStr, _, err := net.SplitHostPort(address)
if err == nil {
ip := net.ParseIP(ipStr)
if ip != nil && !ip.IsGlobalUnicast() {
return
}
}
return c.Control(func(fd uintptr) {
switch network {
case "tcp4", "udp4":
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
case "tcp6", "udp6":
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
}
})
}
}

View File

@ -0,0 +1,27 @@
//go:build !linux
// +build !linux
package dialer
import (
"net"
"sync"
"github.com/Dreamacro/clash/log"
)
var printMarkWarnOnce sync.Once
func printMarkWarn() {
printMarkWarnOnce.Do(func() {
log.Warnln("Routing mark on socket is not supported on current platform")
})
}
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
printMarkWarn()
}
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
printMarkWarn()
}

View File

@ -1,29 +1,34 @@
package dialer
var DefaultOptions []Option
import "go.uber.org/atomic"
type config struct {
skipDefault bool
var (
DefaultOptions []Option
DefaultInterface = atomic.NewString("")
)
type option struct {
interfaceName string
addrReuse bool
routingMark int
}
type Option func(opt *config)
type Option func(opt *option)
func WithInterface(name string) Option {
return func(opt *config) {
return func(opt *option) {
opt.interfaceName = name
}
}
func WithAddrReuse(reuse bool) Option {
return func(opt *config) {
return func(opt *option) {
opt.addrReuse = reuse
}
}
func WithSkipDefault(skip bool) Option {
return func(opt *config) {
opt.skipDefault = skip
func WithRoutingMark(mark int) Option {
return func(opt *option) {
opt.routingMark = mark
}
}