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