chore: listeners support tun

This commit is contained in:
wwqgtxx 2022-12-05 17:43:50 +08:00
parent 5c410b8df4
commit fd9c4cbfa5
12 changed files with 260 additions and 50 deletions

View file

@ -243,7 +243,7 @@ type RawTun struct {
RedirectToTun []string `yaml:"-" json:"-"` RedirectToTun []string `yaml:"-" json:"-"`
MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"`
//Inet4Address []ListenPrefix `yaml:"inet4-address" json:"inet4_address,omitempty"` //Inet4Address []LC.ListenPrefix `yaml:"inet4-address" json:"inet4_address,omitempty"`
Inet6Address []LC.ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"` Inet6Address []LC.ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"`
StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"`
Inet4RouteAddress []LC.ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` Inet4RouteAddress []LC.ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"`

View file

@ -740,3 +740,40 @@ listeners:
network: [ tcp, udp ] network: [ tcp, udp ]
target: target.com target: target.com
- name: tun-in-1
type: tun
# rule: sub-rule
stack: system # gvisor / lwip
dns-hijack:
- 0.0.0.0:53 # 需要劫持的 DNS
# auto-detect-interface: false # 自动识别出口网卡
# auto-route: false # 配置路由表
# mtu: 9000 # 最大传输单元
# strict_route: true # 将所有连接路由到tun来防止泄漏但你的设备将无法其他设备被访问
inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由
- 0.0.0.0/1
- 128.0.0.0/1
inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由
- "::/1"
- "8000::/1"
# endpoint_independent_nat: false # 启用独立于端点的 NAT
# include_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route
# - 0
# include_uid_range: # 限制被路由的的用户范围
# - 1000-99999
# exclude_uid: # 排除路由的的用户
#- 1000
# exclude_uid_range: # 排除路由的的用户范围
# - 1000-99999
# Android 用户和应用规则仅在 Android 下被支持
# 并且需要 auto_route
# include_android_user: # 限制被路由的 Android 用户
# - 0
# - 10
# include_package: # 限制被路由的 Android 应用包名
# - com.android.chrome
# exclude_package: # 排除被路由的 Android 应用包名
# - com.android.captiveportallogin

View file

@ -58,6 +58,18 @@ func (p ListenPrefix) Build() netip.Prefix {
return netip.Prefix(p) return netip.Prefix(p)
} }
func StringSliceToListenPrefixSlice(ss []string) ([]ListenPrefix, error) {
lps := make([]ListenPrefix, 0, len(ss))
for _, s := range ss {
prefix, err := netip.ParsePrefix(s)
if err != nil {
return nil, err
}
lps = append(lps, ListenPrefix(prefix))
}
return lps, nil
}
type Tun struct { type Tun struct {
Enable bool Enable bool
Device string Device string

View file

@ -74,7 +74,7 @@ var _ C.InboundListener = (*Base)(nil)
type BaseOption struct { type BaseOption struct {
NameStr string `inbound:"name"` NameStr string `inbound:"name"`
Listen string `inbound:"listen,omitempty"` Listen string `inbound:"listen,omitempty"`
Port int `inbound:"port"` Port int `inbound:"port,omitempty"`
SpecialRules string `inbound:"rule,omitempty"` SpecialRules string `inbound:"rule,omitempty"`
} }

View file

@ -21,6 +21,7 @@ type ShadowSocks struct {
*Base *Base
config *ShadowSocksOption config *ShadowSocksOption
l C.MultiAddrListener l C.MultiAddrListener
ss LC.ShadowsocksServer
} }
func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) { func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) {
@ -31,8 +32,13 @@ func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) {
return &ShadowSocks{ return &ShadowSocks{
Base: base, Base: base,
config: options, config: options,
ss: LC.ShadowsocksServer{
Enable: true,
Listen: base.RawAddress(),
Password: options.Password,
Cipher: options.Cipher,
},
}, nil }, nil
} }
// Config implements constant.InboundListener // Config implements constant.InboundListener
@ -53,17 +59,7 @@ func (s *ShadowSocks) Address() string {
// Listen implements constant.InboundListener // Listen implements constant.InboundListener
func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
s.l, err = sing_shadowsocks.New( s.l, err = sing_shadowsocks.New(s.ss, tcpIn, udpIn, s.Additions()...)
LC.ShadowsocksServer{
Enable: true,
Listen: s.RawAddress(),
Password: s.config.Password,
Cipher: s.config.Cipher,
},
tcpIn,
udpIn,
s.Additions()...,
)
if err != nil { if err != nil {
return err return err
} }

View file

@ -27,6 +27,7 @@ type Tuic struct {
*Base *Base
config *TuicOption config *TuicOption
l *tuic.Listener l *tuic.Listener
ts LC.TuicServer
} }
func NewTuic(options *TuicOption) (*Tuic, error) { func NewTuic(options *TuicOption) (*Tuic, error) {
@ -37,8 +38,19 @@ func NewTuic(options *TuicOption) (*Tuic, error) {
return &Tuic{ return &Tuic{
Base: base, Base: base,
config: options, config: options,
ts: LC.TuicServer{
Enable: true,
Listen: base.RawAddress(),
Token: options.Token,
Certificate: options.Certificate,
PrivateKey: options.PrivateKey,
CongestionController: options.CongestionController,
MaxIdleTime: options.MaxIdleTime,
AuthenticationTimeout: options.AuthenticationTimeout,
ALPN: options.ALPN,
MaxUdpRelayPacketSize: options.MaxUdpRelayPacketSize,
},
}, nil }, nil
} }
// Config implements constant.InboundListener // Config implements constant.InboundListener
@ -59,23 +71,7 @@ func (t *Tuic) Address() string {
// Listen implements constant.InboundListener // Listen implements constant.InboundListener
func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error var err error
t.l, err = tuic.New( t.l, err = tuic.New(t.ts, tcpIn, udpIn, t.Additions()...)
LC.TuicServer{
Enable: true,
Listen: t.RawAddress(),
Token: t.config.Token,
Certificate: t.config.Certificate,
PrivateKey: t.config.PrivateKey,
CongestionController: t.config.CongestionController,
MaxIdleTime: t.config.MaxIdleTime,
AuthenticationTimeout: t.config.AuthenticationTimeout,
ALPN: t.config.ALPN,
MaxUdpRelayPacketSize: t.config.MaxUdpRelayPacketSize,
},
tcpIn,
udpIn,
t.Additions()...,
)
if err != nil { if err != nil {
return err return err
} }

139
listener/inbound/tun.go Normal file
View file

@ -0,0 +1,139 @@
package inbound
import (
"errors"
"net/netip"
"strings"
C "github.com/Dreamacro/clash/constant"
LC "github.com/Dreamacro/clash/listener/config"
"github.com/Dreamacro/clash/listener/sing_tun"
"github.com/Dreamacro/clash/log"
)
type TunOption struct {
BaseOption
Device string `inbound:"device,omitempty"`
Stack string `inbound:"stack,omitempty"`
DNSHijack []string `inbound:"dns-hijack,omitempty"`
AutoRoute bool `inbound:"auto-route,omitempty"`
AutoDetectInterface bool `inbound:"auto-detect-interface,omitempty"`
MTU uint32 `inbound:"mtu,omitempty"`
Inet4Address []string `inbound:"inet4_address,omitempty"`
Inet6Address []string `inbound:"inet6_address,omitempty"`
StrictRoute bool `inbound:"strict_route,omitempty"`
Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"`
Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"`
IncludeUID []uint32 `inbound:"include_uid,omitempty"`
IncludeUIDRange []string `inbound:"include_uid_range,omitempty"`
ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"`
ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"`
IncludeAndroidUser []int `inbound:"include_android_user,omitempty"`
IncludePackage []string `inbound:"include_package,omitempty"`
ExcludePackage []string `inbound:"exclude_package,omitempty"`
EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"`
UDPTimeout int64 `inbound:"udp_timeout,omitempty"`
}
func (o TunOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
type Tun struct {
*Base
config *TunOption
l *sing_tun.Listener
tun LC.Tun
}
func NewTun(options *TunOption) (*Tun, error) {
base, err := NewBase(&options.BaseOption)
if err != nil {
return nil, err
}
stack, exist := C.StackTypeMapping[strings.ToLower(options.Stack)]
if !exist {
return nil, errors.New("invalid tun stack")
}
dnsHijack := make([]netip.AddrPort, 0, len(options.DNSHijack))
for _, str := range options.DNSHijack {
var a netip.AddrPort
err = a.UnmarshalText([]byte(str))
if err != nil {
return nil, err
}
dnsHijack = append(dnsHijack, a)
}
inet4Address, err := LC.StringSliceToListenPrefixSlice(options.Inet4Address)
if err != nil {
return nil, err
}
inet6Address, err := LC.StringSliceToListenPrefixSlice(options.Inet6Address)
if err != nil {
return nil, err
}
inet4RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet4RouteAddress)
if err != nil {
return nil, err
}
inet6RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet6RouteAddress)
if err != nil {
return nil, err
}
return &Tun{
Base: base,
config: options,
tun: LC.Tun{
Enable: true,
Device: options.Device,
Stack: stack,
DNSHijack: dnsHijack,
AutoRoute: options.AutoRoute,
AutoDetectInterface: options.AutoDetectInterface,
MTU: options.MTU,
Inet4Address: inet4Address,
Inet6Address: inet6Address,
StrictRoute: options.StrictRoute,
Inet4RouteAddress: inet4RouteAddress,
Inet6RouteAddress: inet6RouteAddress,
IncludeUID: options.IncludeUID,
IncludeUIDRange: options.IncludeUIDRange,
ExcludeUID: options.ExcludeUID,
ExcludeUIDRange: options.ExcludeUIDRange,
IncludeAndroidUser: options.IncludeAndroidUser,
IncludePackage: options.IncludePackage,
ExcludePackage: options.ExcludePackage,
EndpointIndependentNat: options.EndpointIndependentNat,
UDPTimeout: options.UDPTimeout,
},
}, nil
}
// Config implements constant.InboundListener
func (t *Tun) Config() C.InboundConfig {
return t.config
}
// Address implements constant.InboundListener
func (t *Tun) Address() string {
return t.l.Address()
}
// Listen implements constant.InboundListener
func (t *Tun) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error
t.l, err = sing_tun.New(t.tun, tcpIn, udpIn, t.Additions()...)
if err != nil {
return err
}
log.Infoln("Tun[%s] proxy listening at: %s", t.Name(), t.Address())
return nil
}
// Close implements constant.InboundListener
func (t *Tun) Close() error {
return t.l.Close()
}
var _ C.InboundListener = (*Tun)(nil)

