tncattach/TAP.c
Tristan Brice Velloza Kildaire 05bc0ae6ad tncattach
- Now parse IPv6 address and prefix in opt-args

TAP

- Removed parsing from here
2024-12-15 18:34:19 +02:00

293 lines
11 KiB
C

#include "TAP.h"
char tap_name[IFNAMSIZ];
extern bool verbose;
extern bool noipv6;
extern bool set_ipv4;
extern bool set_ipv6;
extern bool link_local_v6;
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(&paramReq, 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, &paramReq) < 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)
{
// 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);
}
// 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);
}