github.com/clmul/water@v0.0.3-0.20221017135504-100d910a03ab/syscalls_darwin.go (about) 1 package water 2 3 import ( 4 "unsafe" 5 6 "golang.org/x/sys/unix" 7 ) 8 9 type Config struct{} 10 11 const appleUTUNCtl = "com.apple.net.utun_control" 12 13 /* 14 * From ioctl.h: 15 * #define IOCPARM_MASK 0x1fff // parameter length, at most 13 bits 16 * ... 17 * #define IOC_OUT 0x40000000 // copy out parameters 18 * #define IOC_IN 0x80000000 // copy in parameters 19 * #define IOC_INOUT (IOC_IN|IOC_OUT) 20 * ... 21 * #define _IOC(inout,group,num,len) \ 22 * (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num)) 23 * ... 24 * #define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) 25 * 26 * From kern_control.h: 27 * #define CTLIOCGINFO _IOWR('N', 3, struct ctl_info) // get id from name 28 * 29 */ 30 31 const appleCTLIOCGINFO = (0x40000000 | 0x80000000) | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3 32 33 /* 34 * #define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t)) 35 * #define TUNSIFMODE _IOW('t', 94, int) 36 */ 37 const appleTUNSIFMODE = (0x80000000) | ((4 & 0x1fff) << 16) | uint32(byte('t'))<<8 | 94 38 39 /* 40 * struct sockaddr_ctl { 41 * u_char sc_len; // depends on size of bundle ID string 42 * u_char sc_family; // AF_SYSTEM 43 * u_int16_t ss_sysaddr; // AF_SYS_KERNCONTROL 44 * u_int32_t sc_id; // Controller unique identifier 45 * u_int32_t sc_unit; // Developer private unit number 46 * u_int32_t sc_reserved[5]; 47 * }; 48 */ 49 type sockaddrCtl struct { 50 scLen uint8 51 scFamily uint8 52 ssSysaddr uint16 53 scID uint32 54 scUnit uint32 55 scReserved [5]uint32 56 } 57 58 var sockaddrCtlSize uintptr = 32 59 60 func open(Config) (int, string, error) { 61 // Supposed to be socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), but ... 62 // 63 // In sys/socket.h: 64 // #define PF_SYSTEM AF_SYSTEM 65 // 66 // In sys/sys_domain.h: 67 // #define SYSPROTO_CONTROL 2 /* kernel control protocol */ 68 fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2) 69 if err != nil { 70 return 0, "", err 71 } 72 73 var ctlInfo = &struct { 74 ctlID uint32 75 ctlName [96]byte 76 }{} 77 copy(ctlInfo.ctlName[:], []byte(appleUTUNCtl)) 78 79 _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(appleCTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo))) 80 if errno != 0 { 81 return 0, "", errno 82 } 83 84 addrP := unsafe.Pointer(&sockaddrCtl{ 85 scLen: uint8(sockaddrCtlSize), 86 scFamily: unix.AF_SYSTEM, 87 88 /* #define AF_SYS_CONTROL 2 */ 89 ssSysaddr: 2, 90 91 scID: ctlInfo.ctlID, 92 scUnit: 0, 93 }) 94 _, _, errno = unix.Syscall(unix.SYS_CONNECT, uintptr(fd), uintptr(addrP), uintptr(sockaddrCtlSize)) 95 if errno != 0 { 96 return 0, "", errno 97 } 98 99 var ifName [16]byte 100 ifNameSize := uintptr(16) 101 _, _, errno = unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), 102 2, /* #define SYSPROTO_CONTROL 2 */ 103 2, /* #define UTUN_OPT_IFNAME 2 */ 104 uintptr(unsafe.Pointer(&ifName)), 105 uintptr(unsafe.Pointer(&ifNameSize)), 0) 106 if errno != 0 { 107 return 0, "", errno 108 } 109 110 name := string(ifName[:ifNameSize-1]) 111 return fd, name, nil 112 } 113 114 // this is a hack to work around the first 4 bytes "packet information" 115 // because there doesn't seem to be an IFF_NO_PI for darwin. 116 func (ifce *Interface) Read(buffer []byte) (int, error) { 117 n, err := ifce.File.Read(buffer) 118 if err != nil { 119 return 0, err 120 } 121 copy(buffer, buffer[4:]) 122 return n - 4, nil 123 } 124 125 func (ifce *Interface) Write(buffer []byte) (int, error) { 126 // Determine the IP Family for the NULL L2 Header 127 buffer = buffer[:len(buffer)+4] 128 copy(buffer[4:], buffer) 129 ipVer := buffer[0] >> 4 130 switch ipVer { 131 case 4: 132 buffer[3] = unix.AF_INET 133 case 6: 134 buffer[3] = unix.AF_INET6 135 default: 136 panic("unable to determine IP version from packet") 137 } 138 139 buffer[0] = 0 140 buffer[1] = 0 141 buffer[2] = 0 142 143 n, err := ifce.File.Write(buffer) 144 return n - 4, err 145 }