View file

@ -55,7 +55,7 @@ func (t *Tunnel) Close() error {
if err == nil { if err == nil {
err = udpErr err = udpErr
} else { } else {
return fmt.Errorf("close tcp err: %t, close udp err: %t", err.Error(), udpErr.Error()) return fmt.Errorf("close tcp err: %s, close udp err: %s", err.Error(), udpErr.Error())
} }
} }
} }
@ -82,7 +82,8 @@ func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter
return err return err
} }
default: default:
return fmt.Errorf("unknow network type: %s", network) log.Warnln("unknown network type: %s, passed", network)
continue
} }
log.Infoln("Tunnel[%s](%s/%s)proxy listening at: %s", t.Name(), network, t.config.Target, t.Address()) log.Infoln("Tunnel[%s](%s/%s)proxy listening at: %s", t.Name(), network, t.config.Target, t.Address())
} }

View file

@ -26,6 +26,7 @@ type Vmess struct {
*Base *Base
config *VmessOption config *VmessOption
l C.MultiAddrListener l C.MultiAddrListener
vs LC.VmessServer
} }
func NewVmess(options *VmessOption) (*Vmess, error) { func NewVmess(options *VmessOption) (*Vmess, error) {
@ -33,11 +34,23 @@ func NewVmess(options *VmessOption) (*Vmess, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
users := make([]LC.VmessUser, len(options.Users))
for i, v := range options.Users {
users[i] = LC.VmessUser{
Username: v.Username,
UUID: v.UUID,
AlterID: v.AlterID,
}
}
return &Vmess{ return &Vmess{
Base: base, Base: base,
config: options, config: options,
vs: LC.VmessServer{
Enable: true,
Listen: base.RawAddress(),
Users: users,
},
}, nil }, nil
} }
// Config implements constant.InboundListener // Config implements constant.InboundListener
@ -66,16 +79,7 @@ func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter)
AlterID: v.AlterID, AlterID: v.AlterID,
} }
} }
v.l, err = sing_vmess.New( v.l, err = sing_vmess.New(v.vs, tcpIn, udpIn, v.Additions()...)
LC.VmessServer{
Enable: true,
Listen: v.RawAddress(),
Users: users,
},
tcpIn,
udpIn,
v.Additions()...,
)
if err != nil { if err != nil {
return err return err
} }

