tncattach/TAP.c

198 lines
8.3 KiB
C

#include "TAP.h"
char tap_name[IFNAMSIZ];
extern bool verbose;
extern bool noipv6;
extern bool set_ipv4;
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* netmask;
extern void cleanup();
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 AF_INET 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);
}
}
}
}
}
}
}
}
}
}
}
return fd;
}
}
}
int close_tap(int tap_fd) {
return close(tap_fd);
}