Use devname() if available to support devfs cloning on BSD.
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 9 Apr 2016 16:39:40 +0000 (18:39 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 9 Apr 2016 16:39:40 +0000 (18:39 +0200)
Some BSD flavors allow opening /dev/tun and/or /dev/tap, which automatically
create a new tun or tap interface with an unused number. To find out which
number the interface got, you have to call devname() on the device file
that was opened.

The semantics are different from the way Linux's /dev/tun works though.
In particular, after closing the device, the interface will continue to exist.
Restarting tincd would cause the old interface to stay around, and a new
one to be created. One could add a tinc-down script with the following line:

ifconfig $INTERFACE destroy

But that is still no guarantee that restarting tinc will give you the same
interface. So the default tun and tap device will stay /dev/tun0 and /dev/tap0
for all BSD flavors to avoid surprises for existing users.

configure.ac
src/bsd/device.c

index 3b781ba..61917f8 100644 (file)
@@ -187,7 +187,7 @@ AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp,
 
 dnl Checks for library functions.
 AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall pselect putenv random select strdup strerror strsignal strtol system unsetenv usleep vsyslog writev],
+AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall pselect putenv random select strdup strerror strsignal strtol system unsetenv usleep vsyslog writev devname fdevname],
   [], [], [#include "src/have.h"]
 )
 
index b58db8a..70e0b0b 100644 (file)
@@ -60,7 +60,7 @@ static device_type_t device_type = DEVICE_TYPE_TUN;
 #endif
 
 static bool setup_device(void) {
-       char *type;
+       // Find out which device file to open
 
        if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
                if(routing_mode == RMODE_ROUTER)
@@ -69,10 +69,9 @@ static bool setup_device(void) {
                        device = xstrdup(DEFAULT_TAP_DEVICE);
        }
 
-       if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
-               iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
-       else if(strcmp(iface, strrchr(device, '/') ? strrchr(device, '/') + 1 : device))
-               logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
+       // Find out if it's supposed to be a tun or a tap device
+
+       char *type;
 
        if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
                if(!strcasecmp(type, "tun"))
@@ -96,6 +95,8 @@ static bool setup_device(void) {
                        device_type = DEVICE_TYPE_TAP;
        }
 
+       // Open the device
+
        switch(device_type) {
 #ifdef ENABLE_TUNEMU
                case DEVICE_TYPE_TUNEMU: {
@@ -117,6 +118,27 @@ static bool setup_device(void) {
        fcntl(device_fd, F_SETFD, FD_CLOEXEC);
 #endif
 
+       // Guess what the corresponding interface is called
+
+       char *realname;
+
+#if defined(HAVE_FDEVNAME)
+       realname = fdevname(device_fd) ? : device;
+#elif defined(HAVE_DEVNAME)
+       struct stat buf;
+       if(!fstat(device_fd, &buf))
+               realname = devname(buf.st_rdev, S_IFCHR) ? : device;
+#else
+       realname = device;
+#endif
+
+       if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
+               iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
+       else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname))
+               logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
+
+       // Configure the device as best as we can
+
        switch(device_type) {
                default:
                        device_type = DEVICE_TYPE_TUN;