github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/netlink/route_darwin.go (about)

     1  package netlink
     2  
     3  import (
     4  	"fmt"
     5  	"log/slog"
     6  	"net"
     7  	"net/netip"
     8  	"os"
     9  	"syscall"
    10  	"unsafe"
    11  
    12  	"github.com/Asutorufa/yuhaiin/pkg/log"
    13  	"golang.org/x/net/route"
    14  	"golang.org/x/sys/unix"
    15  )
    16  
    17  const (
    18  	SIOCAIFADDR_IN6       = 2155899162 // netinet6/in6_var.h
    19  	IN6_IFF_NODAD         = 0x0020     // netinet6/in6_var.h
    20  	IN6_IFF_SECURED       = 0x0400     // netinet6/in6_var.h
    21  	ND6_INFINITE_LIFETIME = 0xFFFFFFFF // netinet6/nd6.h
    22  )
    23  
    24  type ifAliasReq struct {
    25  	Name    [unix.IFNAMSIZ]byte
    26  	Addr    unix.RawSockaddrInet4
    27  	Dstaddr unix.RawSockaddrInet4
    28  	Mask    unix.RawSockaddrInet4
    29  }
    30  
    31  type ifAliasReq6 struct {
    32  	Name     [16]byte
    33  	Addr     unix.RawSockaddrInet6
    34  	Dstaddr  unix.RawSockaddrInet6
    35  	Mask     unix.RawSockaddrInet6
    36  	Flags    uint32
    37  	Lifetime addrLifetime6
    38  }
    39  
    40  type addrLifetime6 struct {
    41  	Expire    float64
    42  	Preferred float64
    43  	Vltime    uint32
    44  	Pltime    uint32
    45  }
    46  
    47  func Route(options *Options) error {
    48  	var iface string
    49  
    50  	if options.Interface.Scheme == "tun" {
    51  		iface = options.Interface.Name
    52  	} else {
    53  		return nil
    54  		// name, err := unix.GetsockoptString(
    55  		// 	int(options.Interface.Fd),
    56  		// 	2, /* #define SYSPROTO_CONTROL 2 */
    57  		// 	2, /* #define UTUN_OPT_IFNAME 2 */
    58  		// )
    59  		// if err != nil {
    60  		// 	return fmt.Errorf("GetSockoptString: %w", err)
    61  		// }
    62  		// iface = name
    63  	}
    64  
    65  	if iface == "" {
    66  		return fmt.Errorf("empty interface name")
    67  	}
    68  
    69  	if err := setMtu(iface, options.MTU); err != nil {
    70  		return err
    71  	}
    72  
    73  	for _, address := range append(options.Inet4Address, options.Inet6Address...) {
    74  		if err := setAddress(iface, address); err != nil {
    75  			return err
    76  		}
    77  	}
    78  
    79  	var err error
    80  	for _, v := range options.Routes {
    81  		if v.Addr().Is4() && options.V4Address().IsValid() {
    82  			err = addRoute(v, options.V4Address().Addr())
    83  		} else if options.V6Address().IsValid() {
    84  			err = addRoute(v, options.V6Address().Addr())
    85  		}
    86  		if err != nil {
    87  			log.Error("add route failed", slog.Any("err", err))
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func useSocket(domain, typ, proto int, block func(socketFd int) error) error {
    95  	socketFd, err := unix.Socket(domain, typ, proto)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	defer unix.Close(socketFd)
   100  	return block(socketFd)
   101  }
   102  
   103  func addRoute(destination netip.Prefix, gateway netip.Addr) error {
   104  	routeMessage := route.RouteMessage{
   105  		Type:    unix.RTM_ADD,
   106  		Flags:   unix.RTF_UP | unix.RTF_STATIC | unix.RTF_GATEWAY,
   107  		Version: unix.RTM_VERSION,
   108  		Seq:     1,
   109  	}
   110  	if gateway.Is4() {
   111  		routeMessage.Addrs = []route.Addr{
   112  			syscall.RTAX_DST:     &route.Inet4Addr{IP: destination.Addr().As4()},
   113  			syscall.RTAX_NETMASK: &route.Inet4Addr{IP: netip.MustParseAddr(net.IP(net.CIDRMask(destination.Bits(), 32)).String()).As4()},
   114  			syscall.RTAX_GATEWAY: &route.Inet4Addr{IP: gateway.As4()},
   115  		}
   116  	} else {
   117  		routeMessage.Addrs = []route.Addr{
   118  			syscall.RTAX_DST:     &route.Inet6Addr{IP: destination.Addr().As16()},
   119  			syscall.RTAX_NETMASK: &route.Inet6Addr{IP: netip.MustParseAddr(net.IP(net.CIDRMask(destination.Bits(), 128)).String()).As16()},
   120  			syscall.RTAX_GATEWAY: &route.Inet6Addr{IP: gateway.As16()},
   121  		}
   122  	}
   123  	request, err := routeMessage.Marshal()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	return useSocket(unix.AF_ROUTE, unix.SOCK_RAW, 0, func(socketFd int) error {
   128  		_, err := unix.Write(socketFd, request)
   129  		return err
   130  	})
   131  }
   132  
   133  func setAddress(ifaceName string, address netip.Prefix) error {
   134  	var req, socketAddr uintptr
   135  	var afInt int
   136  
   137  	if address.Addr().Is4() {
   138  		ifReq := ifAliasReq{
   139  			Addr: unix.RawSockaddrInet4{
   140  				Len:    unix.SizeofSockaddrInet4,
   141  				Family: unix.AF_INET,
   142  				Addr:   address.Addr().As4(),
   143  			},
   144  			Dstaddr: unix.RawSockaddrInet4{
   145  				Len:    unix.SizeofSockaddrInet4,
   146  				Family: unix.AF_INET,
   147  				Addr:   address.Addr().As4(),
   148  			},
   149  			Mask: unix.RawSockaddrInet4{
   150  				Len:    unix.SizeofSockaddrInet4,
   151  				Family: unix.AF_INET,
   152  				Addr:   netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 32)).String()).As4(),
   153  			},
   154  		}
   155  		copy(ifReq.Name[:], ifaceName)
   156  
   157  		afInt = unix.AF_INET
   158  		req = uintptr(unsafe.Pointer(&ifReq))
   159  		socketAddr = uintptr(unix.SIOCAIFADDR)
   160  	} else {
   161  		ifReq6 := ifAliasReq6{
   162  			Addr: unix.RawSockaddrInet6{
   163  				Len:    unix.SizeofSockaddrInet6,
   164  				Family: unix.AF_INET6,
   165  				Addr:   address.Addr().As16(),
   166  			},
   167  			Mask: unix.RawSockaddrInet6{
   168  				Len:    unix.SizeofSockaddrInet6,
   169  				Family: unix.AF_INET6,
   170  				Addr:   netip.MustParseAddr(net.IP(net.CIDRMask(address.Bits(), 128)).String()).As16(),
   171  			},
   172  			Flags: IN6_IFF_NODAD | IN6_IFF_SECURED,
   173  			Lifetime: addrLifetime6{
   174  				Vltime: ND6_INFINITE_LIFETIME,
   175  				Pltime: ND6_INFINITE_LIFETIME,
   176  			},
   177  		}
   178  		if address.Bits() == 128 {
   179  			ifReq6.Dstaddr = unix.RawSockaddrInet6{
   180  				Len:    unix.SizeofSockaddrInet6,
   181  				Family: unix.AF_INET6,
   182  				Addr:   address.Addr().Next().As16(),
   183  			}
   184  		}
   185  		copy(ifReq6.Name[:], ifaceName)
   186  
   187  		req = uintptr(unsafe.Pointer(&ifReq6))
   188  		socketAddr = uintptr(SIOCAIFADDR_IN6)
   189  		afInt = unix.AF_INET6
   190  	}
   191  
   192  	return useSocket(afInt, unix.SOCK_DGRAM, 0, func(socketFd int) error {
   193  		if _, _, errno := unix.Syscall(
   194  			syscall.SYS_IOCTL,
   195  			uintptr(socketFd),
   196  			socketAddr,
   197  			req,
   198  		); errno != 0 {
   199  			return os.NewSyscallError("SIOCAIFADDR", errno)
   200  		}
   201  		return nil
   202  	})
   203  }
   204  
   205  func setMtu(ifaceName string, mtu int) error {
   206  	err := useSocket(unix.AF_INET, unix.SOCK_DGRAM, 0, func(socketFd int) error {
   207  		var ifr unix.IfreqMTU
   208  		copy(ifr.Name[:], ifaceName)
   209  		ifr.MTU = int32(mtu)
   210  		return unix.IoctlSetIfreqMTU(socketFd, &ifr)
   211  	})
   212  	if err != nil {
   213  		return os.NewSyscallError("IoctlSetIfreqMTU", err)
   214  	}
   215  
   216  	return nil
   217  }