syscalls_darwin.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package water
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "math"
  7. "os"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "syscall"
  12. "unsafe"
  13. )
  14. const appleUTUNCtl = "com.apple.net.utun_control"
  15. /*
  16. * From ioctl.h:
  17. * #define IOCPARM_MASK 0x1fff // parameter length, at most 13 bits
  18. * ...
  19. * #define IOC_OUT 0x40000000 // copy out parameters
  20. * #define IOC_IN 0x80000000 // copy in parameters
  21. * #define IOC_INOUT (IOC_IN|IOC_OUT)
  22. * ...
  23. * #define _IOC(inout,group,num,len) \
  24. * (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
  25. * ...
  26. * #define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
  27. *
  28. * From kern_control.h:
  29. * #define CTLIOCGINFO _IOWR('N', 3, struct ctl_info) // get id from name
  30. *
  31. */
  32. const appleCTLIOCGINFO = (0x40000000 | 0x80000000) | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3
  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. * struct sockaddr_ctl {
  40. * u_char sc_len; // depends on size of bundle ID string
  41. * u_char sc_family; // AF_SYSTEM
  42. * u_int16_t ss_sysaddr; // AF_SYS_KERNCONTROL
  43. * u_int32_t sc_id; // Controller unique identifier
  44. * u_int32_t sc_unit; // Developer private unit number
  45. * u_int32_t sc_reserved[5];
  46. * };
  47. */
  48. type sockaddrCtl struct {
  49. scLen uint8
  50. scFamily uint8
  51. ssSysaddr uint16
  52. scID uint32
  53. scUnit uint32
  54. scReserved [5]uint32
  55. }
  56. var sockaddrCtlSize uintptr = 32
  57. func openDev(config Config) (ifce *Interface, err error) {
  58. if config.Driver == MacOSDriverTunTapOSX {
  59. return openDevTunTapOSX(config)
  60. }
  61. if config.Driver == MacOSDriverSystem {
  62. return openDevSystem(config)
  63. }
  64. return nil, errors.New("unrecognized driver")
  65. }
  66. // openDevSystem opens tun device on system
  67. func openDevSystem(config Config) (ifce *Interface, err error) {
  68. if config.DeviceType != TUN {
  69. return nil, errors.New("only tun is implemented for SystemDriver, use TunTapOSXDriver for tap")
  70. }
  71. ifIndex := -1
  72. if config.Name != "" {
  73. const utunPrefix = "utun"
  74. if !strings.HasPrefix(config.Name, utunPrefix) {
  75. return nil, fmt.Errorf("Interface name must be utun[0-9]+")
  76. }
  77. ifIndex, err = strconv.Atoi(config.Name[len(utunPrefix):])
  78. if err != nil || ifIndex < 0 || ifIndex > math.MaxUint32-1 {
  79. return nil, fmt.Errorf("Interface name must be utun[0-9]+")
  80. }
  81. }
  82. var fd int
  83. // Supposed to be socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), but ...
  84. //
  85. // In sys/socket.h:
  86. // #define PF_SYSTEM AF_SYSTEM
  87. //
  88. // In sys/sys_domain.h:
  89. // #define SYSPROTO_CONTROL 2 /* kernel control protocol */
  90. if fd, err = syscall.Socket(syscall.AF_SYSTEM, syscall.SOCK_DGRAM, 2); err != nil {
  91. return nil, fmt.Errorf("error in syscall.Socket: %v", err)
  92. }
  93. var ctlInfo = &struct {
  94. ctlID uint32
  95. ctlName [96]byte
  96. }{}
  97. copy(ctlInfo.ctlName[:], []byte(appleUTUNCtl))
  98. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(appleCTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo))); errno != 0 {
  99. err = errno
  100. return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
  101. }
  102. addrP := unsafe.Pointer(&sockaddrCtl{
  103. scLen: uint8(sockaddrCtlSize),
  104. scFamily: syscall.AF_SYSTEM,
  105. /* #define AF_SYS_CONTROL 2 */
  106. ssSysaddr: 2,
  107. scID: ctlInfo.ctlID,
  108. scUnit: uint32(ifIndex) + 1,
  109. })
  110. if _, _, errno := syscall.RawSyscall(syscall.SYS_CONNECT, uintptr(fd), uintptr(addrP), uintptr(sockaddrCtlSize)); errno != 0 {
  111. err = errno
  112. return nil, fmt.Errorf("error in syscall.RawSyscall(syscall.SYS_CONNECT, ...): %v", err)
  113. }
  114. var ifName struct {
  115. name [16]byte
  116. }
  117. ifNameSize := uintptr(16)
  118. if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd),
  119. 2, /* #define SYSPROTO_CONTROL 2 */
  120. 2, /* #define UTUN_OPT_IFNAME 2 */
  121. uintptr(unsafe.Pointer(&ifName)),
  122. uintptr(unsafe.Pointer(&ifNameSize)), 0); errno != 0 {
  123. err = errno
  124. return nil, fmt.Errorf("error in syscall.Syscall6(syscall.SYS_GETSOCKOPT, ...): %v", err)
  125. }
  126. if err = setNonBlock(fd); err != nil {
  127. return nil, fmt.Errorf("setting non-blocking error")
  128. }
  129. return &Interface{
  130. isTAP: false,
  131. name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
  132. ReadWriteCloser: &tunReadCloser{
  133. f: os.NewFile(uintptr(fd), string(ifName.name[:])),
  134. },
  135. }, nil
  136. }
  137. // openDevTunTapOSX opens tun / tap device, assuming tuntaposx is installed
  138. func openDevTunTapOSX(config Config) (ifce *Interface, err error) {
  139. var fd int
  140. var socketFD int
  141. if config.DeviceType == TAP && !strings.HasPrefix(config.Name, "tap") {
  142. return nil, errors.New("device name does not start with tap when creating a tap device")
  143. }
  144. if config.DeviceType == TUN && !strings.HasPrefix(config.Name, "tun") {
  145. return nil, errors.New("device name does not start with tun when creating a tun device")
  146. }
  147. if config.DeviceType != TAP && config.DeviceType != TUN {
  148. return nil, errors.New("unsupported DeviceType")
  149. }
  150. if len(config.Name) >= 15 {
  151. return nil, errors.New("device name is too long")
  152. }
  153. if fd, err = syscall.Open(
  154. "/dev/"+config.Name, os.O_RDWR|syscall.O_NONBLOCK, 0); err != nil {
  155. return nil, err
  156. }
  157. // Note that we are not setting NONBLOCK on the fd itself since it breaks tuntaposx
  158. // see https://sourceforge.net/p/tuntaposx/bugs/6/
  159. // create socket so we can do SIO ioctls, we are not using it afterwards
  160. if socketFD, err = syscall.Socket(syscall.AF_SYSTEM, syscall.SOCK_DGRAM, 2); err != nil {
  161. return nil, fmt.Errorf("error in syscall.Socket: %v", err)
  162. }
  163. var ifReq = &struct {
  164. ifName [16]byte
  165. ifruFlags int16
  166. pad [16]byte
  167. }{}
  168. copy(ifReq.ifName[:], []byte(config.Name))
  169. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(socketFD), uintptr(syscall.SIOCGIFFLAGS), uintptr(unsafe.Pointer(ifReq))); errno != 0 {
  170. err = errno
  171. return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
  172. }
  173. ifReq.ifruFlags |= syscall.IFF_RUNNING | syscall.IFF_UP
  174. if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(socketFD), uintptr(syscall.SIOCSIFFLAGS), uintptr(unsafe.Pointer(ifReq))); errno != 0 {
  175. err = errno
  176. return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
  177. }
  178. syscall.Close(socketFD)
  179. return &Interface{
  180. isTAP: config.DeviceType == TAP,
  181. ReadWriteCloser: os.NewFile(uintptr(fd), "tun"),
  182. name: config.Name,
  183. }, nil
  184. }
  185. // tunReadCloser is a hack to work around the first 4 bytes "packet
  186. // information" because there doesn't seem to be an IFF_NO_PI for darwin.
  187. type tunReadCloser struct {
  188. f io.ReadWriteCloser
  189. rMu sync.Mutex
  190. rBuf []byte
  191. wMu sync.Mutex
  192. wBuf []byte
  193. }
  194. var _ io.ReadWriteCloser = (*tunReadCloser)(nil)
  195. func (t *tunReadCloser) Read(to []byte) (int, error) {
  196. t.rMu.Lock()
  197. defer t.rMu.Unlock()
  198. if cap(t.rBuf) < len(to)+4 {
  199. t.rBuf = make([]byte, len(to)+4)
  200. }
  201. t.rBuf = t.rBuf[:len(to)+4]
  202. n, err := t.f.Read(t.rBuf)
  203. copy(to, t.rBuf[4:])
  204. return n - 4, err
  205. }
  206. func (t *tunReadCloser) Write(from []byte) (int, error) {
  207. if len(from) == 0 {
  208. return 0, syscall.EIO
  209. }
  210. t.wMu.Lock()
  211. defer t.wMu.Unlock()
  212. if cap(t.wBuf) < len(from)+4 {
  213. t.wBuf = make([]byte, len(from)+4)
  214. }
  215. t.wBuf = t.wBuf[:len(from)+4]
  216. // Determine the IP Family for the NULL L2 Header
  217. ipVer := from[0] >> 4
  218. if ipVer == 4 {
  219. t.wBuf[3] = syscall.AF_INET
  220. } else if ipVer == 6 {
  221. t.wBuf[3] = syscall.AF_INET6
  222. } else {
  223. return 0, errors.New("Unable to determine IP version from packet")
  224. }
  225. copy(t.wBuf[4:], from)
  226. n, err := t.f.Write(t.wBuf)
  227. return n - 4, err
  228. }
  229. func (t *tunReadCloser) Close() error {
  230. return t.f.Close()
  231. }