TUN(4)

🌸 NAME 🌸

okay bestie, welcome to tun(4) β€” this is the tunnel software network interface page from the Kernel Interfaces Manual, and honestly? she's iconic. let's get into it πŸ’…


✨ SYNOPSIS ✨

device tuntap

that's it. that's the whole vibe. πŸŽ€


πŸ¦‹ DESCRIPTION πŸ¦‹

okay so the tun interface is a software loopback mechanism β€” and the cutest way to describe it is that she's basically the network-interface version of pty(4). like, tun does for network interfaces what the pty(4) driver does for terminals. no cap, that's the whole analogy. 🫢

the tun driver, same as pty(4), gives you two interfaces at once:

  • an interface just like the thing it's simulating (a network interface, in tun's case β€” for pty(4) it'd be a terminal), and
  • a character-special device "control" interface.

a client program moves IP packets (by default) to or from the tun "control" interface. and if you want the same energy at the Ethernet layer, that's tap(4) β€” a client transfers Ethernet frames to or from a tap(4) "control" interface. sibling energy fr fr. 🌈

the network interfaces get named "tun0", "tun1", etc. β€” one for every control device that's been opened. these network interfaces persist until the if_tuntap.ko module is unloaded, or until you remove them with ifconfig(8). they're not going anywhere on their own, periodt.

tun devices are created using interface cloning, which you do with the ifconfig tunN create command. and this? this is the preferred method of creating tun devices. the same method also lets you remove interfaces β€” for that you use ifconfig tunN destroy. slay. πŸ’–

if the sysctl(8) variable net.link.tun.devfs_cloning is non-zero, the tun interface permits opens on the special control device /dev/tun. when that device gets opened, tun will hand you a handle for the lowest unused tun device (use devname(3) to figure out which one you actually got πŸ‘€).

⚠️ heads up bestie: disabling the legacy devfs cloning functionality may break existing applications which use tun, like ppp(8) and ssh(1). that's exactly why it defaults to being enabled until further notice. don't come for me, I'm just the messenger 😭

control devices (once they've been successfully opened) persist until if_tuntap.ko is unloaded β€” same way the network interfaces persist (see above ⬆️).

each interface supports the usual network-interface ioctl(2)s, like SIOCAIFADDR, so you can use it with ifconfig(8) like literally any other interface. at boot time they're POINTOPOINT interfaces, but that can be changed β€” see the description of the control device below. when the system chooses to transmit a packet on the network interface, that packet can be read from the control device (it shows up as "input" over there), and writing a packet to the control device generates an input packet on the network interface, as if the (non-existent) hardware had just received it. fake it till you make it, the hardware version. πŸ‘‘

the tunnel device (/dev/tunN) is exclusive-open β€” it cannot be opened if it's already open. a read(2) call will return an error (EHOSTDOWN) if the interface is not "ready", and "ready" means the control device is open and the interface's address has been set. both. no half measures. βœ‹

once the interface is ready, read(2) will return a packet if one's available; if not, it'll either block until one shows up or return EWOULDBLOCK, depending on whether non-blocking I/O has been enabled. and if the packet is longer than the buffer you passed to read(2) allows for, the extra data gets silently dropped. it's giving "oops, anyway" πŸ’€

if the TUNSLMODE ioctl has been set, packets read from the control device will be prepended with the destination address as presented to the network interface output routine, tunoutput(). that destination address is in struct sockaddr format, and the actual length of the prepended address lives in the member sa_len. if the TUNSIFHEAD ioctl has been set instead, packets get prepended with a four byte address family in network byte order. TUNSLMODE and TUNSIFHEAD are mutually exclusive β€” pick a lane bestie. in any case, the packet data follows immediately.

a write(2) call passes a packet in to be "received" on the pseudo-interface. if the TUNSIFHEAD ioctl has been set, the address family must be prepended; otherwise the packet is assumed to be of type AF_INET. each write(2) call supplies exactly one packet, and the packet length is taken from the amount of data provided to write(2) (minus any supplied address family). writes will not block. if the packet can't be accepted for a transient reason (e.g., no buffer space available), it is silently dropped; if the reason is not transient (e.g., packet too large), an error is returned. transient problems get ghosted, permanent ones get told. πŸ™ˆ


πŸŽ€ the ioctl(2) calls πŸŽ€

the following ioctl(2) calls are supported (defined in <net/if_tun.h>):

  • TUNSDEBUG β€” the argument should be a pointer to an int; this sets the internal debugging variable to that value. what, if anything, this variable controls is not documented here β€” go read the source code, iykyk πŸ“–
  • TUNGDEBUG β€” the argument should be a pointer to an int; this stores the internal debugging variable's value into it.
  • TUNSIFINFO β€” the argument should be a pointer to an struct tuninfo, and it lets you set the MTU and the baudrate of the tunnel device. the type must be the same as returned by TUNGIFINFO, or set to IFT_PPP β€” otherwise the ioctl(2) call will fail. the struct tuninfo is declared in <net/if_tun.h>.
πŸ”’ the use of this ioctl is restricted to the super-user. root only, sorry bestie.
  • TUNGIFINFO β€” the argument should be a pointer to an struct tuninfo, and the current MTU, type, and baudrate will be stored there. πŸ’Ύ
  • TUNSIFMODE β€” the argument should be a pointer to an int; its value must be either IFF_POINTOPOINT or IFF_BROADCAST, and it should have IFF_MULTICAST OR'd into the value if multicast support is required. the type of the corresponding "tunN" interface is set to the supplied type. if the value is outside the above range, an EINVAL error is returned. the interface must be down at the time β€” if it's up, an EBUSY error is returned. sit down before you change your type, that's the rule. πŸ’…
  • TUNSLMODE β€” the argument should be a pointer to an int; a non-zero value turns off "multi-af" mode and turns on "link-layer" mode, which makes packets read from the tunnel device get prepended with the network destination address (see above).
  • TUNSIFPID β€” will set the pid owning the tunnel device to the current process's pid. it's yours now. 🫢
  • TUNSIFHEAD β€” the argument should be a pointer to an int; a non-zero value turns off "link-layer" mode and enables "multi-af" mode, where every packet is preceded with a four byte address family.
  • TUNGIFHEAD β€” the argument should be a pointer to an int; the ioctl sets the value to one if the device is in "multi-af" mode, and zero otherwise.
  • FIONBIO β€” turn non-blocking I/O for reads off or on, according as the argument int's value is or is not zero. (writes are always non-blocking, no matter what. ✨)
  • FIOASYNC β€” turn asynchronous I/O for reads off or on β€” that's generation of SIGIO when data is available to be read β€” according as the argument int's value is or is not zero.
  • FIONREAD β€” if any packets are queued to be read, store the size of the first one into the argument int; otherwise, store zero.
  • TIOCSPGRP β€” set the process group to receive SIGIO signals, when asynchronous I/O is enabled, to the argument int value.
  • TIOCGPGRP β€” retrieve the process group value for SIGIO signals into the argument int value.

the control device also supports select(2) for read. selecting for write is pointless and always succeeds, since writes are always non-blocking β€” literally a free win, do nothing with that information. 😌

on the last close of the data device, by default, the interface is brought down (as if with ifconfig tunN down). all queued packets are thrown away. and if the interface is up when the data device is not open, output packets are always thrown away rather than letting them pile up. the queue gets cleared, no hoarding allowed. πŸ—‘οΈβœ¨


πŸ”₯ SEE ALSO πŸ”₯

ioctl(2), read(2), select(2), write(2), devname(3), inet(4), intro(4), pty(4), tap(4), ifconfig(8)


πŸ‘‘ AUTHORS πŸ‘‘

this manual page was originally obtained from NetBSD. 🌸


and that's the whole page bestie!! this lil masterpiece comes from the Debian crew and it's dated April 29, 2019 β€” so yes, she's a classic, she's timeless, she ate and left no crumbs. mwah. πŸ’–πŸŽ€πŸ¦‹πŸ’…

πŸ“¦ where this page comes from