View file

@ -533,6 +533,7 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack
} }
tunLister, err = sing_tun.New(tunConf, tcpIn, udpIn) tunLister, err = sing_tun.New(tunConf, tcpIn, udpIn)
log.Infoln("[TUN] Tun adapter listening at: %s", tunLister.Address())
} }
func ReCreateRedirToTun(ifaceNames []string) { func ReCreateRedirToTun(ifaceNames []string) {

View file

@ -62,6 +62,16 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) {
return nil, err return nil, err
} }
listener, err = IN.NewTunnel(tunnelOption) listener, err = IN.NewTunnel(tunnelOption)
case "tun":
tunOption := &IN.TunOption{
Stack: C.TunGvisor.String(),
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
}
err = decoder.Decode(mapping, tunOption)
if err != nil {
return nil, err
}
listener, err = IN.NewTun(tunOption)
case "shadowsocks": case "shadowsocks":
shadowsocksOption := &IN.ShadowSocksOption{} shadowsocksOption := &IN.ShadowSocksOption{}
err = decoder.Decode(mapping, shadowsocksOption) err = decoder.Decode(mapping, shadowsocksOption)

View file

@ -2,12 +2,14 @@ package sing_tun
import ( import (
"context" "context"
"fmt"
"net" "net"
"net/netip" "net/netip"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
@ -29,6 +31,7 @@ type Listener struct {
options LC.Tun options LC.Tun
handler *ListenerHandler handler *ListenerHandler
tunName string tunName string
addrStr string
tunIf tun.Tun tunIf tun.Tun
tunStack tun.Stack tunStack tun.Stack
@ -64,7 +67,13 @@ func CalculateInterfaceName(name string) (tunName string) {
return return
} }
func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (l *Listener, err error) { func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (l *Listener, err error) {
if len(additions) == 0 {
additions = []inbound.Addition{
inbound.WithInName("DEFAULT-TUN"),
inbound.WithSpecialRules(""),
}
}
tunName := options.Device tunName := options.Device
if tunName == "" { if tunName == "" {
tunName = CalculateInterfaceName(InterfaceName) tunName = CalculateInterfaceName(InterfaceName)
@ -116,6 +125,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte
TcpIn: tcpIn, TcpIn: tcpIn,
UdpIn: udpIn, UdpIn: udpIn,
Type: C.TUN, Type: C.TUN,
Additions: additions,
}, },
DnsAdds: dnsAdds, DnsAdds: dnsAdds,
} }
@ -211,7 +221,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte
//l.openAndroidHotspot(tunOptions) //l.openAndroidHotspot(tunOptions)
log.Infoln("[TUN] Tun adapter listening at: %s(%s,%s), mtu: %d, auto route: %v, ip stack: %s", l.addrStr = fmt.Sprintf("%s(%s,%s), mtu: %d, auto route: %v, ip stack: %s",
tunName, tunOptions.Inet4Address, tunOptions.Inet6Address, tunMTU, options.AutoRoute, options.Stack) tunName, tunOptions.Inet4Address, tunOptions.Inet6Address, tunMTU, options.AutoRoute, options.Stack)
return return
} }
@ -286,3 +296,7 @@ func (l *Listener) Close() error {
func (l *Listener) Config() LC.Tun { func (l *Listener) Config() LC.Tun {
return l.options return l.options
} }
func (l *Listener) Address() string {
return l.addrStr
}