#include "TAP.h" char tap_name[IFNAMSIZ]; extern bool verbose; extern bool noipv6; extern bool set_ipv4; extern bool set_ipv6; extern bool set_linklocal; extern bool set_netmask; extern bool noup; extern int mtu; extern int device_type; extern char if_name[IFNAMSIZ]; extern char* ipv4_addr; extern char* ipv6_addr; extern long ipv6_prefixLen; extern char* netmask; extern void cleanup(); void trySixSet ( int interfaceIndex, struct in6_addr address, int prefixLen ) { char ip_str[INET6_ADDRSTRLEN+1]; inet_ntop(AF_INET6, &address, ip_str, INET6_ADDRSTRLEN+1); printf ( "Adding IPv6 address of '%s/%d' to interface at if_index %d\n", ip_str, prefixLen, interfaceIndex ); int inet6 = socket(AF_INET6, SOCK_DGRAM, 0); if(inet6 < 0) { printf("Error opening control socket for adding IPv6 address to interface\n"); cleanup(); exit(1); } struct in6_ifreq paramReq; memset(¶mReq, 0, sizeof(struct in6_ifreq)); paramReq.ifr6_ifindex = interfaceIndex; paramReq.ifr6_prefixlen = prefixLen; paramReq.ifr6_addr = address; // Try add the address if(ioctl(inet6, SIOCSIFADDR, ¶mReq) < 0) { printf ( "There was an errror assigning address '%s/%d' to if_index %d\n", ip_str, prefixLen, interfaceIndex ); cleanup(); close(inet6); exit(1); } printf("Address '%s/%d' added\n", ip_str, prefixLen); close(inet6); } int open_tap(void) { struct ifreq ifr; int fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { perror("Could not open clone device"); exit(1); } else { memset(&ifr, 0, sizeof(ifr)); // TODO: Enable PI header again? if (device_type == IF_TAP) { ifr.ifr_flags = IFF_TAP | IFF_NO_PI; } else if (device_type == IF_TUN) { ifr.ifr_flags = IFF_TUN; } else { printf("Error: Unsupported interface type\r\n"); cleanup(); exit(1); } strcpy(tap_name, "tnc%d"); strncpy(ifr.ifr_name, tap_name, IFNAMSIZ); if (ioctl(fd, TUNSETIFF, &ifr) < 0) { perror("Could not configure network interface"); exit(1); } else { strcpy(if_name, ifr.ifr_name); int inet = socket(AF_INET, SOCK_DGRAM, 0); if (inet == -1) { perror("Could not open control socket"); cleanup(); exit(1); } else { if (ioctl(inet, SIOCGIFMTU, &ifr) < 0) { perror("Could not get interface flags from kernel"); close(inet); cleanup(); exit(1); } else { ifr.ifr_mtu = mtu; if (ioctl(inet, SIOCSIFMTU, &ifr) < 0) { perror("Could not configure interface MTU"); close(inet); cleanup(); exit(1); } // Configure TX queue length if (ioctl(inet, SIOCGIFTXQLEN, &ifr) < 0) { perror("Could not get interface flags from kernel"); close(inet); cleanup(); exit(1); } else { ifr.ifr_qlen = TXQUEUELEN; if (ioctl(inet, SIOCSIFTXQLEN, &ifr) < 0) { perror("Could not set interface TX queue length"); close(inet); cleanup(); exit(1); } } // Configure ARP characteristics char path_buf[256]; if (device_type == IF_TAP) { snprintf(path_buf, sizeof(path_buf), "/proc/sys/net/ipv4/neigh/%s/base_reachable_time_ms", ifr.ifr_name); int arp_fd = open(path_buf, O_WRONLY); if (arp_fd < 0) { perror("Could not open proc entry for ARP parameters"); close(inet); cleanup(); exit(1); } else { if (dprintf(arp_fd, "%d", ARP_BASE_REACHABLE_TIME*1000) <= 0) { perror("Could not configure interface ARP parameter base_reachable_time_ms"); close(inet); close(arp_fd); cleanup(); exit(1); } else { close(arp_fd); } } snprintf(path_buf, sizeof(path_buf), "/proc/sys/net/ipv4/neigh/%s/retrans_time_ms", ifr.ifr_name); arp_fd = open(path_buf, O_WRONLY); if (arp_fd < 0) { perror("Could not open proc entry for ARP parameters"); close(inet); cleanup(); exit(1); } else { if (dprintf(arp_fd, "%d", ARP_RETRANS_TIME*1000) <= 0) { perror("Could not configure interface ARP parameter retrans_time_ms"); close(inet); close(arp_fd); cleanup(); exit(1); } else { close(arp_fd); } } } // Bring up if requested if (!noup) { if (ioctl(inet, SIOCGIFFLAGS, &ifr) < 0) { perror("Could not get interface flags from kernel"); close(inet); cleanup(); exit(1); } else { ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl(inet, SIOCSIFFLAGS, &ifr) < 0) { perror("Could not bring up interface"); close(inet); cleanup(); exit(1); } else { if (set_ipv4) { struct ifreq a_ifr; struct sockaddr_in addr, snm; memset(&a_ifr, 0, sizeof(a_ifr)); memset(&addr, 0, sizeof(addr)); memset(&snm, 0, sizeof(addr)); strncpy(a_ifr.ifr_name, ifr.ifr_name, IFNAMSIZ); addr.sin_family = AF_INET; snm.sin_family = AF_INET; int addr_conversion = inet_pton(AF_INET, ipv4_addr, &(addr.sin_addr)); if (addr_conversion != 1) { printf("Error: Invalid IPv4 address specified\r\n"); close(inet); cleanup(); exit(1); } else { a_ifr.ifr_addr = *(struct sockaddr*)&addr; if (ioctl(inet, SIOCSIFADDR, &a_ifr) < 0) { perror("Could not set IP-address"); close(inet); cleanup(); exit(1); } else { if (set_netmask) { int snm_conversion = inet_pton(AF_INET, netmask, &(snm.sin_addr)); if (snm_conversion != 1) { printf("Error: Invalid subnet mask specified\r\n"); close(inet); cleanup(); exit(1); } else { a_ifr.ifr_addr = *(struct sockaddr*)&snm; if (ioctl(inet, SIOCSIFNETMASK, &a_ifr) < 0) { perror("Could not set subnet mask"); close(inet); cleanup(); exit(1); } } } } } } if(set_ipv6 || set_linklocal) { // Firstly, obtain the interface index by `ifr_name` int inet6 = socket(AF_INET6, SOCK_DGRAM, 0); if(inet6 < 0) { printf("Error opening control socket for adding IPv6 address to interface\n"); cleanup(); exit(1); } if(ioctl(inet6, SIOCGIFINDEX, &ifr) < 0) { printf("Could not get interface index for interface '%s'\n", ifr.ifr_name); close(inet6); cleanup(); exit(1); } // if link-local was NOT requested and interface // has been up'd -> then kernel would have added // a link-local already, this removes it if(!set_linklocal & !noup) { // TODO: Get all addresses that start with fe80 } // Else it could have been no-up; hence you will have to remove // the link-local yourself // Other else is link-local was requested, then we don't care (whether // up'd or not as it will inevitably be added by the kernel) // Convert ASCII IPv6 address to ABI structure struct in6_addr six_addr_itself; memset(&six_addr_itself, 0, sizeof(struct in6_addr)); if(inet_pton(AF_INET6, ipv6_addr, &six_addr_itself) < 0) { printf("Error parsing IPv6 address '%s'\n", ipv6_addr); close(inet6); cleanup(); exit(1); } // Add user's requested address trySixSet(ifr.ifr_ifindex, six_addr_itself, ipv6_prefixLen); close(inet6); } } } } } } return fd; } } } int close_tap(int tap_fd) { return close(tap_fd); }