Add IPv6 support (command-line and tuntap) (#16)

* tncattach

- Added `set_ipv6`, `ipv6_addr` and `netmask_v6` globals
- Added `--ipv6` option
- If `n` is specified (i.e. `--noipv6`) then bail out if the user specified IPv6 addressing with `--ipv6 <arg>`
- Added `6` parsing, this is for when we have an `--ipv6` and want to set the address

* tncattach

- Removed global `netmask_v6` which is never used

* TAP

- Added initial code that I have been working on

* TAP

- Removed old (bad) code `trySixSet2(...)`

* TAP

- Clean up

* TAP

- Clean up

* TAP

- Added device type checl

* TAP

- Randomize the remaining octets of the link-local address

* TAP

- Seed random number generatro based off of current time

* TAP

- Removed TODO

* TAP_

- Cleaned up a little bit
- The `mtu` (on Luinux) must be `1280` of greater, else IPv6 won't work (and the address will not be allowed to be added)

* TAP

- More clean up

* TAP

- Moved mtu check for Ipv6 to be earlier

* TAP

- Added missing `cleanup()` calls

* TAP

- Aded newline

* TAP

- Now link-local and normal v6 can be requested independently

tncattach

- Added `--ll` mode to add link-local

* TAP

- More cleanup

* TAP

- Removed code to generate a link-local address

* tncattach

- Added error handling for mtu with IPv6 support

* TAP

- Removed uneeded imports

* TAP

- Cleaned up

* Cleaned up

* TAP

- Removed duplicate import

* TAP

- Removed error checking code from there

* TAP

- Cleaned up
- Remove dneed for `link_local_v6`

tncattach

- Removed `link_local_v6`

* TAP

- Close control socket when done

* tncattach

- Removed debug print

* TAP

- Cleaned up

* TAP

- Cleaned up

* TAP

- Cleaned up

* TAP

- Added check for bad open

* TAP

- Added another check

* tncattach

- Now parse IPv6 address and prefix in opt-args

TAP

- Removed parsing from here

* Fixed mtu stuff

* tncattach

- Typo fix

* Work

* tncattach

- WHen parsing the `prefixPart_s` (the prefix length), only continue if
the text is a number, if not then bail out with an error

* tncattach

- Only allow prefix length of between 0 to 128

* TAP

- Cleaned up

* TAP

- Cleaned up

* tncattach

- Cleaned up
This commit is contained in:
Tristan B. Velloza Kildaire 2024-12-22 15:27:16 +02:00 committed by GitHub
parent bb4b1917d5
commit c910421796
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 202 additions and 12 deletions

110
TAP.c
View File

@ -5,15 +5,72 @@ 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(&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);
@ -43,10 +100,11 @@ int open_tap(void) {
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");
perror("Could not open control socket");
cleanup();
exit(1);
} else {
@ -182,6 +240,54 @@ int open_tap(void) {
}
}
}
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);
}
}
}
}
@ -195,4 +301,4 @@ int open_tap(void) {
int close_tap(int tap_fd) {
return close(tap_fd);
}
}

1
TAP.h
View File

@ -9,6 +9,7 @@
#include <linux/if_tun.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/ipv6.h>
#include "Constants.h"
int open_tap(void);

View File

@ -34,11 +34,16 @@ bool noipv6 = false;
bool noup = false;
bool daemonize = false;
bool set_ipv4 = false;
bool set_ipv6 = false;
bool set_linklocal = false;
bool set_netmask = false;
bool kiss_over_tcp = false;
char* ipv4_addr;
char* netmask;
char* ipv6_addr;
long ipv6_prefixLen;
char* tcp_host;
int tcp_port;
@ -269,15 +274,17 @@ static struct argp_option options[] = {
{ "mtu", 'm', "MTU", 0, "Specify interface MTU", 1},
{ "ethernet", 'e', 0, 0, "Create a full ethernet device", 2},
{ "ipv4", 'i', "IP_ADDRESS", 0, "Configure an IPv4 address on interface", 3},
{ "noipv6", 'n', 0, 0, "Filter IPv6 traffic from reaching TNC", 4},
{ "noup", 1, 0, 0, "Only create interface, don't bring it up", 5},
{ "kisstcp", 'T', 0, 0, "Use KISS over TCP instead of serial port", 6},
{ "tcphost", 'H', "TCP_HOST", 0, "Host to connect to when using KISS over TCP", 7},
{ "tcpport", 'P', "TCP_PORT", 0, "TCP port when using KISS over TCP", 8},
{ "interval", 't', "SECONDS", 0, "Maximum interval between station identifications", 9},
{ "id", 's', "CALLSIGN", 0, "Station identification data", 10},
{ "daemon", 'd', 0, 0, "Run tncattach as a daemon", 11},
{ "verbose", 'v', 0, 0, "Enable verbose output", 12},
{ "ipv6", '6', "IP6_ADDRESS", 0, "Configure an IPv6 address on interface", 4},
{ "ll", 'l', 0, 0, "Add a link-local Ipv6 address", 5},
{ "noipv6", 'n', 0, 0, "Filter IPv6 traffic from reaching TNC", 6},
{ "noup", 1, 0, 0, "Only create interface, don't bring it up", 7},
{ "kisstcp", 'T', 0, 0, "Use KISS over TCP instead of serial port", 8},
{ "tcphost", 'H', "TCP_HOST", 0, "Host to connect to when using KISS over TCP", 9},
{ "tcpport", 'P', "TCP_PORT", 0, "TCP port when using KISS over TCP", 10},
{ "interval", 't', "SECONDS", 0, "Maximum interval between station identifications", 11},
{ "id", 's', "CALLSIGN", 0, "Station identification data", 12},
{ "daemon", 'd', 0, 0, "Run tncattach as a daemon", 13},
{ "verbose", 'v', 0, 0, "Enable verbose output", 14},
{ 0 }
};
@ -285,6 +292,7 @@ static struct argp_option options[] = {
struct arguments {
char *args[N_ARGS];
char *ipv4;
char *ipv6;
char *id;
bool valid_id;
int id_interval;
@ -296,6 +304,9 @@ struct arguments {
bool verbose;
bool set_ipv4;
bool set_netmask;
bool set_ipv6;
bool link_local_v6;
bool set_netmask_v6;
bool noipv6;
bool noup;
bool kiss_over_tcp;
@ -321,6 +332,13 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
printf("Error: Invalid MTU specified\r\n\r\n");
argp_usage(state);
}
if((arguments->set_ipv6 || arguments->link_local_v6) && arguments->mtu < 1280)
{
printf("IPv6 and/or link-local IPv6 was requested, but the MTU provided is lower than 1280\n");
exit(EXIT_FAILURE);
}
break;
case 't':
@ -466,9 +484,70 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
}
break;
case '6':
if(arguments->noipv6)
{
perror("Sorry, but you had noipv6 set yet want to use ipv6?\n");
exit(EXIT_FAILURE);
}
char* ipPart_s = strtok(arg, "/");
char* prefixPart_s = strtok(NULL, "/");
printf("ipPart_s: %s\n", ipPart_s);
if(!prefixPart_s)
{
printf("No prefix length was provided\n");
exit(1);
}
printf("prefixPart_s: %s\n", prefixPart_s);
long prefixLen_l = strtol(prefixPart_s, NULL, 10); // TODO: Add handling here for errors (using errno)
if(prefixLen_l == 0) {
printf("Prefix length '%s' is not numeric\n", prefixPart_s);
exit(EXIT_FAILURE);
}
else if(!(prefixLen_l >= 0 && prefixLen_l <= 128))
{
printf("Prefix length '%s' is not within valid range of 0-128\n", prefixPart_s);
exit(EXIT_FAILURE);
}
arguments->ipv6 = ipPart_s;
arguments->set_ipv6 = true;
// Copy across global IPv6 address
ipv6_addr = malloc(strlen(arguments->ipv6)+1);
strcpy(ipv6_addr, arguments->ipv6);
// Set global IPv6 prefix length
ipv6_prefixLen = prefixLen_l;
printf("MTU was %d, setting to minimum of %d as is required for IPv6\n", arguments->mtu, 1280);
arguments->mtu = 1280;
break;
case 'l':
if(arguments->noipv6)
{
perror("Sorry, but you had noipv6 set yet want to use ipv6 link-local?\n");
exit(EXIT_FAILURE);
}
arguments->link_local_v6 = true;
printf("MTU was %d, setting to minimum of %d as is required for IPv6\n", arguments->mtu, 1280);
arguments->mtu = 1280;
break;
case 'n':
arguments->noipv6 = true;
if(arguments->set_ipv6)
{
printf("Requested no IPv6 yet you have set the IPv6 to '%s'\n", arguments->ipv6);
exit(1);
}
break;
case 'd':
@ -559,6 +638,9 @@ int main(int argc, char **argv) {
arguments.verbose = false;
arguments.set_ipv4 = false;
arguments.set_netmask = false;
arguments.set_ipv6 = false;
arguments.link_local_v6 = false;
arguments.set_netmask_v6 = false;
arguments.noipv6 = false;
arguments.daemon = false;
arguments.noup = false;
@ -586,6 +668,7 @@ int main(int argc, char **argv) {
if (arguments.noipv6) noipv6 = true;
if (arguments.set_ipv4) set_ipv4 = true;
if (arguments.set_netmask) set_netmask = true;
if (arguments.set_ipv6) set_ipv6 = true;
if (arguments.noup) noup = true;
mtu = arguments.mtu;
@ -632,4 +715,4 @@ int main(int argc, char **argv) {
read_loop();
return 0;
}
}