3

I want to correctly match TAP/TUN devices with the processes they are using, and I want to do this from outside of these processes using TAP/TUN devices (that is, I cannot issue any ioctl()s because I don't have access to a particular file descriptor inside its process itself).

I'm aware of the answers to How to find the connection between tap interface and its file descriptor?, that is: /proc/[PID]/fdinfo/[FD] has an additional iff: key-value pair that gives the name of the corresponding TAP/TUN network interface.

However, there's a problem with network namespaces, especially when TAP/TUN network interfaces get moved around network namespaces after their user-space processes have attached to them; for instance (here, tapclient is a simple variation of a34729t's tunclient.c, which accepts a tap network name and attaches to it):

$ sudo ip tuntap add tap123 mode tap
$ sudo tapclient tap123 &
$ sudo ip netns add fooz
$ sudo ip link set tap123 netns fooz
$ PID=$(ps faux | grep tapclient | grep -v -e sudo -e grep | awk '{print $2}')
$ sudo cat /proc/$PID/fdinfo/3

...which then gives: iff: tap123 -- but not the network namespace where the tap123 network interface is currently located in.

Of course, tap123 can be located by iterating over all network namespaces and looking for a matching network interface inside one of them. Unfortunately, there might be duplicate names, such as when creating another tap123 in the host namespace after we've moved the first one of this name into the fooz network namespace above:

$ sudo ip tuntap add tap123 mode tap
$ ip link show tap123
$ sudo ip netns exec fooz ip link show tap123

So we now have two tap123s in separate network namespaces, and fdinfo only gives us an ambiguous iff: tap123.

Unfortunately, looking at the /proc/$PID/ns/net network namespace of the tapclient won't help either, since that doesn't match the current network namespace of tap123 any longer:

$ findmnt -t nsfs | grep /run/netns/fooz
$ sudo readlink /proc/$PID/ns/net

For instance, this gives net:[4026532591] versus net:[4026531993].

It there a way to unambiguously match the tapclient process with the correct tap123 network interface instance it is attached to?

  • Note that there's ip netns identify $PID that should give you the net namespace of $PID without you having to look at nsfs inode numbers (and ip netns pids fooz to go the other way), but they don't seem to find anything either. Sounds like a kernel bug. – TooTea Mar 7 at 10:40
  • @TooTea ip netns identify $PID is doing nothing more than taking /proc/$PID/ns/net and then trying to match only against its own list of bind-mounted symbolic network namespace names. Unfortunately, that's most of the time rather pointless as few are using iproute2's bindmount positions. My example is just using ip netns ... to give an easily reproducable example to check the underlying mechanisms, but it's not a typical deployment situation. – TheDiveO Mar 7 at 14:16
1

You can try matching the tun interface by its hardware address rather than by name (you can obtain that with ioctl(SIOCGIFHWADDR) on the tun/tap file descriptor).

I don't think there's anything simpler, otherwise a recent change like this (which adds the possibility of also retrieving the net namespace of the interface via the tun fd) wouldn't have been needed and accepted.

  • The new SIOCGSKNSioctl() you link to looks very promising, I'll look into its code to see if it does the job I'm asking for. At first glance it looks like it does, as I noticed already that the TUN clone device fd has the network namespace associated, but this cannot be retrieved from userspace later. What I'm unsure is whether it really works under the example conditions laid out above. But an interesting link anyway, many thanks! – TheDiveO Mar 7 at 14:22
  • The problem with SIOCGIFHWADDR and also SIOCGSKNS is rather that they need to be carried out on the original file descriptor because this fd's state is crucial here. Unfortunately, as unix.stackexchange.com/questions/74672/… points out, it's not really safely possible to duplicate the fd from the TAP/TUN user process to be used by someone else in order to issue the SIOCGKSNS. This leads me to believe that it's necessary to ask the kernel devs to be so kind as to add another fdinfo key for giving correct network namespace information. – TheDiveO Mar 7 at 15:12
  • I disagree that it's not "safely possible" to attach to a process with ptrace() and run any code in the context of that process (including sending fds with SCM_RIGHTS), but I don't have any nice and fast code to show right now. Until they add that info to fdinfo, and If using gdb is an option, you can make a list of tap interfaces, and call the ioctl via gdb only when necessary (when there really are duplicate names, etc). – mosvy Mar 7 at 20:17
  • Agreed on disagree: "safely" is misleading and I meant it to be along your "nice and fast code", deployable in production. I'm under the impression that SIOCGSKNS is strange as it returns the network namespace which was originally active when /dev/net/tun was opened. When moving the TAP/TUN later as in my example, the original network namespace would be returned, but the network interface isn't there anymore. The network namespace handling in tun.c looks slightly odd to me in places, especially when the stored original netns is passed but then ignored... – TheDiveO Mar 7 at 22:08
  • "SIOCGSKNS ... returns the network namespace which was originally active when /dev/net/tun was opened." that is unfortunately true ;-( wrong call, then. – mosvy Mar 7 at 23:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.