add sockopts config

This commit is contained in:
ginuerzh 2022-03-29 23:04:12 +08:00
parent 78089d8887
commit 47cfc087e9
11 changed files with 115 additions and 36 deletions

View File

@ -20,7 +20,6 @@ var (
type Route struct { type Route struct {
chain *Chain chain *Chain
ifceName string
nodes []*Node nodes []*Node
logger logger.Logger logger logger.Logger
} }
@ -29,14 +28,24 @@ func (r *Route) addNode(node *Node) {
r.nodes = append(r.nodes, node) r.nodes = append(r.nodes, node)
} }
func (r *Route) Dial(ctx context.Context, network, address string) (net.Conn, error) { func (r *Route) Dial(ctx context.Context, network, address string, opts ...DialOption) (net.Conn, error) {
var options DialOptions
for _, opt := range opts {
opt(&options)
}
if r.Len() == 0 { if r.Len() == 0 {
netd := dialer.NetDialer{ netd := dialer.NetDialer{
Timeout: 30 * time.Second, Timeout: options.Timeout,
Interface: options.Interface,
}
if options.SockOpts != nil {
netd.Mark = options.SockOpts.Mark
} }
if r != nil { if r != nil {
netd.Interface = r.ifceName netd.Logger = r.logger
} }
return netd.Dial(ctx, network, address) return netd.Dial(ctx, network, address)
} }
@ -198,3 +207,29 @@ func (r *Route) bindLocal(ctx context.Context, network, address string, opts ...
return nil, err return nil, err
} }
} }
type DialOptions struct {
Timeout time.Duration
Interface string
SockOpts *SockOpts
}
type DialOption func(opts *DialOptions)
func TimeoutDialOption(d time.Duration) DialOption {
return func(opts *DialOptions) {
opts.Timeout = d
}
}
func InterfaceDialOption(ifName string) DialOption {
return func(opts *DialOptions) {
opts.Interface = ifName
}
}
func SockOptsDialOption(so *SockOpts) DialOption {
return func(opts *DialOptions) {
opts.SockOpts = so
}
}

View File

@ -13,10 +13,15 @@ import (
"github.com/go-gost/core/resolver" "github.com/go-gost/core/resolver"
) )
type SockOpts struct {
Mark int
}
type Router struct { type Router struct {
ifceName string
sockOpts *SockOpts
timeout time.Duration timeout time.Duration
retries int retries int
ifceName string
chain Chainer chain Chainer
resolver resolver.Resolver resolver resolver.Resolver
hosts hosts.HostMapper hosts hosts.HostMapper
@ -38,6 +43,11 @@ func (r *Router) WithInterface(ifceName string) *Router {
return r return r
} }
func (r *Router) WithSockOpts(so *SockOpts) *Router {
r.sockOpts = so
return r
}
func (r *Router) WithChain(chain Chainer) *Router { func (r *Router) WithChain(chain Chainer) *Router {
r.chain = chain r.chain = chain
return r return r
@ -109,10 +119,11 @@ func (r *Router) dial(ctx context.Context, network, address string) (conn net.Co
if route == nil { if route == nil {
route = &Route{} route = &Route{}
} }
route.ifceName = r.ifceName
route.logger = r.logger route.logger = r.logger
conn, err = route.Dial(ctx, network, address,
conn, err = route.Dial(ctx, network, address) InterfaceDialOption(r.ifceName),
SockOptsDialOption(r.sockOpts),
)
if err == nil { if err == nil {
break break
} }

View File

@ -13,6 +13,7 @@ import (
type Transport struct { type Transport struct {
addr string addr string
ifceName string ifceName string
sockOpts *SockOpts
route *Route route *Route
dialer dialer.Dialer dialer dialer.Dialer
connector connector.Connector connector connector.Connector
@ -29,6 +30,11 @@ func (tr *Transport) WithInterface(ifceName string) *Transport {
return tr return tr
} }
func (tr *Transport) WithSockOpts(so *SockOpts) *Transport {
tr.sockOpts = so
return tr
}
func (tr *Transport) WithDialer(dialer dialer.Dialer) *Transport { func (tr *Transport) WithDialer(dialer dialer.Dialer) *Transport {
tr.dialer = dialer tr.dialer = dialer
return tr return tr
@ -42,7 +48,10 @@ func (tr *Transport) WithConnector(connector connector.Connector) *Transport {
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) { func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
netd := &net_dialer.NetDialer{ netd := &net_dialer.NetDialer{
Interface: tr.ifceName, Interface: tr.ifceName,
Timeout: 30 * time.Second, Timeout: 15 * time.Second,
}
if tr.sockOpts != nil {
netd.Mark = tr.sockOpts.Mark
} }
if tr.route.Len() > 0 { if tr.route.Len() > 0 {
netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) { netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {

View File

@ -10,14 +10,17 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
const (
DefaultTimeout = 15 * time.Second
)
var ( var (
DefaultNetDialer = &NetDialer{ DefaultNetDialer = &NetDialer{}
Timeout: 30 * time.Second,
}
) )
type NetDialer struct { type NetDialer struct {
Interface string Interface string
Mark int
Timeout time.Duration Timeout time.Duration
DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
Logger logger.Logger Logger logger.Logger
@ -27,6 +30,10 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (net.Conn, e
if d == nil { if d == nil {
d = DefaultNetDialer d = DefaultNetDialer
} }
if d.Timeout <= 0 {
d.Timeout = DefaultTimeout
}
log := d.Logger log := d.Logger
if log == nil { if log == nil {
log = logger.Default() log = logger.Default()
@ -39,7 +46,7 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (net.Conn, e
if d.DialFunc != nil { if d.DialFunc != nil {
return d.DialFunc(ctx, network, addr) return d.DialFunc(ctx, network, addr)
} }
logger.Default().Infof("interface: %s %v/%s", ifceName, ifAddr, network) log.Infof("interface: %s %v/%s", ifceName, ifAddr, network)
switch network { switch network {
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":
@ -59,17 +66,18 @@ func (d *NetDialer) Dial(ctx context.Context, network, addr string) (net.Conn, e
Timeout: d.Timeout, Timeout: d.Timeout,
LocalAddr: ifAddr, LocalAddr: ifAddr,
Control: func(network, address string, c syscall.RawConn) error { Control: func(network, address string, c syscall.RawConn) error {
var cerr error return c.Control(func(fd uintptr) {
err := c.Control(func(fd uintptr) { if ifceName != "" {
cerr = bindDevice(fd, ifceName) if err := bindDevice(fd, ifceName); err != nil {
log.Warnf("bind device: %v", err)
}
}
if d.Mark != 0 {
if err := setMark(fd, d.Mark); err != nil {
log.Warnf("set mark: %v", err)
}
}
}) })
if err != nil {
return err
}
if cerr != nil {
return cerr
}
return nil
}, },
} }
return netd.DialContext(ctx, network, addr) return netd.DialContext(ctx, network, addr)

View File

@ -12,3 +12,10 @@ func bindDevice(fd uintptr, ifceName string) error {
} }
return unix.BindToDevice(int(fd), ifceName) return unix.BindToDevice(int(fd), ifceName)
} }
func setMark(fd uintptr, mark int) error {
if mark == 0 {
return nil
}
return unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, mark)
}

View File

@ -5,3 +5,7 @@ package dialer
func bindDevice(fd uintptr, ifceName string) error { func bindDevice(fd uintptr, ifceName string) error {
return nil return nil
} }
func setMark(fd uintptr, mark int) error {
return nil
}

View File

@ -41,7 +41,7 @@ func (r *UDPRelay) SetBufferSize(n int) {
func (r *UDPRelay) Run() (err error) { func (r *UDPRelay) Run() (err error) {
bufSize := r.bufferSize bufSize := r.bufferSize
if bufSize <= 0 { if bufSize <= 0 {
bufSize = 1024 bufSize = 1500
} }
errc := make(chan error, 2) errc := make(chan error, 2)

View File

@ -154,7 +154,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
} }
if network == "udp" { if network == "udp" {
return h.handleUDP(ctx, conn, network, req.Host, log) return h.handleUDP(ctx, conn, log)
} }
if req.Method == "PRI" || if req.Method == "PRI" ||

View File

@ -13,7 +13,7 @@ import (
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, log logger.Logger) error {
log = log.WithFields(map[string]any{ log = log.WithFields(map[string]any{
"cmd": "udp", "cmd": "udp",
}) })

View File

@ -34,7 +34,7 @@ func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
if bs := mdata.GetInt(md, udpBufferSize); bs > 0 { if bs := mdata.GetInt(md, udpBufferSize); bs > 0 {
h.md.udpBufferSize = int(math.Min(math.Max(float64(bs), 512), 64*1024)) h.md.udpBufferSize = int(math.Min(math.Max(float64(bs), 512), 64*1024))
} else { } else {
h.md.udpBufferSize = 1024 h.md.udpBufferSize = 1500
} }
h.md.compatibilityMode = mdata.GetBool(md, compatibilityMode) h.md.compatibilityMode = mdata.GetBool(md, compatibilityMode)

View File

@ -38,6 +38,15 @@ func (c *serverConn) Write(b []byte) (n int, err error) {
return return
} }
func (c *serverConn) SyscallConn() (rc syscall.RawConn, err error) {
if sc, ok := c.Conn.(syscall.Conn); ok {
rc, err = sc.SyscallConn()
return
}
err = errUnsupport
return
}
type packetConn struct { type packetConn struct {
net.PacketConn net.PacketConn
service string service string
@ -168,7 +177,7 @@ func (c *udpConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, er
} }
func (c *udpConn) SyscallConn() (rc syscall.RawConn, err error) { func (c *udpConn) SyscallConn() (rc syscall.RawConn, err error) {
if nc, ok := c.PacketConn.(syscallConn); ok { if nc, ok := c.PacketConn.(syscall.Conn); ok {
return nc.SyscallConn() return nc.SyscallConn()
} }
err = errUnsupport err = errUnsupport
@ -189,8 +198,8 @@ type UDPConn interface {
readUDP readUDP
writeUDP writeUDP
setBuffer setBuffer
syscallConn
remoteAddr remoteAddr
syscall.Conn
} }
type setBuffer interface { type setBuffer interface {
@ -208,10 +217,6 @@ type writeUDP interface {
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
} }
type syscallConn interface {
SyscallConn() (syscall.RawConn, error)
}
type remoteAddr interface { type remoteAddr interface {
RemoteAddr() net.Addr RemoteAddr() net.Addr
} }