198 lines
8.3 KiB
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);
|
|
} |