Skip to content

Commit

Permalink
Feature: mark on socket (#1705)
Browse files Browse the repository at this point in the history
  • Loading branch information
fakeboboliu authored Nov 8, 2021
1 parent e622d8d commit bd2ea2b
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 22 deletions.
20 changes: 14 additions & 6 deletions adapter/outbound/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Base struct {
iface string
tp C.AdapterType
udp bool
rmark int
}

// Name implements C.ProxyAdapter
Expand Down Expand Up @@ -66,19 +67,25 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
opts = append(opts, dialer.WithInterface(b.iface))
}

if b.rmark != 0 {
opts = append(opts, dialer.WithRoutingMark(b.rmark))
}

return opts
}

type BasicOption struct {
Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"`
}

type BaseOption struct {
Name string
Addr string
Type C.AdapterType
UDP bool
Interface string
Name string
Addr string
Type C.AdapterType
UDP bool
Interface string
RoutingMark int
}

func NewBase(opt BaseOption) *Base {
Expand All @@ -88,6 +95,7 @@ func NewBase(opt BaseOption) *Base {
tp: opt.Type,
udp: opt.UDP,
iface: opt.Interface,
rmark: opt.RoutingMark,
}
}

Expand Down
2 changes: 1 addition & 1 deletion adapter/outbound/socks5.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Socks5 struct {
}

type Socks5Option struct {
*BaseOption
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Expand Down
7 changes: 4 additions & 3 deletions adapter/outboundgroup/fallback.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
return &Fallback{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
Type: C.Fallback,
Interface: option.Interface,
Name: option.Name,
Type: C.Fallback,
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
Expand Down
7 changes: 4 additions & 3 deletions adapter/outboundgroup/loadbalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,10 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
}
return &LoadBalance{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
Type: C.LoadBalance,
Interface: option.Interface,
Name: option.Name,
Type: C.LoadBalance,
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
Expand Down
7 changes: 4 additions & 3 deletions adapter/outboundgroup/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) []C.Proxy {
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
return &Relay{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
Type: C.Relay,
Interface: option.Interface,
Name: option.Name,
Type: C.Relay,
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
Expand Down
7 changes: 4 additions & 3 deletions adapter/outboundgroup/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider)
selected := providers[0].Proxies()[0].Name()
return &Selector{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
Type: C.Selector,
Interface: option.Interface,
Name: option.Name,
Type: C.Selector,
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
Expand Down
7 changes: 4 additions & 3 deletions adapter/outboundgroup/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,10 @@ func parseURLTestOption(config map[string]interface{}) []urlTestOption {
func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, options ...urlTestOption) *URLTest {
urlTest := &URLTest{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
Type: C.URLTest,
Interface: option.Interface,
Name: option.Name,
Type: C.URLTest,
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
fastSingle: singledo.NewSingle(time.Second * 10),
Expand Down
6 changes: 6 additions & 0 deletions component/dialer/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ 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)
}
Expand All @@ -82,6 +85,9 @@ func dialContext(ctx context.Context, network string, destination net.IP, port s
return nil, err
}
}
if opt.routingMark != 0 {
bindMarkToDialer(opt.routingMark, dialer, network, destination)
}

return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port))
}
Expand Down
44 changes: 44 additions & 0 deletions component/dialer/mark_linux.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}
27 changes: 27 additions & 0 deletions component/dialer/mark_nonlinux.go
Original file line number Diff line number Diff line change
@@ -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()
}
7 changes: 7 additions & 0 deletions component/dialer/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var (
type option struct {
interfaceName string
addrReuse bool
routingMark int
}

type Option func(opt *option)
Expand All @@ -25,3 +26,9 @@ func WithAddrReuse(reuse bool) Option {
opt.addrReuse = reuse
}
}

func WithRoutingMark(mark int) Option {
return func(opt *option) {
opt.routingMark = mark
}
}

0 comments on commit bd2ea2b

Please sign in to comment.