From c77af62db8ad78bbc97057a844d0120def78fd7b Mon Sep 17 00:00:00 2001 From: Kazuyoshi Aizawa Date: Mon, 12 Dec 2011 18:10:20 +0000 Subject: [PATCH] Plumb interface for IPv6 with I_LINK ioctl we do for Legacy IP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the inconsistency noted in commit 5f873b34 — that we plumb the interface from openconnect itself for Legacy IP, but use 'ifconfig' in the vpnc-script to set it up for IPv6. Which has the potential to leave a stale interface lying around if openconnect exits uncleanly. Signed-off-by: Kazuyoshi Aizawa Signed-off-by: David Woodhouse --- openconnect-internal.h | 1 + tun.c | 123 +++++++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/openconnect-internal.h b/openconnect-internal.h index f551324a..05dea2ae 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -191,6 +191,7 @@ struct openconnect_info { #ifdef __sun__ int ip_fd; + int ip6_fd; #endif int tun_fd; int ssl_fd; diff --git a/tun.c b/tun.c index 0bbf18ca..2f6f2ae5 100644 --- a/tun.c +++ b/tun.c @@ -389,6 +389,62 @@ void script_reconnect (struct openconnect_info *vpninfo) script_config_tun(vpninfo); } +#ifdef __sun__ +static int link_proto(int unit_nr, const char *devname, uint64_t flags) +{ + int ip_fd, mux_id, tun2_fd; + struct lifreq ifr; + + tun2_fd = open("/dev/tun", O_RDWR); + if (tun2_fd < 0) { + perror(_("Could not /dev/tun for plumbing")); + return -EIO; + } + if (ioctl(tun2_fd, I_PUSH, "ip") < 0) { + perror(_("Can't push IP")); + close(tun2_fd); + return -EIO; + } + + sprintf(ifr.lifr_name, "tun%d", unit_nr); + ifr.lifr_ppa = unit_nr; + ifr.lifr_flags = flags; + + if (ioctl(tun2_fd, SIOCSLIFNAME, &ifr) < 0) { + perror(_("Can't set ifname")); + close(tun2_fd); + return -1; + } + + ip_fd = open(devname, O_RDWR); + if (ip_fd < 0) { + fprintf(stderr, _("Can't open %s: %s"), devname, + strerror(errno)); + close(tun2_fd); + return -1; + } + if (ioctl(ip_fd, I_PUSH, "arp") < 0) { + perror(_("Can't push ARP")); + close(tun2_fd); + close(ip_fd); + return -1; + } + + mux_id = ioctl(ip_fd, I_LINK, tun2_fd); + if (mux_id < 0) { + fprintf(stderr, _("Can't plumb %s for IPv%d: %s\n"), + ifr.lifr_name, (flags == IFF_IPV4) ? 4 : 6, + strerror(errno)); + close(tun2_fd); + close(ip_fd); + return -1; + } + + close(tun2_fd); + + return ip_fd; +} +#endif /* Set up a tuntap device. */ int setup_tun(struct openconnect_info *vpninfo) { @@ -458,19 +514,11 @@ int setup_tun(struct openconnect_info *vpninfo) vpninfo->ifname = strdup(ifr.ifr_name); #elif defined (__sun__) static char tun_name[80]; - int tun2_fd, ip_fd = open("/dev/ip", O_RDWR); - int unit_nr, mux_id; - struct ifreq ifr; - - if (ip_fd < 0) { - perror(_("open /dev/ip")); - return -EIO; - } + int unit_nr; tun_fd = open("/dev/tun", O_RDWR); if (tun_fd < 0) { perror(_("open /dev/tun")); - close(ip_fd); return -EIO; } @@ -478,55 +526,28 @@ int setup_tun(struct openconnect_info *vpninfo) if (unit_nr < 0) { perror(_("Failed to create new tun")); close(tun_fd); - close(ip_fd); - return -EIO; - } - - tun2_fd = open("/dev/tun", O_RDWR); - if (tun2_fd < 0) { - perror(_("open /dev/tun again")); - close(tun_fd); - close(ip_fd); - return -EIO; - } - if (ioctl(tun2_fd, I_PUSH, "ip") < 0) { - perror(_("Can't push IP")); - close(tun2_fd); - close(tun_fd); - close(ip_fd); return -EIO; } - if (ioctl(tun2_fd, IF_UNITSEL, &unit_nr) < 0) { - perror(_("Can't select unit")); - close(tun2_fd); - close(tun_fd); - close(ip_fd); - return -EIO; - } - mux_id = ioctl(ip_fd, I_LINK, tun2_fd); - if (mux_id < 0) { - perror(_("Can't link tun to IP")); - close(tun2_fd); - close(tun_fd); - close(ip_fd); - return -EIO; - } - close(tun2_fd); sprintf(tun_name, "tun%d", unit_nr); vpninfo->ifname = strdup(tun_name); - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, tun_name); - ifr.ifr_ip_muxid = mux_id; - - if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) { - perror(_("Set mux id")); + vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4); + if (vpninfo->ip_fd < 0) { close(tun_fd); - close(ip_fd); return -EIO; } - vpninfo->ip_fd = ip_fd; + + if (vpninfo->vpn_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]; @@ -704,6 +725,10 @@ void shutdown_tun(struct openconnect_info *vpninfo) #ifdef __sun__ close(vpninfo->ip_fd); vpninfo->ip_fd = -1; + if (vpninfo->ip6_fd != -1) { + close(vpninfo->ip6_fd); + vpninfo->ip6_fd = -1; + } #endif }