Chore: bump to go1.18rc1, use netip.Addr to replace net.IP with system TUN stack

This commit is contained in:
yaling888
2022-03-12 02:16:13 +08:00
parent 8333815e95
commit 8b4f9a35f6
19 changed files with 166 additions and 805 deletions

View File

@ -389,3 +389,9 @@ func genAddr(host string, port int, allowLan bool) string {
return fmt.Sprintf("127.0.0.1:%d", port)
}
func Cleanup() {
if tunStackListener != nil {
_ = tunStackListener.Close()
}
}

View File

@ -64,11 +64,11 @@ func (t *TUN) Read(packet []byte) (int, error) {
return t.nt.Read(packet, t.offset)
}
buff := make([]byte, t.offset+int(t.mtu))
buff := make([]byte, t.offset+cap(packet))
n, err := t.nt.Read(buff, t.offset)
if err != nil {
return n, err
return 0, err
}
copy(packet, buff[t.offset:t.offset+n])

View File

@ -1,7 +1,7 @@
package commons
import (
"net"
"net/netip"
"time"
"github.com/Dreamacro/clash/component/resolver"
@ -11,17 +11,12 @@ import (
const DefaultDnsReadTimeout = time.Second * 10
func ShouldHijackDns(dnsAdds []net.IP, targetAddr net.IP, targetPort int) bool {
if targetPort != 53 {
return false
}
for _, ip := range dnsAdds {
if ip.IsUnspecified() || ip.Equal(targetAddr) {
func ShouldHijackDns(dnsAdds []netip.AddrPort, targetAddr netip.AddrPort) bool {
for _, addrPort := range dnsAdds {
if addrPort == targetAddr || (addrPort.Addr().IsUnspecified() && targetAddr.Port() == 53) {
return true
}
}
return false
}

View File

@ -7,7 +7,8 @@ import (
var ROUTES = []string{"1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1"}
func IPv4MaskString(m net.IPMask) string {
func IPv4MaskString(bits int) string {
m := net.CIDRMask(bits, 32)
if len(m) != 4 {
panic("ipv4Mask: len must be 4 bytes")
}

View File

@ -2,7 +2,7 @@ package commons
import (
"fmt"
"net"
"net/netip"
"github.com/Dreamacro/clash/common/cmd"
"github.com/Dreamacro/clash/listener/tun/device"
@ -12,14 +12,14 @@ func GetAutoDetectInterface() (string, error) {
return cmd.ExecCmd("bash -c netstat -rnf inet | grep 'default' | awk -F ' ' 'NR==1{print $6}' | xargs echo -n")
}
func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, autoRoute bool) error {
func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute bool) error {
interfaceName := dev.Name()
if addr.IP.To4() == nil {
if !addr.Addr().Is4() {
return fmt.Errorf("supported ipv4 only")
}
ip := addr.IP.String()
netmask := IPv4MaskString(addr.Mask)
ip := addr.Addr()
netmask := IPv4MaskString(addr.Bits())
cmdStr := fmt.Sprintf("ifconfig %s inet %s netmask %s %s", interfaceName, ip, netmask, ip)
_, err := cmd.ExecCmd(cmdStr)
@ -27,10 +27,10 @@ func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, au
return err
}
_, err = cmd.ExecCmd(fmt.Sprintf("ipconfig set %s automatic-v6", interfaceName))
if err != nil {
return err
}
// _, err = cmd.ExecCmd(fmt.Sprintf("ipconfig set %s automatic-v6", interfaceName))
// if err != nil {
// return err
// }
if autoRoute {
err = configInterfaceRouting(interfaceName, addr)
@ -38,7 +38,7 @@ func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, au
return err
}
func configInterfaceRouting(interfaceName string, addr *net.IPNet) error {
func configInterfaceRouting(interfaceName string, addr netip.Prefix) error {
routes := append(ROUTES, addr.String())
for _, route := range routes {
@ -47,7 +47,8 @@ func configInterfaceRouting(interfaceName string, addr *net.IPNet) error {
}
}
return execRouterCmd("add", "-inet6", "2000::/3", interfaceName)
// return execRouterCmd("add", "-inet6", "2000::/3", interfaceName)
return nil
}
func execRouterCmd(action, inet, route string, interfaceName string) error {

View File

@ -2,7 +2,7 @@ package commons
import (
"fmt"
"net"
"net/netip"
"github.com/Dreamacro/clash/common/cmd"
"github.com/Dreamacro/clash/listener/tun/device"
@ -12,7 +12,7 @@ func GetAutoDetectInterface() (string, error) {
return cmd.ExecCmd("bash -c ip route show | grep 'default via' | awk -F ' ' 'NR==1{print $5}' | xargs echo -n")
}
func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, autoRoute bool) error {
func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute bool) error {
interfaceName := dev.Name()
_, err := cmd.ExecCmd(fmt.Sprintf("ip addr add %s dev %s", addr.String(), interfaceName))
if err != nil {
@ -30,9 +30,9 @@ func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, au
return err
}
func configInterfaceRouting(interfaceName string, addr *net.IPNet) error {
func configInterfaceRouting(interfaceName string, addr netip.Prefix) error {
for _, route := range ROUTES {
if err := execRouterCmd("add", route, interfaceName, addr.IP.String()); err != nil {
if err := execRouterCmd("add", route, interfaceName, addr.Addr().String()); err != nil {
return err
}
}

View File

@ -4,7 +4,7 @@ package commons
import (
"fmt"
"net"
"net/netip"
"runtime"
"github.com/Dreamacro/clash/listener/tun/device"
@ -14,6 +14,6 @@ func GetAutoDetectInterface() (string, error) {
return "", fmt.Errorf("can not auto detect interface-name on this OS: %s, you must be detecting interface-name by manual", runtime.GOOS)
}
func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, autoRoute bool) error {
func ConfigInterfaceAddress(device.Device, netip.Prefix, int, bool) error {
return fmt.Errorf("unsupported on this OS: %s", runtime.GOOS)
}

View File

@ -1,11 +1,9 @@
package commons
import (
"bytes"
"errors"
"fmt"
"net"
"sort"
"net/netip"
"time"
"github.com/Dreamacro/clash/listener/tun/device"
@ -25,7 +23,7 @@ func GetAutoDetectInterface() (string, error) {
return getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET6))
}
func ConfigInterfaceAddress(dev device.Device, addr *net.IPNet, forceMTU int, autoRoute bool) error {
func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int, autoRoute bool) error {
retryOnFailure := StartedAtBoot()
tryTimes := 0
startOver:
@ -38,41 +36,39 @@ startOver:
tryTimes++
luid := winipcfg.LUID(dev.(*tun.TUN).LUID())
if guid, err1 := luid.GUID(); err1 == nil {
log.Infoln("[wintun]: tun adapter GUID: %s", guid.String())
}
tunAddress := ParseIPCidr(addr.String())
addresses := []net.IPNet{tunAddress.IPNet()}
addresses := []netip.Prefix{addr}
family := winipcfg.AddressFamily(windows.AF_INET)
familyV6 := winipcfg.AddressFamily(windows.AF_INET6)
currentFamily := winipcfg.AddressFamily(windows.AF_INET6)
if addr.IP.To4() != nil {
if addr.Addr().Is4() {
currentFamily = winipcfg.AddressFamily(windows.AF_INET)
}
err = luid.FlushIPAddresses(familyV6)
err = luid.FlushRoutes(windows.AF_INET6)
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
goto startOver
} else if err != nil {
return err
}
err = luid.FlushDNS(family)
err = luid.FlushIPAddresses(windows.AF_INET6)
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
goto startOver
} else if err != nil {
return err
}
err = luid.FlushDNS(familyV6)
err = luid.FlushDNS(windows.AF_INET6)
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
goto startOver
} else if err != nil {
return err
}
err = luid.FlushRoutes(familyV6)
err = luid.FlushDNS(windows.AF_INET)
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
goto startOver
} else if err != nil {
@ -83,64 +79,39 @@ startOver:
foundDefault6 := false
if autoRoute {
allowedIPs := []*IPCidr{}
routeArr := append(ROUTES, "224.0.0.0/4", "255.255.255.255/32")
var allowedIPs []netip.Prefix
routeArr := ROUTES
for _, route := range routeArr {
allowedIPs = append(allowedIPs, ParseIPCidr(route))
allowedIPs = append(allowedIPs, netip.MustParsePrefix(route))
}
estimatedRouteCount := len(allowedIPs)
routes := make([]winipcfg.RouteData, 0, estimatedRouteCount)
var haveV4Address, haveV6Address bool = true, false
routes := make(map[winipcfg.RouteData]bool, estimatedRouteCount)
for _, allowedip := range allowedIPs {
allowedip.MaskSelf()
if (allowedip.Bits() == 32 && !haveV4Address) || (allowedip.Bits() == 128 && !haveV6Address) {
continue
}
route := winipcfg.RouteData{
Destination: allowedip.IPNet(),
Destination: allowedip.Masked(),
Metric: 0,
}
if allowedip.Bits() == 32 {
if allowedip.Cidr == 0 {
if allowedip.Addr().Is4() {
if allowedip.Bits() == 0 {
foundDefault4 = true
}
route.NextHop = net.IPv4zero
} else if allowedip.Bits() == 128 {
if allowedip.Cidr == 0 {
route.NextHop = netip.IPv4Unspecified()
} else if allowedip.Addr().Is6() {
if allowedip.Bits() == 0 {
foundDefault6 = true
}
route.NextHop = net.IPv6zero
route.NextHop = netip.IPv6Unspecified()
}
routes = append(routes, route)
routes[route] = true
}
deduplicatedRoutes := make([]*winipcfg.RouteData, 0, len(routes))
sort.Slice(routes, func(i, j int) bool {
if routes[i].Metric != routes[j].Metric {
return routes[i].Metric < routes[j].Metric
}
if c := bytes.Compare(routes[i].NextHop, routes[j].NextHop); c != 0 {
return c < 0
}
if c := bytes.Compare(routes[i].Destination.IP, routes[j].Destination.IP); c != 0 {
return c < 0
}
if c := bytes.Compare(routes[i].Destination.Mask, routes[j].Destination.Mask); c != 0 {
return c < 0
}
return false
})
for i := 0; i < len(routes); i++ {
if i > 0 && routes[i].Metric == routes[i-1].Metric &&
bytes.Equal(routes[i].NextHop, routes[i-1].NextHop) &&
bytes.Equal(routes[i].Destination.IP, routes[i-1].Destination.IP) &&
bytes.Equal(routes[i].Destination.Mask, routes[i-1].Destination.Mask) {
continue
}
deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
for route := range routes {
r := route
deduplicatedRoutes = append(deduplicatedRoutes, &r)
}
err = luid.SetRoutesForFamily(family, deduplicatedRoutes)
@ -167,6 +138,7 @@ startOver:
if err != nil {
return err
}
ipif.ForwardingEnabled = true
ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
ipif.DadTransmits = 0
ipif.ManagedAddressConfigurationSupported = false
@ -208,28 +180,24 @@ startOver:
return fmt.Errorf("unable to set v6 metric and MTU: %w", err)
}
err = luid.SetDNS(family, []net.IP{net.ParseIP("198.18.0.2")}, nil)
dnsAdds := []netip.Addr{netip.MustParseAddr("198.18.0.2")}
err = luid.SetDNS(family, dnsAdds, nil)
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
goto startOver
} else if err != nil {
return fmt.Errorf("unable to set DNS %s %s: %w", "198.18.0.2", "nil", err)
}
return nil
}
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) {
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []netip.Prefix) {
if len(addresses) == 0 {
return
}
addrToStr := func(ip *net.IP) string {
if ip4 := ip.To4(); ip4 != nil {
return string(ip4)
}
return string(*ip)
}
addrHash := make(map[string]bool, len(addresses))
addrHash := make(map[netip.Addr]bool, len(addresses))
for i := range addresses {
addrHash[addrToStr(&addresses[i].IP)] = true
addrHash[addresses[i].Addr()] = true
}
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
if err != nil {
@ -240,11 +208,10 @@ func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, add
continue
}
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
ip := address.Address.IP()
if addrHash[addrToStr(&ip)] {
ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
log.Infoln("Cleaning up stale address %s from interface %s", ipnet.String(), iface.FriendlyName())
iface.LUID.DeleteIPAddress(ipnet)
if ip, _ := netip.AddrFromSlice(address.Address.IP()); addrHash[ip] {
prefix := netip.PrefixFrom(ip, int(address.OnLinkPrefixLength))
log.Infoln("Cleaning up stale address %s from interface %s", prefix.String(), iface.FriendlyName())
iface.LUID.DeleteIPAddress(prefix)
}
}
}
@ -255,27 +222,25 @@ func getAutoDetectInterfaceByFamily(family winipcfg.AddressFamily) (string, erro
if err != nil {
return "", fmt.Errorf("get ethernet interface failure. %w", err)
}
var destination netip.Prefix
if family == windows.AF_INET {
destination = netip.PrefixFrom(netip.IPv4Unspecified(), 0)
} else {
destination = netip.PrefixFrom(netip.IPv6Unspecified(), 0)
}
for _, iface := range interfaces {
if iface.OperStatus != winipcfg.IfOperStatusUp {
continue
}
ifname := iface.FriendlyName()
if ifname == "Clash" {
continue
}
for gatewayAddress := iface.FirstGatewayAddress; gatewayAddress != nil; gatewayAddress = gatewayAddress.Next {
nextHop := gatewayAddress.Address.IP()
nextHop, _ := netip.AddrFromSlice(gatewayAddress.Address.IP())
var ipnet net.IPNet
if family == windows.AF_INET {
ipnet = net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}
} else {
ipnet = net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}
}
if _, err = iface.LUID.Route(ipnet, nextHop); err == nil {
if _, err = iface.LUID.Route(destination, nextHop); err == nil {
return ifname, nil
}
}

View File

@ -3,6 +3,7 @@ package gvisor
import (
"encoding/binary"
"net"
"net/netip"
"time"
"github.com/Dreamacro/clash/adapter/inbound"
@ -17,7 +18,7 @@ import (
var _ adapter.Handler = (*GVHandler)(nil)
type GVHandler struct {
DNSAdds []net.IP
DNSAdds []netip.AddrPort
TCPIn chan<- C.ConnContext
UDPIn chan<- *inbound.PacketAdapter
@ -32,9 +33,12 @@ func (gh *GVHandler) HandleTCPConn(tunConn adapter.TCPConn) {
Zone: "",
}
if D.ShouldHijackDns(gh.DNSAdds, rAddr.IP, rAddr.Port) {
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, id.LocalPort)
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
go func() {
log.Debugln("[TUN] hijack dns tcp: %s", rAddr.String())
log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String())
defer tunConn.Close()
@ -46,21 +50,21 @@ func (gh *GVHandler) HandleTCPConn(tunConn adapter.TCPConn) {
length := uint16(0)
if err := binary.Read(tunConn, binary.BigEndian, &length); err != nil {
return
break
}
if int(length) > len(buf) {
return
break
}
n, err := tunConn.Read(buf[:length])
if err != nil {
return
break
}
msg, err := D.RelayDnsPacket(buf[:n])
if err != nil {
return
break
}
_, _ = tunConn.Write(msg)
@ -82,6 +86,8 @@ func (gh *GVHandler) HandleUDPConn(tunConn adapter.UDPConn) {
Zone: "",
}
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, id.LocalPort)
target := socks5.ParseAddrToSocksAddr(rAddr)
go func() {
@ -91,12 +97,12 @@ func (gh *GVHandler) HandleUDPConn(tunConn adapter.UDPConn) {
n, addr, err := tunConn.ReadFrom(buf)
if err != nil {
pool.Put(buf)
return
break
}
payload := buf[:n]
if D.ShouldHijackDns(gh.DNSAdds, rAddr.IP, rAddr.Port) {
if D.ShouldHijackDns(gh.DNSAdds, addrPort) {
go func() {
defer pool.Put(buf)

View File

@ -4,6 +4,7 @@ import (
"encoding/binary"
"io"
"net"
"net/netip"
"strconv"
"time"
@ -35,9 +36,10 @@ func (s sysStack) Close() error {
return nil
}
var _, ipv4LoopBack, _ = net.ParseCIDR("127.0.0.0/8")
var ipv4LoopBack = netip.MustParsePrefix("127.0.0.0/8")
func New(device device.Device, dnsHijack []net.IP, portal net.IP, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
portal := tunAddress.Addr()
gateway := portal
stack, err := tun2socket.StartTun2Socket(device, gateway, portal)
@ -64,15 +66,18 @@ func New(device device.Device, dnsHijack []net.IP, portal net.IP, tcpIn chan<- C
lAddr := conn.LocalAddr().(*net.TCPAddr)
rAddr := conn.RemoteAddr().(*net.TCPAddr)
if ipv4LoopBack.Contains(rAddr.IP) {
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, uint16(rAddr.Port))
if ipv4LoopBack.Contains(addrIp) {
conn.Close()
continue
}
if D.ShouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) {
if D.ShouldHijackDns(dnsAddr, addrPort) {
go func() {
log.Debugln("[TUN] hijack dns tcp: %s", rAddr.String())
log.Debugln("[TUN] hijack dns tcp: %s", addrPort.String())
defer conn.Close()
@ -84,21 +89,21 @@ func New(device device.Device, dnsHijack []net.IP, portal net.IP, tcpIn chan<- C
length := uint16(0)
if err := binary.Read(conn, binary.BigEndian, &length); err != nil {
return
break
}
if int(length) > len(buf) {
return
break
}
n, err := conn.Read(buf[:length])
if err != nil {
return
break
}
msg, err := D.RelayDnsPacket(buf[:n])
if err != nil {
return
break
}
_, _ = conn.Write(msg)
@ -139,13 +144,16 @@ func New(device device.Device, dnsHijack []net.IP, portal net.IP, tcpIn chan<- C
lAddr := lRAddr.(*net.UDPAddr)
rAddr := rRAddr.(*net.UDPAddr)
if ipv4LoopBack.Contains(rAddr.IP) {
addrIp, _ := netip.AddrFromSlice(rAddr.IP)
addrPort := netip.AddrPortFrom(addrIp, uint16(rAddr.Port))
if ipv4LoopBack.Contains(addrIp) {
pool.Put(buf)
continue
}
if D.ShouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) {
if D.ShouldHijackDns(dnsAddr, addrPort) {
go func() {
defer pool.Put(buf)
@ -156,7 +164,7 @@ func New(device device.Device, dnsHijack []net.IP, portal net.IP, tcpIn chan<- C
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
log.Debugln("[TUN] hijack dns udp: %s", rAddr.String())
log.Debugln("[TUN] hijack dns udp: %s", addrPort.String())
}()
continue

View File

@ -2,7 +2,7 @@ package tun
import (
"fmt"
"net"
"net/netip"
"net/url"
"runtime"
"strings"
@ -28,7 +28,7 @@ func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
devName = generateDeviceName()
}
tunAddrIPNet := &net.IPNet{IP: net.IP{198, 18, 0, 1}, Mask: net.CIDRMask(16, 32)}
tunAddress := netip.MustParsePrefix("198.18.0.1/16")
autoRoute := tunConf.AutoRoute
stackType := tunConf.Stack
mtu := 9000
@ -71,7 +71,7 @@ func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
return nil, fmt.Errorf("can't attach endpoint to tun: %w", err)
}
tunStack, err = system.New(tunDevice, tunConf.DNSHijack, tunAddrIPNet.IP, tcpIn, udpIn)
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)
@ -81,7 +81,7 @@ func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
}
// setting address and routing
err = commons.ConfigInterfaceAddress(tunDevice, tunAddrIPNet, mtu, autoRoute)
err = commons.ConfigInterfaceAddress(tunDevice, tunAddress, mtu, autoRoute)
if err != nil {
_ = tunDevice.Close()
return nil, fmt.Errorf("setting interface address and routing failed: %w", err)
@ -89,7 +89,7 @@ func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
setAtLatest(stackType)
log.Infoln("TUN stack listening at: %s(%s), mtu: %d, auto route: %v, ip stack: %s", tunDevice.Name(), tunAddrIPNet.IP.String(), mtu, autoRoute, stackType)
log.Infoln("TUN stack listening at: %s(%s), mtu: %d, auto route: %v, ip stack: %s", tunDevice.Name(), tunAddress.Addr().String(), mtu, autoRoute, stackType)
return tunStack, nil
}