📄 tun.c
字号:
#elsevoidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ ASSERT (0);}#endif#elsevoidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);}#endif /* HAVE_LINUX_IF_TUN_H */#ifdef TUNSETPERSISTvoidtuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode){ struct tuntap *tt; ALLOC_OBJ (tt, struct tuntap); clear_tuntap (tt); tt->type = dev_type_enum (dev, dev_type); open_tun (dev, dev_type, dev_node, ipv6, tt); if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0) msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); close_tun (tt); msg (M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF"));}#endif /* TUNSETPERSIST */voidclose_tun (struct tuntap *tt){ if (tt) { close_tun_generic (tt); free (tt); }}intwrite_tun (struct tuntap* tt, uint8_t *buf, int len){#if LINUX_IPV6 if (tt->ipv6) { struct tun_pi pi; struct iphdr *iph; struct iovec vect[2]; int ret; iph = (struct iphdr *)buf; pi.flags = 0; if(iph->version == 6) pi.proto = htons(ETH_P_IPV6); else pi.proto = htons(ETH_P_IP); vect[0].iov_len = sizeof(pi); vect[0].iov_base = π vect[1].iov_len = len; vect[1].iov_base = buf; ret = writev(tt->fd, vect, 2); return(ret - sizeof(pi)); } else#endif return write (tt->fd, buf, len);}intread_tun (struct tuntap* tt, uint8_t *buf, int len){#if LINUX_IPV6 if (tt->ipv6) { struct iovec vect[2]; struct tun_pi pi; int ret; vect[0].iov_len = sizeof(pi); vect[0].iov_base = π vect[1].iov_len = len; vect[1].iov_base = buf; ret = readv(tt->fd, vect, 2); return(ret - sizeof(pi)); } else#endif return read (tt->fd, buf, len);}#elif defined(TARGET_SOLARIS)#ifndef TUNNEWPPA#error I need the symbol TUNNEWPPA from net/if_tun.h#endifvoidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ int if_fd, muxid, ppa = -1; struct ifreq ifr; const char *ptr; const char *ip_node; const char *dev_tuntap_type; int link_type; bool is_tun; ipv6_support (ipv6, false, tt); if (tt->type == DEV_TYPE_NULL) { open_null (tt); return; } if (tt->type == DEV_TYPE_TUN) { ip_node = "/dev/udp"; if (!dev_node) dev_node = "/dev/tun"; dev_tuntap_type = "tun"; link_type = I_PLINK; is_tun = true; } else if (tt->type == DEV_TYPE_TAP) { ip_node = "/dev/ip"; if (!dev_node) dev_node = "/dev/tap"; dev_tuntap_type = "tap"; link_type = I_PLINK; /* was: I_LINK */ is_tun = false; } else { msg (M_FATAL, "I don't recognize device %s as a tun or tap device", dev); } /* get unit number */ if (*dev) { ptr = dev; while (*ptr && !isdigit ((int) *ptr)) ptr++; ppa = atoi (ptr); } if ((tt->ip_fd = open (ip_node, O_RDWR, 0)) < 0) msg (M_ERR, "Can't open %s", ip_node); if ((tt->fd = open (dev_node, O_RDWR, 0)) < 0) msg (M_ERR, "Can't open %s", dev_node); /* Assign a new PPA and get its unit number. */ if ((ppa = ioctl (tt->fd, TUNNEWPPA, ppa)) < 0) msg (M_ERR, "Can't assign new interface"); if ((if_fd = open (dev_node, O_RDWR, 0)) < 0) msg (M_ERR, "Can't open %s (2)", dev_node); if (ioctl (if_fd, I_PUSH, "ip") < 0) msg (M_ERR, "Can't push IP module"); /* Assign ppa according to the unit number returned by tun device */ if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0) msg (M_ERR, "Can't set PPA %d", ppa); if ((muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0) msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type); close (if_fd); tt->actual_name = (char *) malloc (32); check_malloc_return (tt->actual_name); openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa); CLEAR (ifr); strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name)); ifr.ifr_ip_muxid = muxid; if (ioctl (tt->ip_fd, SIOCSIFMUXID, &ifr) < 0) { ioctl (tt->ip_fd, I_PUNLINK, muxid); msg (M_ERR, "Can't set multiplexor id"); } set_nonblock (tt->fd); set_cloexec (tt->fd); set_cloexec (tt->ip_fd); msg (M_INFO, "TUN/TAP device %s opened", tt->actual_name);}static voidsolaris_close_tun (struct tuntap *tt){ if (tt) { if (tt->ip_fd >= 0) { struct ifreq ifr; CLEAR (ifr); strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name)); if (ioctl (tt->ip_fd, SIOCGIFFLAGS, &ifr) < 0) msg (M_WARN | M_ERRNO, "Can't get iface flags"); if (ioctl (tt->ip_fd, SIOCGIFMUXID, &ifr) < 0) msg (M_WARN | M_ERRNO, "Can't get multiplexor id"); if (ioctl (tt->ip_fd, I_PUNLINK, ifr.ifr_ip_muxid) < 0) msg (M_WARN | M_ERRNO, "Can't unlink interface"); close (tt->ip_fd); tt->ip_fd = -1; } if (tt->fd >= 0) { close (tt->fd); tt->fd = -1; } }}/* * Close TUN device. */voidclose_tun (struct tuntap *tt){ if (tt) { solaris_close_tun (tt); if (tt->actual_name) free (tt->actual_name); clear_tuntap (tt); free (tt); }}static voidsolaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual){ char command_line[256]; openvpn_snprintf (command_line, sizeof (command_line), IFCONFIG_PATH " %s unplumb", actual); msg (M_INFO, "%s", command_line); system_check (command_line, es, 0, "Solaris ifconfig unplumb failed"); close_tun (tt); msg (M_FATAL, "Solaris ifconfig failed");}intwrite_tun (struct tuntap* tt, uint8_t *buf, int len){ struct strbuf sbuf; sbuf.len = len; sbuf.buf = (char *)buf; return putmsg (tt->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;}intread_tun (struct tuntap* tt, uint8_t *buf, int len){ struct strbuf sbuf; int f = 0; sbuf.maxlen = len; sbuf.buf = (char *)buf; return getmsg (tt->fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;}#elif defined(TARGET_OPENBSD)#if !defined(HAVE_READV) || !defined(HAVE_WRITEV)#error openbsd build requires readv & writev library functions#endif/* * OpenBSD has a slightly incompatible TUN device from * the rest of the world, in that it prepends a * uint32 to the beginning of the IP header * to designate the protocol (why not just * look at the version field in the IP header to * determine v4 or v6?). * * We strip off this field on reads and * put it back on writes. * * I have not tested TAP devices on OpenBSD, * but I have conditionalized the special * TUN handling code described above to * go away for TAP devices. */voidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); /* Enable multicast on the interface */ if (tt->fd >= 0) { struct tuninfo info; if (ioctl (tt->fd, TUNGIFINFO, &info) < 0) { msg (M_WARN | M_ERRNO, "Can't get interface info: %s", strerror(errno)); } info.flags |= IFF_MULTICAST; if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) { msg (M_WARN | M_ERRNO, "Can't set interface info: %s", strerror(errno)); } }}voidclose_tun (struct tuntap* tt){ if (tt) { close_tun_generic (tt); free (tt); }}static inline intopenbsd_modify_read_write_return (int len){ if (len > 0) return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; else return len;}intwrite_tun (struct tuntap* tt, uint8_t *buf, int len){ if (tt->type == DEV_TYPE_TUN) { u_int32_t type; struct iovec iv[2]; struct ip *iph; iph = (struct ip *) buf; if (tt->ipv6 && iph->ip_v == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); iv[0].iov_base = &type; iv[0].iov_len = sizeof (type); iv[1].iov_base = buf; iv[1].iov_len = len; return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); } else return write (tt->fd, buf, len);}intread_tun (struct tuntap* tt, uint8_t *buf, int len){ if (tt->type == DEV_TYPE_TUN) { u_int32_t type; struct iovec iv[2]; iv[0].iov_base = &type; iv[0].iov_len = sizeof (type); iv[1].iov_base = buf; iv[1].iov_len = len; return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); } else return read (tt->fd, buf, len);}#elif defined(TARGET_NETBSD)/* * NetBSD does not support IPv6 on tun out of the box, * but there exists a patch. When this patch is applied, * only two things are left to openvpn: * 1. Activate multicasting (this has already been done * before by the kernel, but we make sure that nobody * has deactivated multicasting inbetween. * 2. Deactivate "link layer mode" (otherwise NetBSD * prepends the address family to the packet, and we * would run into the same trouble as with OpenBSD. */voidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); if (tt->fd >= 0) { int i = IFF_POINTOPOINT|IFF_MULTICAST; ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */ i = 0; ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ }}voidclose_tun (struct tuntap *tt){ if (tt) { close_tun_generic (tt); free (tt); }}intwrite_tun (struct tuntap* tt, uint8_t *buf, int len){ return write (tt->fd, buf, len);}intread_tun (struct tuntap* tt, uint8_t *buf, int len){ return read (tt->fd, buf, len);}#elif defined(TARGET_FREEBSD)static inline intfreebsd_modify_read_write_return (int len){ if (len > 0) return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; else return len;}voidopen_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt){ open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); if (tt->fd >= 0) { int i = 0; /* Disable extended modes */ ioctl (tt->fd, TUNSLMODE, &i); i = 1; ioctl (tt->fd, TUNSIFHEAD, &i); }}voidclose_tun (struct tuntap *tt){ if (tt) { close_tun_generic (tt); free (tt); }}intwrite_tun (struct tuntap* tt, uint8_t *buf, int len){ if (tt->type == DEV_TYPE_TUN) { u_int32_t type; struct iovec iv[2]; struct ip *iph; iph = (struct ip *) buf; if (tt->ipv6 && iph->ip_v == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); iv[0].iov_base = (char *)&type; iv[0].iov_len = sizeof (type); iv[1].iov_base = buf; iv[1].iov_len = len; return freebsd_modify_read_write_return (writev (tt->fd, iv, 2)); } else return write (tt->fd, buf, len);}intread_tun (struct tuntap* tt, uint8_t *buf, int len){ if (tt->type == DEV_TYPE_TUN) { u_int32_t type; struct iovec iv[2]; iv[0].iov_base = (char *)&type; iv[0].iov_len = sizeof (type); iv[1].iov_base = buf; iv[1].iov_len = len; return freebsd_modify_read_write_return (readv (tt->fd, iv, 2)); } else return read (tt->fd, buf, len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -