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 β forpty(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 usetun, likeppp(8)andssh(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 anint; 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 anint; this stores the internal debugging variable's value into it.TUNSIFINFOβ the argument should be a pointer to anstruct tuninfo, and it lets you set the MTU and the baudrate of the tunnel device. the type must be the same as returned byTUNGIFINFO, or set toIFT_PPPβ otherwise theioctl(2)call will fail. thestruct tuninfois 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 anstruct tuninfo, and the current MTU, type, and baudrate will be stored there. πΎTUNSIFMODEβ the argument should be a pointer to anint; its value must be eitherIFF_POINTOPOINTorIFF_BROADCAST, and it should haveIFF_MULTICASTOR'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, anEINVALerror is returned. the interface must be down at the time β if it's up, anEBUSYerror is returned. sit down before you change your type, that's the rule. πTUNSLMODEβ the argument should be a pointer to anint; 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 anint; 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 anint; 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 argumentint'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 ofSIGIOwhen data is available to be read β according as the argumentint'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 argumentint; otherwise, store zero.TIOCSPGRPβ set the process group to receiveSIGIOsignals, when asynchronous I/O is enabled, to the argumentintvalue.TIOCGPGRPβ retrieve the process group value forSIGIOsignals into the argumentintvalue.
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
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms