1/* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2020-2021 WireGuard LLC. All Rights Reserved. 4 */ 5 6package tun 7 8import ( 9 "bytes" 10 "errors" 11 "fmt" 12 "net" 13 "os" 14 "syscall" 15 "unsafe" 16 17 "golang.org/x/net/ipv6" 18 "golang.org/x/sys/unix" 19) 20 21 22// IOCTL numbers derived from <sys/net/tun/if_tun.h> (print them in C) 23const ( 24 _TUNSIFHEAD = 0x80047460 // _IOW('t', 96, int) 25 _TUNGIFNAME = 0x40207462 // _IOR('t', 98, struct ifreq) 26) 27 28// Iface status string max len 29const _IFSTATMAX = 800 30 31const SIZEOF_UINTPTR = 4 << (^uintptr(0) >> 32 & 1) 32 33// structure for iface requests with a pointer 34type ifreq_ptr struct { 35 Name [unix.IFNAMSIZ]byte 36 Data uintptr 37 Pad0 [16 - SIZEOF_UINTPTR]byte 38} 39 40// Structure for iface mtu get/set ioctls 41type ifreq_mtu struct { 42 Name [unix.IFNAMSIZ]byte 43 MTU uint32 44 Pad0 [12]byte 45} 46 47// Structure for interface status request ioctl 48type ifstat struct { 49 IfsName [unix.IFNAMSIZ]byte 50 Ascii [_IFSTATMAX]byte 51} 52 53type NativeTun struct { 54 name string 55 tunFile *os.File 56 events chan Event 57 errors chan error 58 routeSocket int 59} 60 61func (tun *NativeTun) routineRouteListener(tunIfindex int) { 62 var ( 63 statusUp bool 64 statusMTU int 65 ) 66 67 defer close(tun.events) 68 69 data := make([]byte, os.Getpagesize()) 70 for { 71 retry: 72 n, err := unix.Read(tun.routeSocket, data) 73 if err != nil { 74 if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR { 75 goto retry 76 } 77 tun.errors <- err 78 return 79 } 80 81 if n < 14 { 82 continue 83 } 84 85 if data[3 /* type */] != unix.RTM_IFINFO { 86 continue 87 } 88 ifindex := int(*(*uint16)(unsafe.Pointer(&data[4 /* ifindex */]))) 89 if ifindex != tunIfindex { 90 continue 91 } 92 93 iface, err := net.InterfaceByIndex(ifindex) 94 if err != nil { 95 tun.errors <- err 96 return 97 } 98 99 // Up / Down event 100 up := (iface.Flags & net.FlagUp) != 0 101 if up != statusUp && up { 102 tun.events <- EventUp 103 } 104 if up != statusUp && !up { 105 tun.events <- EventDown 106 } 107 statusUp = up 108 109 // MTU changes 110 if iface.MTU != statusMTU { 111 tun.events <- EventMTUUpdate 112 } 113 statusMTU = iface.MTU 114 } 115} 116 117func tunName(fd uintptr) (string, error) { 118 var ifr ifreq_ptr; 119 _, _, errno := unix.Syscall( 120 unix.SYS_IOCTL, 121 uintptr(fd), 122 uintptr(_TUNGIFNAME), 123 uintptr(unsafe.Pointer(&ifr)), 124 ) 125 if errno != 0 { 126 return "", errors.New("failed to get name of TUN device: " + errno.Error()) 127 } 128 129 name := ifr.Name[:] 130 if i := bytes.IndexByte(name, 0); i != -1 { 131 name = name[:i] 132 } 133 return string(name), nil 134} 135 136func tunDestroy(name string) error { 137 fd, err := unix.Socket( 138 unix.AF_INET, 139 unix.SOCK_DGRAM, 140 0, 141 ) 142 if err != nil { 143 return err 144 } 145 defer unix.Close(fd) 146 147 var ifr [unix.IFNAMSIZ]byte 148 copy(ifr[:], name) 149 _, _, errno := unix.Syscall( 150 unix.SYS_IOCTL, 151 uintptr(fd), 152 uintptr(unix.SIOCIFDESTROY), 153 uintptr(unsafe.Pointer(&ifr[0])), 154 ) 155 if errno != 0 { 156 return fmt.Errorf("failed to destroy interface %s: %s", name, errno.Error()) 157 } 158 159 return nil 160} 161 162func CreateTUN(name string, mtu int) (Device, error) { 163 if len(name) > unix.IFNAMSIZ-1 { 164 return nil, errors.New("interface name too long") 165 } 166 167 iface, _ := net.InterfaceByName(name) 168 if iface != nil { 169 return nil, fmt.Errorf("interface %s already exists", name) 170 } 171 172 tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0) 173 if err != nil { 174 return nil, err 175 } 176 177 tun := NativeTun{tunFile: tunFile} 178 var assignedName string 179 tun.operateOnFd(func(fd uintptr) { 180 assignedName, err = tunName(fd) 181 }) 182 if err != nil { 183 tunFile.Close() 184 return nil, err 185 } 186 187 // Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet 188 ifheadmode := 1 189 var errno syscall.Errno 190 tun.operateOnFd(func(fd uintptr) { 191 _, _, errno = unix.Syscall( 192 unix.SYS_IOCTL, 193 fd, 194 uintptr(_TUNSIFHEAD), 195 uintptr(unsafe.Pointer(&ifheadmode)), 196 ) 197 }) 198 if errno != 0 { 199 tunFile.Close() 200 tunDestroy(assignedName) 201 return nil, fmt.Errorf("unable to put into IFHEAD mode: %v", errno) 202 } 203 204 // Rename tun interface 205 206 confd, err := unix.Socket( 207 unix.AF_INET, 208 unix.SOCK_DGRAM, 209 0, 210 ) 211 if err != nil { 212 return nil, err 213 } 214 defer unix.Close(confd) 215 216 var newnp [unix.IFNAMSIZ]byte 217 copy(newnp[:], name) 218 219 var ifr ifreq_ptr 220 copy(ifr.Name[:], assignedName) 221 ifr.Data = uintptr(unsafe.Pointer(&newnp[0])) 222 223 _, _, errno = unix.Syscall( 224 unix.SYS_IOCTL, 225 uintptr(confd), 226 uintptr(unix.SIOCSIFNAME), 227 uintptr(unsafe.Pointer(&ifr)), 228 ) 229 if errno != 0 { 230 tunFile.Close() 231 tunDestroy(assignedName) 232 return nil, fmt.Errorf("failed to rename %s to %s: %v", assignedName, name, errno) 233 } 234 235 return CreateTUNFromFile(tunFile, mtu) 236} 237 238func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { 239 tun := &NativeTun{ 240 tunFile: file, 241 events: make(chan Event, 10), 242 errors: make(chan error, 1), 243 } 244 245 name, err := tun.Name() 246 if err != nil { 247 tun.tunFile.Close() 248 return nil, err 249 } 250 251 tunIfindex, err := func() (int, error) { 252 iface, err := net.InterfaceByName(name) 253 if err != nil { 254 return -1, err 255 } 256 return iface.Index, nil 257 }() 258 if err != nil { 259 tun.tunFile.Close() 260 return nil, err 261 } 262 263 tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) 264 if err != nil { 265 tun.tunFile.Close() 266 return nil, err 267 } 268 269 go tun.routineRouteListener(tunIfindex) 270 271 err = tun.setMTU(mtu) 272 if err != nil { 273 tun.Close() 274 return nil, err 275 } 276 277 return tun, nil 278} 279 280func (tun *NativeTun) Name() (string, error) { 281 var name string 282 var err error 283 tun.operateOnFd(func(fd uintptr) { 284 name, err = tunName(fd) 285 }) 286 if err != nil { 287 return "", err 288 } 289 290 tun.name = name 291 return name, nil 292} 293 294func (tun *NativeTun) File() *os.File { 295 return tun.tunFile 296} 297 298func (tun *NativeTun) Events() chan Event { 299 return tun.events 300} 301 302func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { 303 select { 304 case err := <-tun.errors: 305 return 0, err 306 default: 307 buff := buff[offset-4:] 308 n, err := tun.tunFile.Read(buff[:]) 309 if n < 4 { 310 return 0, err 311 } 312 return n - 4, err 313 } 314} 315 316func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { 317 // reserve space for header 318 buff = buff[offset-4:] 319 320 // add packet information header 321 buff[0] = 0x00 322 buff[1] = 0x00 323 buff[2] = 0x00 324 if buff[4]>>4 == ipv6.Version { 325 buff[3] = unix.AF_INET6 326 } else { 327 buff[3] = unix.AF_INET 328 } 329 330 return tun.tunFile.Write(buff) 331} 332 333func (tun *NativeTun) Flush() error { 334 // TODO: can flushing be implemented by buffering and using sendmmsg? 335 return nil 336} 337 338func (tun *NativeTun) Close() error { 339 var err3 error 340 err1 := tun.tunFile.Close() 341 err2 := tunDestroy(tun.name) 342 if tun.routeSocket != -1 { 343 unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) 344 err3 = unix.Close(tun.routeSocket) 345 tun.routeSocket = -1 346 } else if tun.events != nil { 347 close(tun.events) 348 } 349 if err1 != nil { 350 return err1 351 } 352 if err2 != nil { 353 return err2 354 } 355 return err3 356} 357 358func (tun *NativeTun) setMTU(n int) error { 359 fd, err := unix.Socket( 360 unix.AF_INET, 361 unix.SOCK_DGRAM, 362 0, 363 ) 364 if err != nil { 365 return err 366 } 367 defer unix.Close(fd) 368 369 var ifr ifreq_mtu 370 copy(ifr.Name[:], tun.name) 371 ifr.MTU = uint32(n) 372 373 _, _, errno := unix.Syscall( 374 unix.SYS_IOCTL, 375 uintptr(fd), 376 uintptr(unix.SIOCSIFMTU), 377 uintptr(unsafe.Pointer(&ifr)), 378 ) 379 if errno != 0 { 380 return fmt.Errorf("failed to set MTU on %s", tun.name) 381 } 382 383 return nil 384} 385 386func (tun *NativeTun) MTU() (int, error) { 387 fd, err := unix.Socket( 388 unix.AF_INET, 389 unix.SOCK_DGRAM, 390 0, 391 ) 392 if err != nil { 393 return 0, err 394 } 395 defer unix.Close(fd) 396 397 var ifr ifreq_mtu 398 copy(ifr.Name[:], tun.name) 399 400 _, _, errno := unix.Syscall( 401 unix.SYS_IOCTL, 402 uintptr(fd), 403 uintptr(unix.SIOCGIFMTU), 404 uintptr(unsafe.Pointer(&ifr)), 405 ) 406 if errno != 0 { 407 return 0, fmt.Errorf("failed to get MTU on %s", tun.name) 408 } 409 410 return int(*(*int32)(unsafe.Pointer(&ifr.MTU))), nil 411} 412