mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-09-19 07:12:31 +00:00
a375b85fa0
# Conflicts: # .github/workflows/linter.yml # .github/workflows/release.yml # config/config.go # go.mod # go.sum # hub/executor/executor.go
169 lines
4.8 KiB
Go
169 lines
4.8 KiB
Go
package tun
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/Dreamacro/clash/adapter/inbound"
|
|
"github.com/Dreamacro/clash/common/cmd"
|
|
"github.com/Dreamacro/clash/component/process"
|
|
"github.com/Dreamacro/clash/config"
|
|
C "github.com/Dreamacro/clash/constant"
|
|
"github.com/Dreamacro/clash/listener/tun/device"
|
|
"github.com/Dreamacro/clash/listener/tun/device/fdbased"
|
|
"github.com/Dreamacro/clash/listener/tun/device/tun"
|
|
"github.com/Dreamacro/clash/listener/tun/ipstack"
|
|
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
|
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor"
|
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system"
|
|
"github.com/Dreamacro/clash/log"
|
|
"net/netip"
|
|
"net/url"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// New TunAdapter
|
|
func New(tunConf *config.Tun, dnsConf *config.DNS, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
|
|
var tunAddressPrefix string
|
|
if dnsConf.FakeIPRange != nil {
|
|
tunAddressPrefix = dnsConf.FakeIPRange.IPNet().String()
|
|
}
|
|
|
|
var (
|
|
tunAddress, _ = netip.ParsePrefix(tunAddressPrefix)
|
|
devName = tunConf.Device
|
|
stackType = tunConf.Stack
|
|
autoRoute = tunConf.AutoRoute
|
|
mtu = 9000
|
|
|
|
tunDevice device.Device
|
|
tunStack ipstack.Stack
|
|
|
|
err error
|
|
)
|
|
|
|
if devName == "" {
|
|
devName = generateDeviceName()
|
|
}
|
|
|
|
if !tunAddress.IsValid() || !tunAddress.Addr().Is4() {
|
|
tunAddress = netip.MustParsePrefix("198.18.0.1/16")
|
|
}
|
|
|
|
process.AppendLocalIPs(tunAddress.Masked().Addr().Next().AsSlice())
|
|
|
|
// open tun device
|
|
|
|
tunDevice, err = parseDevice(devName, uint32(mtu))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("can't open tun: %w", err)
|
|
}
|
|
|
|
// new ip stack
|
|
switch stackType {
|
|
case C.TunGvisor:
|
|
err = tunDevice.UseEndpoint()
|
|
if err != nil {
|
|
_ = tunDevice.Close()
|
|
return nil, fmt.Errorf("can't attach endpoint to tun: %w", err)
|
|
}
|
|
|
|
tunStack, err = gvisor.New(tunDevice,
|
|
&gvisor.GVHandler{
|
|
DNSAdds: tunConf.DNSHijack,
|
|
TCPIn: tcpIn, UDPIn: udpIn,
|
|
},
|
|
gvisor.WithDefault(),
|
|
)
|
|
|
|
if err != nil {
|
|
_ = tunDevice.Close()
|
|
return nil, fmt.Errorf("can't New gvisor stack: %w", err)
|
|
}
|
|
case C.TunSystem:
|
|
err = tunDevice.UseIOBased()
|
|
if err != nil {
|
|
_ = tunDevice.Close()
|
|
return nil, fmt.Errorf("can't New system stack: %w", err)
|
|
}
|
|
|
|
tunStack, err = system.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn)
|
|
if err != nil {
|
|
_ = tunDevice.Close()
|
|
return nil, fmt.Errorf("can't New system stack: %w", err)
|
|
}
|
|
default:
|
|
// never happen
|
|
}
|
|
|
|
// setting address and routing
|
|
err = commons.ConfigInterfaceAddress(tunDevice, tunAddress, mtu, autoRoute)
|
|
if err != nil {
|
|
_ = tunDevice.Close()
|
|
return nil, fmt.Errorf("setting interface address and routing failed: %w", err)
|
|
}
|
|
|
|
setAtLatest(stackType, devName)
|
|
|
|
log.Infoln("TUN stack listening at: %s(%s), mtu: %d, auto route: %v, ip stack: %s", tunDevice.Name(), tunAddress.Masked().Addr().Next().String(), mtu, autoRoute, stackType)
|
|
return tunStack, nil
|
|
}
|
|
|
|
func generateDeviceName() string {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
return tun.Driver + "://Meta"
|
|
case "windows":
|
|
return tun.Driver + "://Meta"
|
|
default:
|
|
return tun.Driver + "://Meta"
|
|
}
|
|
}
|
|
|
|
func parseDevice(s string, mtu uint32) (device.Device, error) {
|
|
if !strings.Contains(s, "://") {
|
|
s = fmt.Sprintf("%s://%s", tun.Driver /* default driver */, s)
|
|
}
|
|
|
|
u, err := url.Parse(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
name := u.Host
|
|
driver := strings.ToLower(u.Scheme)
|
|
|
|
switch driver {
|
|
case fdbased.Driver:
|
|
return fdbased.Open(name, mtu)
|
|
case tun.Driver:
|
|
return tun.Open(name, mtu)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported driver: %s", driver)
|
|
}
|
|
}
|
|
|
|
func setAtLatest(stackType C.TUNStack, devName string) {
|
|
if stackType != C.TunSystem {
|
|
return
|
|
}
|
|
|
|
switch runtime.GOOS {
|
|
case "windows":
|
|
_, _ = cmd.ExecCmd("ipconfig /renew")
|
|
case "linux":
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.ip_forward=1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.forwarding = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_local = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.accept_redirects = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.rp_filter = 2")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.default.forwarding = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.default.accept_local = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.default.accept_redirects = 1")
|
|
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.default.rp_filter = 2")
|
|
// _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.forwarding = 1", devName))
|
|
// _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_local = 1", devName))
|
|
// _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.accept_redirects = 1", devName))
|
|
// _, _ = cmd.ExecCmd(fmt.Sprintf("sysctl -w net.ipv4.conf.%s.rp_filter = 2", devName))
|
|
// _, _ = cmd.ExecCmd("iptables -t filter -P FORWARD ACCEPT")
|
|
}
|
|
}
|