;;
esac
+AC_CHECK_FUNC(fdevname_r, [AC_DEFINE(HAVE_FDEVNAME_R, 1)], [])
AC_CHECK_FUNC(getline, [AC_DEFINE(HAVE_GETLINE, 1)], [symver_getline="openconnect__getline;"])
AC_CHECK_FUNC(strcasestr, [AC_DEFINE(HAVE_STRCASESTR, 1)], [])
AC_CHECK_FUNC(asprintf, [AC_DEFINE(HAVE_ASPRINTF, 1)], [symver_asprintf="openconnect__asprintf;"])
}
#endif
+#ifdef SIOCIFCREATE
+static int bsd_open_tun(char *tun_name)
+{
+ int fd;
+ int s;
+ struct ifreq ifr;
+
+ fd = open(tun_name, O_RDWR);
+ if (fd >= 0) {
+ return fd;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, tun_name + 5, sizeof(ifr.ifr_name) - 1);
+ if (!ioctl(s, SIOCIFCREATE, &ifr))
+ fd = open(tun_name, O_RDWR);
+
+ close(s);
+ }
+ return fd;
+}
+#else
+#define bsd_open_tun(tun_name) open(tun_name, O_RDWR)
+#endif
+
static int os_setup_tun(struct openconnect_info *vpninfo)
{
- int tun_fd;
+ int tun_fd = -1;
#ifdef IFF_TUN /* Linux */
struct ifreq ifr;
}
snprintf(tun_name, sizeof(tun_name),
"/dev/%s", vpninfo->ifname);
- tun_fd = open(tun_name, O_RDWR);
+ tun_fd = bsd_open_tun(tun_name);
if (tun_fd < 0) {
int err = errno;
vpn_progress(vpninfo, PRG_ERR,
tun_name, strerror(err));
return -EINVAL;
}
- } else {
+ }
+#ifdef HAVE_FDEVNAME_R
+ /* We don't have to iterate over the possible devices; on FreeBSD
+ at least, opening /dev/tun will give us the next available
+ device. */
+ if (tun_fd < 0) {
+ tun_fd = open("/dev/tun", O_RDWR);
+ if (tun_fd >= 0) {
+ if (!fdevname_r(tun_fd, tun_name, sizeof(tun_name)) ||
+ strncmp(tun_name, "tun", 3)) {
+ close(tun_fd);
+ tun_fd = -1;
+ } else
+ vpninfo->ifname = strdup(tun_name);
+ }
+ }
+#endif
+ if (tun_fd < 0) {
for (i = 0; i < 255; i++) {
sprintf(tun_name, "/dev/tun%d", i);
- tun_fd = open(tun_name, O_RDWR);
+ tun_fd = bsd_open_tun(tun_name);
if (tun_fd >= 0)
break;
}