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 }