make tun config compatible with premium

This commit is contained in:
Clash-Mini 2022-01-05 00:33:42 +08:00
parent 14917c8af1
commit 9475799615
11 changed files with 180 additions and 121 deletions

View file

@ -15,15 +15,27 @@ GOBUILDOP=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/cl
PLATFORM_LIST = \
darwin-amd64 \
darwin-arm64 \
linux-arm64 \
linux-amd64 \
linux-arm64-AutoIptables\
linux-amd64-AutoIptables
linux-armv5 \
linux-armv6 \
linux-armv7 \
linux-armv8 \
linux-mips64 \
linux-mips64le \
linux-mips-softfloat \
linux-mips-hardfloat \
linux-mipsle-softfloat \
linux-mipsle-hardfloat \
freebsd-386 \
freebsd-amd64 \
freebsd-arm64
WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64
windows-amd64 \
windows-arm64 \
windows-arm32v7
all: linux-arm64-AutoIptables linux-amd64-AutoIptables linux-arm64 linux-amd64 darwin-amd64 darwin-arm64 windows-amd64 windows-386 # Most used
@ -109,6 +121,9 @@ windows-386:
windows-amd64:
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-arm64:
GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-arm32v7:
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe

View file

@ -48,7 +48,6 @@ type Inbound struct {
RedirPort int `json:"redir-port"`
TProxyPort int `json:"tproxy-port"`
MixedPort int `json:"mixed-port"`
Tun Tun `json:"tun"`
Authentication []string `json:"authentication"`
AllowLan bool `json:"allow-lan"`
BindAddress string `json:"bind-address"`
@ -101,8 +100,9 @@ type Profile struct {
type Tun struct {
Enable bool `yaml:"enable" json:"enable"`
Stack string `yaml:"stack" json:"stack"`
DNSListen string `yaml:"dns-listen" json:"dns-listen"`
DnsHijack []string `yaml:"dns-hijack" json:"dns-hijack"`
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
}
// Script config
@ -209,8 +209,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
Tun: Tun{
Enable: false,
Stack: "gvisor",
DNSListen: "0.0.0.0:53",
DnsHijack: []string{"192.18.0.2:53"},
AutoRoute: true,
AutoDetectInterface: true,
},
DNS: RawDNS{
Enable: false,
@ -225,6 +226,17 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
DefaultNameserver: []string{
"114.114.114.114",
"223.5.5.5",
"8.8.8.8",
"1.0.0.1",
},
NameServer: []string{
"https://8.8.8.8/dns-query",
"https://1.0.0.1/dns-query",
},
FakeIPFilter: []string{
"dns.msftnsci.com",
"www.msftnsci.com",
"www.msftconnecttest.com",
},
},
Profile: Profile{
@ -254,7 +266,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
return nil, err
}
config.General = general
//TODO 暂未使用
config.Tun = &rawCfg.Tun
proxies, providers, err := parseProxies(rawCfg)
@ -312,7 +324,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
RedirPort: cfg.RedirPort,
TProxyPort: cfg.TProxyPort,
MixedPort: cfg.MixedPort,
Tun: cfg.Tun,
AllowLan: cfg.AllowLan,
BindAddress: cfg.BindAddress,
},
@ -332,7 +343,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
proxies = make(map[string]C.Proxy)
providersMap = make(map[string]providerTypes.ProxyProvider)
proxyList := []string{}
var proxyList []string
_proxiesList := list.New()
_groupsList := list.New()
proxiesConfig := cfg.Proxy
@ -421,7 +432,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
}
}
ps := []C.Proxy{}
var ps []C.Proxy
for _, v := range proxyList {
ps = append(ps, proxies[v])
}
@ -502,14 +513,14 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
R.SetRuleProvider(rp)
}
for _, provider := range ruleProviders {
log.Infoln("Start initial provider %s", (*provider).Name())
if err := (*provider).Initial(); err != nil {
return nil, nil, fmt.Errorf("initial rule provider %s error: %w", (*provider).Name(), err)
for _, ruleProvider := range ruleProviders {
log.Infoln("Start initial provider %s", (*ruleProvider).Name())
if err := (*ruleProvider).Initial(); err != nil {
return nil, nil, fmt.Errorf("initial rule provider %s error: %w", (*ruleProvider).Name(), err)
}
}
rules := []C.Rule{}
var rules []C.Rule
rulesConfig := cfg.Rule
mode := cfg.Mode
@ -519,7 +530,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
var (
payload string
target string
params = []string{}
params []string
ruleName = strings.ToUpper(rule[0])
)
@ -607,7 +618,7 @@ func hostWithDefaultPort(host string, defPort string) (string, error) {
}
func parseNameServer(servers []string) ([]dns.NameServer, error) {
nameservers := []dns.NameServer{}
var nameservers []dns.NameServer
for idx, server := range servers {
// parse without scheme .e.g 8.8.8.8:53
@ -675,7 +686,7 @@ func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServe
}
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
ipNets := []*net.IPNet{}
var ipNets []*net.IPNet
for idx, ip := range ips {
_, ipnet, err := net.ParseCIDR(ip)
@ -689,7 +700,7 @@ func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
}
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
sites := []*router.DomainMatcher{}
var sites []*router.DomainMatcher
for _, country := range countries {
found := false
@ -784,7 +795,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie, rules []C.Rule) (*DNS,
if net.ParseIP(fb.Addr) != nil {
continue
}
host.Insert(fb.Addr, true)
_ = host.Insert(fb.Addr, true)
}
}

View file

@ -2,6 +2,7 @@ package constant
import (
"encoding/json"
"fmt"
"net"
"strconv"
)
@ -89,6 +90,14 @@ func (m *Metadata) SourceAddress() string {
return net.JoinHostPort(m.SrcIP.String(), m.SrcPort)
}
func (m *Metadata) SourceDetail() string {
if m.Process != "" {
return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
} else {
return fmt.Sprintf("%s", m.SourceAddress())
}
}
func (m *Metadata) Resolved() bool {
return m.DstIP != nil
}

View file

@ -78,9 +78,10 @@ func ApplyConfig(cfg *config.Config, force bool) {
updateRules(cfg.Rules, cfg.RuleProviders)
updateHosts(cfg.Hosts)
updateProfile(cfg)
updateIPTables(cfg.DNS, cfg.General)
updateDNS(cfg.DNS, cfg.General)
updateIPTables(cfg.DNS, cfg.General, cfg.Tun)
updateDNS(cfg.DNS, cfg.Tun)
updateGeneral(cfg.General, force)
updateTun(cfg.General, cfg.Tun)
updateExperimental(cfg)
}
@ -98,7 +99,6 @@ func GetGeneral() *config.General {
RedirPort: ports.RedirPort,
TProxyPort: ports.TProxyPort,
MixedPort: ports.MixedPort,
Tun: P.Tun(),
Authentication: authenticator,
AllowLan: P.AllowLan(),
BindAddress: P.BindAddress(),
@ -113,8 +113,8 @@ func GetGeneral() *config.General {
func updateExperimental(c *config.Config) {}
func updateDNS(c *config.DNS, general *config.General) {
if !c.Enable && !general.Tun.Enable {
func updateDNS(c *config.DNS, Tun *config.Tun) {
if !c.Enable && !Tun.Enable {
resolver.DefaultResolver = nil
resolver.MainResolver = nil
resolver.DefaultHostMapper = nil
@ -152,7 +152,7 @@ func updateDNS(c *config.DNS, general *config.General) {
resolver.DefaultResolver = r
resolver.MainResolver = mr
resolver.DefaultHostMapper = m
if general.Tun.Enable && !strings.EqualFold(general.Tun.Stack, "gvisor") {
if Tun.Enable && !strings.EqualFold(Tun.Stack, "gVisor") {
resolver.DefaultLocalServer = dns.NewLocalServer(r, m)
} else {
resolver.DefaultLocalServer = nil
@ -179,20 +179,6 @@ func updateGeneral(general *config.General, force bool) {
tunnel.SetMode(general.Mode)
resolver.DisableIPv6 = !general.IPv6
adapter.UnifiedDelay.Store(general.UnifiedDelay)
if (general.Tun.Enable || general.TProxyPort != 0) && general.Interface == "" {
autoDetectInterfaceName, err := dev.GetAutoDetectInterface()
if err == nil {
if autoDetectInterfaceName != "" && autoDetectInterfaceName != "<nil>" {
general.Interface = autoDetectInterfaceName
} else {
log.Debugln("Auto detect interface name is empty.")
}
} else {
log.Debugln("Can not find auto detect interface. %s", err.Error())
}
}
dialer.DefaultInterface.Store(general.Interface)
log.Infoln("Use interface name: %s", general.Interface)
@ -219,12 +205,33 @@ func updateGeneral(general *config.General, force bool) {
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
if err := P.ReCreateTun(general.Tun, tcpIn, udpIn); err != nil {
log.Errorln("Start Tun interface error: %s", err.Error())
os.Exit(2)
log.SetLevel(general.LogLevel)
}
log.SetLevel(general.LogLevel)
func updateTun(General *config.General, Tun *config.Tun) {
if Tun == nil {
return
}
if (Tun.Enable || General.TProxyPort != 0) && General.Interface == "" {
autoDetectInterfaceName, err := dev.GetAutoDetectInterface()
if err == nil {
if autoDetectInterfaceName != "" && autoDetectInterfaceName != "<nil>" {
General.Interface = autoDetectInterfaceName
} else {
log.Debugln("Auto detect interface name is empty.")
}
} else {
log.Debugln("Can not find auto detect interface. %s", err.Error())
}
}
tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn()
if err := P.ReCreateTun(*Tun, tcpIn, udpIn); err != nil {
log.Errorln("Start Tun interface error: %s", err.Error())
}
}
func updateUsers(users []auth.AuthUser) {
@ -270,9 +277,9 @@ func patchSelectGroup(proxies map[string]C.Proxy) {
}
}
func updateIPTables(dns *config.DNS, general *config.General) {
func updateIPTables(dns *config.DNS, general *config.General, tun *config.Tun) {
AutoIptables := C.AutoIptables
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || general.Tun.Enable || AutoIptables != "Enable" {
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || tun.Enable || AutoIptables != "Enable" {
return
}

View file

@ -23,7 +23,6 @@ type Rule struct {
func getRules(w http.ResponseWriter, r *http.Request) {
rawRules := tunnel.Rules()
rules := []Rule{}
for _, rule := range rawRules {
rules = append(rules, Rule{
@ -31,6 +30,7 @@ func getRules(w http.ResponseWriter, r *http.Request) {
Payload: rule.Payload(),
Proxy: rule.Adapter(),
})
}
render.JSON(w, r, render.M{

View file

@ -71,7 +71,7 @@ func Tun() config.Tun {
return config.Tun{
Enable: true,
Stack: tunAdapter.Stack(),
DNSListen: tunAdapter.DNSListen(),
DnsHijack: tunAdapter.DnsHijack(),
AutoRoute: tunAdapter.AutoRoute(),
}
}

View file

@ -36,7 +36,7 @@ const nicID tcpip.NICID = 1
type gvisorAdapter struct {
device dev.TunDevice
ipstack *stack.Stack
dnsserver *DNSServer
dnsServers []*DNSServer
udpIn chan<- *inbound.PacketAdapter
stackName string
@ -113,7 +113,7 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, tcpIn chan<- C.ConnContex
ipstack.SetTransportProtocolHandler(udp.ProtocolNumber, adapter.udpHandlePacket)
if resolver.DefaultResolver != nil {
err = adapter.ReCreateDNSServer(resolver.DefaultResolver.(*dns.Resolver), resolver.DefaultHostMapper.(*dns.ResolverEnhancer), conf.DNSListen)
err = adapter.ReCreateDNSServer(resolver.DefaultResolver.(*dns.Resolver), resolver.DefaultHostMapper.(*dns.ResolverEnhancer), conf.DnsHijack)
if err != nil {
return nil, err
}
@ -132,9 +132,7 @@ func (t *gvisorAdapter) AutoRoute() bool {
// Close close the TunAdapter
func (t *gvisorAdapter) Close() {
if t.dnsserver != nil {
t.dnsserver.Stop()
}
t.StopAllDNSServer()
if t.ipstack != nil {
t.ipstack.Close()
}

View file

@ -241,41 +241,43 @@ func (s *DNSServer) Stop() {
s.NICID)
}
// DNSListen return the listening address of DNS Server
func (t *gvisorAdapter) DNSListen() string {
if t.dnsserver != nil {
id := t.dnsserver.udpEndpointID
return fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort)
}
return ""
// DnsHijack return the listening address of DNS Server
func (t *gvisorAdapter) DnsHijack() []string {
results := make([]string, len(t.dnsServers))
for i, dnsServer := range t.dnsServers {
id := dnsServer.udpEndpointID
results[i] = fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort)
}
// Stop stop the DNS Server on tun
func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, addr string) error {
if addr == "" && t.dnsserver == nil {
return nil
return results
}
if addr == t.DNSListen() && t.dnsserver != nil && t.dnsserver.resolver == resolver {
return nil
func (t *gvisorAdapter) StopAllDNSServer() {
for _, dnsServer := range t.dnsServers {
dnsServer.Stop()
}
if t.dnsserver != nil {
t.dnsserver.Stop()
t.dnsserver = nil
log.Debugln("tun DNS server stoped")
t.dnsServers = nil
}
// ReCreateDNSServer recreate the DNS Server on tun
func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, addrs []string) error {
t.StopAllDNSServer()
if resolver == nil {
return fmt.Errorf("failed to create DNS server on tun: resolver not provided")
}
if len(addrs) == 0 {
return fmt.Errorf("failed to create DNS server on tun: len(addrs) == 0")
}
for _, addr := range addrs {
var err error
_, port, err := net.SplitHostPort(addr)
if port == "0" || port == "" || err != nil {
return nil
}
if resolver == nil {
return fmt.Errorf("failed to create DNS server on tun: resolver not provided")
}
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return err
@ -285,7 +287,9 @@ func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.Re
if err != nil {
return err
}
t.dnsserver = server
t.dnsServers = append(t.dnsServers, server)
log.Infoln("Tun DNS server listening at: %s, fake ip enabled: %v", addr, mapper.FakeIPEnabled())
}
return nil
}

View file

@ -4,6 +4,6 @@ package ipstack
type TunAdapter interface {
Close()
Stack() string
DNSListen() string
DnsHijack() []string
AutoRoute() bool
}

View file

@ -21,7 +21,7 @@ type systemAdapter struct {
tun *tun2socket.Tun2Socket
lock sync.Mutex
stackName string
dnsListen string
dnsHackjack []string
autoRoute bool
}
@ -29,14 +29,14 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror
adapter := &systemAdapter{
device: device,
stackName: conf.Stack,
dnsListen: conf.DNSListen,
dnsHackjack: conf.DnsHijack,
autoRoute: conf.AutoRoute,
}
adapter.lock.Lock()
defer adapter.lock.Unlock()
dnsHost, dnsPort, err := net.SplitHostPort(conf.DNSListen)
dnsHost, dnsPort, err := net.SplitHostPort(conf.DnsHijack[0])
if err != nil {
return nil, err
}
@ -91,8 +91,8 @@ func (t *systemAdapter) AutoRoute() bool {
return t.autoRoute
}
func (t *systemAdapter) DNSListen() string {
return t.dnsListen
func (t *systemAdapter) DnsHijack() []string {
return t.dnsHackjack
}
func (t *systemAdapter) Close() {

View file

@ -242,17 +242,24 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
pCtx.InjectPacketConn(rawPc)
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule)
var ruleDetail string
if rule.Payload() != "" {
ruleDetail = fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload())
} else {
ruleDetail = rule.RuleType().String()
}
switch true {
case rule != nil:
log.Infoln("[UDP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), rawPc.Chains().String())
log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), ruleDetail, rawPc.Chains().String())
case mode == Script:
log.Infoln("[UDP] %s --> %s using SCRIPT %s", metadata.SourceAddress(), metadata.RemoteAddress(), rawPc.Chains().String())
log.Infoln("[UDP] %s --> %s using SCRIPT %s", metadata.SourceDetail(), metadata.RemoteAddress(), rawPc.Chains().String())
case mode == Global:
log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[UDP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress())
case mode == Direct:
log.Infoln("[UDP] %s(%s) --> %s using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[UDP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
default:
log.Infoln("[UDP] %s(%s) --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
}
go handleUDPToLocal(packet.UDPPacket, pc, key, fAddr)
@ -296,17 +303,25 @@ func handleTCPConn(connCtx C.ConnContext) {
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
defer remoteConn.Close()
var ruleDetail string
if rule.Payload() != "" {
ruleDetail = fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload())
} else {
ruleDetail = rule.RuleType().String()
}
switch true {
case rule != nil:
log.Infoln("[TCP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), ruleDetail, remoteConn.Chains().String())
case mode == Script:
log.Infoln("[TCP] %s(%s) --> %s using SCRIPT %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), remoteConn.Chains().String())
log.Infoln("[TCP] %s --> %s using SCRIPT %s", metadata.SourceDetail(), metadata.RemoteAddress(), remoteConn.Chains().String())
case mode == Global:
log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[TCP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress())
case mode == Direct:
log.Infoln("[TCP] %s(%s) --> %s using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[TCP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
default:
log.Infoln("[TCP] %s(%s) --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
log.Infoln("[TCP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
}
handleSocket(connCtx, remoteConn)