示例#1
0
intptr_t os_setup_tun(struct openconnect_info *vpninfo)
{
	int tun_fd = -1;
	static char tun_name[80];
	int unit_nr;

	tun_fd = open("/dev/tun", O_RDWR);
	if (tun_fd < 0) {
		vpn_perror(vpninfo, _("open /dev/tun"));
		return -EIO;
	}

	unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
	if (unit_nr < 0) {
		vpn_perror(vpninfo, _("Failed to create new tun"));
		close(tun_fd);
		return -EIO;
	}

	if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
		vpn_perror(vpninfo, _("Failed to put tun file descriptor into message-discard mode"));
		close(tun_fd);
		return -EIO;
	}

	sprintf(tun_name, "tun%d", unit_nr);
	vpninfo->ifname = strdup(tun_name);

	vpninfo->ip_fd = link_proto(vpninfo, unit_nr, "/dev/udp", IFF_IPV4);
	if (vpninfo->ip_fd < 0) {
		close(tun_fd);
		return -EIO;
	}

	if (vpninfo->ip_info.addr6 || vpninfo->ip_info.netmask6) {
		vpninfo->ip6_fd = link_proto(vpninfo, unit_nr, "/dev/udp6", IFF_IPV6);
		if (vpninfo->ip6_fd < 0) {
			close(tun_fd);
			close(vpninfo->ip_fd);
			vpninfo->ip_fd = -1;
			return -EIO;
		}
	} else
		vpninfo->ip6_fd = -1;

	return tun_fd;
}
示例#2
0
文件: tun.c 项目: neshema/openconnect
intptr_t os_setup_tun(struct openconnect_info *vpninfo)
{
    int tun_fd = -1;
#ifdef IFF_TUN /* Linux */
    struct ifreq ifr;
    int tunerr;

    tun_fd = open("/dev/net/tun", O_RDWR);
    if (tun_fd < 0) {
        /* Android has /dev/tun instead of /dev/net/tun
           Since other systems might have too, just try it
           as a fallback instead of using ifdef __ANDROID__ */
        tunerr = errno;
        tun_fd = open("/dev/tun", O_RDWR);
    }
    if (tun_fd < 0) {
        /* If the error on /dev/tun is ENOENT, that's boring.
           Use the error we got on /dev/net/tun instead */
        if (errno != ENOENT)
            tunerr = errno;

        vpn_progress(vpninfo, PRG_ERR,
                     _("Failed to open tun device: %s\n"),
                     strerror(tunerr));
        return -EIO;
    }
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    if (vpninfo->ifname)
        strncpy(ifr.ifr_name, vpninfo->ifname,
                sizeof(ifr.ifr_name) - 1);
    if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0) {
        vpn_progress(vpninfo, PRG_ERR,
                     _("TUNSETIFF failed: %s\n"),
                     strerror(errno));
        close(tun_fd);
        return -EIO;
    }
    if (!vpninfo->ifname)
        vpninfo->ifname = strdup(ifr.ifr_name);
#elif defined(__sun__)
    static char tun_name[80];
    int unit_nr;

    tun_fd = open("/dev/tun", O_RDWR);
    if (tun_fd < 0) {
        perror(_("open /dev/tun"));
        return -EIO;
    }

    unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
    if (unit_nr < 0) {
        perror(_("Failed to create new tun"));
        close(tun_fd);
        return -EIO;
    }

    if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
        perror(_("Failed to put tun file descriptor into message-discard mode"));
        close(tun_fd);
        return -EIO;
    }

    sprintf(tun_name, "tun%d", unit_nr);
    vpninfo->ifname = strdup(tun_name);

    vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4);
    if (vpninfo->ip_fd < 0) {
        close(tun_fd);
        return -EIO;
    }

    if (vpninfo->ip_info.addr6) {
        vpninfo->ip6_fd = link_proto(unit_nr, "/dev/udp6", IFF_IPV6);
        if (vpninfo->ip6_fd < 0) {
            close(tun_fd);
            close(vpninfo->ip_fd);
            vpninfo->ip_fd = -1;
            return -EIO;
        }
    } else
        vpninfo->ip6_fd = -1;

#else /* BSD et al have /dev/tun$x devices */
    static char tun_name[80];
    int i;

    if (vpninfo->ifname) {
        char *endp = NULL;
        if (strncmp(vpninfo->ifname, "tun", 3) ||
                ((void)strtol(vpninfo->ifname + 3, &endp, 10), !endp) ||
                *endp) {
            vpn_progress(vpninfo, PRG_ERR,
                         _("Invalid interface name '%s'; must match 'tun%%d'\n"),
                         vpninfo->ifname);
            return -EINVAL;
        }
        snprintf(tun_name, sizeof(tun_name),
                 "/dev/%s", vpninfo->ifname);
        tun_fd = bsd_open_tun(tun_name);
        if (tun_fd < 0) {
            int err = errno;
            vpn_progress(vpninfo, PRG_ERR,
                         _("Cannot open '%s': %s\n"),
                         tun_name, strerror(err));
            return -EINVAL;
        }
    }
#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 = bsd_open_tun(tun_name);
            if (tun_fd >= 0)
                break;
        }
        if (tun_fd < 0) {
            vpn_progress(vpninfo, PRG_ERR,
                         _("Failed to open tun device: %s\n"),
                         strerror(errno));
            return -EIO;
        }
        vpninfo->ifname = strdup(tun_name + 5);
    }
#ifdef TUNSIFHEAD
    i = 1;
    if (ioctl(tun_fd, TUNSIFHEAD, &i) < 0) {
        perror(_("TUNSIFHEAD"));
        close(tun_fd);
        return -EIO;
    }
#endif
#endif /* BSD-style */

    /* Ancient vpnc-scripts might not get this right */
    set_tun_mtu(vpninfo);

    return tun_fd;
}