From ab2bbd987faae55c8a1e50f18e8f1c6a7e860b47 Mon Sep 17 00:00:00 2001
From: Chris Hellberg <chris@chrishellberg.com>
Date: Thu, 30 Dec 2021 05:09:16 +0000
Subject: [PATCH] further IPv6 commits

---
 src/iodined.c | 23 ++++++++++++++++++---
 src/tun.c     | 36 +++++++++++++++++++++++++--------
 src/user.c    | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/user.h    |  3 +++
 4 files changed, 106 insertions(+), 11 deletions(-)

diff --git a/src/iodined.c b/src/iodined.c
index 0a02632..b1378ac 100644
--- a/src/iodined.c
+++ b/src/iodined.c
@@ -649,13 +649,30 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds)
 	char in[64*1024];
 	int userid;
 	int read;
-
+        int ip_version;
+	int c;
+	struct in6_addr v6Addr;
+        char v6AddrP[16];
 	if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
 		return 0;
 
 	/* find target ip in packet, in is padded with 4 bytes TUN header */
 	header = (struct ip*) (in + 4);
-	userid = find_user_by_ip(header->ip_dst.s_addr);
+	ip_version = in[4] & 0xf0;
+
+	if (ip_version == 64) { /* IPv4 */
+	     header = (struct ip*) (in + 4);
+	     userid = find_user_by_ip(header->ip_dst.s_addr);
+	} else { /* IPv6 */
+             for (c = 0; c < 16; c++) {
+	        v6Addr.s6_addr[c] = in[c + 28];
+		printf("adding byte: %i to v6 address\n", in[c+28]);
+	     }
+	     inet_ntop(AF_INET6, &v6Addr, v6AddrP, INET6_ADDRSTRLEN);
+	     printf("read v6Addr from tunnel: %s\n", v6AddrP);
+	     userid = find_user_by_ip6(&v6Addr);
+	     printf("userid: %d\n", userid);
+        }
 	if (userid < 0)
 		return 0;
 
@@ -2437,7 +2454,7 @@ main(int argc, char **argv)
 	srand(time(NULL));
 	fw_query_init();
 
-	while ((choice = getopt(argc, argv, "46vcsfhDuS:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) {
+	while ((choice = getopt(argc, argv, "46vcsSfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) {
 		switch(choice) {
 		case '4':
 			addrfamily = AF_INET;
diff --git a/src/tun.c b/src/tun.c
index 7c20404..9d2c16d 100644
--- a/src/tun.c
+++ b/src/tun.c
@@ -549,19 +549,39 @@ write_tun(int tun_fd, char *data, size_t len)
 		len -= 4;
 	} else {
 #ifdef LINUX
+		
+                int i = data[4] & 0xf0;
+		if (i == 64) {
+			fprintf(stderr, "IPv4 packet\n");
+		// Look at the fifth bype 
 		// Linux prefixes with 32 bits ethertype
 		// 0x0800 for IPv4, 0x86DD for IPv6
-		data[0] = 0x00;
-		data[1] = 0x00;
-		data[2] = 0x08;
-		data[3] = 0x00;
+	    	    data[0] = 0x00;
+		    data[1] = 0x00;
+		    data[2] = 0x08;
+		    data[3] = 0x00;
+	        } else { /* 96 for IPV6 */
+			fprintf(stderr, "IPv6 packet\n");
+	    	    data[0] = 0x00;
+		    data[1] = 0x00;
+		    data[2] = 0x86;
+		    data[3] = 0xDD;
+	       }	
 #else /* OPENBSD and DARWIN(utun) */
 		// BSDs prefix with 32 bits address family
 		// AF_INET for IPv4, AF_INET6 for IPv6
-		data[0] = 0x00;
-		data[1] = 0x00;
-		data[2] = 0x00;
-		data[3] = 0x02;
+		if (i == 64) {
+			fprintf(stderr, "IPv4 packet\n");
+	    	    data[0] = 0x00;
+		    data[1] = 0x00;
+		    data[2] = 0x00;
+		    data[3] = 0x02;
+	        } else { /* 96 for IPV6 */
+			fprintf(stderr, "IPv6 packet\n");
+	    	    data[0] = 0x00;
+		    data[1] = 0x00;
+		    data[2] = 0x00;
+		    data[3] = 0x0A;
 #endif
 	}
 
diff --git a/src/user.c b/src/user.c
index b0ecdba..cbe91fe 100644
--- a/src/user.c
+++ b/src/user.c
@@ -42,12 +42,20 @@ int init_users(in_addr_t my_ip, int netbits)
 	int i;
 	int skip = 0;
 	char newip[16];
+	char ip6Tmp[16];
+	char ip6Tmp2[18];
+        char ipv4Tmp[16];
 
 	int maxusers;
 
 	in_addr_t netmask = 0;
 	struct in_addr net;
 	struct in_addr ipstart;
+	 
+	/* For IPv6, we take the IPv4 address and simply prepend ::
+	 * and use a 64-bit mask. Reduces the need to parse
+	 * netmasks. 
+	 */
 
 	for (i = 0; i < netbits; i++) {
 		netmask = (netmask << 1) | 1;
@@ -70,6 +78,19 @@ int init_users(in_addr_t my_ip, int netbits)
 			skip++;
 			snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
 			ip = ipstart.s_addr + inet_addr(newip);
+
+			inet_ntop(AF_INET, &ip, ip6Tmp, INET_ADDRSTRLEN);
+
+			snprintf(ip6Tmp2, sizeof(ip6Tmp2), "::%s", ip6Tmp);
+                        
+			inet_pton(AF_INET6, ip6Tmp2, &users[i].tun_ip6);
+			memset(ip6Tmp2,0,strlen(ip6Tmp2)); 
+			inet_ntop(AF_INET6, &users[i].tun_ip6, ip6Tmp2, INET6_ADDRSTRLEN); 
+			inet_ntop(AF_INET, &ip, ipv4Tmp, INET_ADDRSTRLEN); 
+	                printf("storing IPv4 address: %s\n", ipv4Tmp);
+	                printf("storing IPv6 address: %s\n", ip6Tmp2);
+			memset(ip6Tmp2,0,strlen(ip6Tmp2)); 
+			
 		}
 		users[i].tun_ip = ip;
 		net.s_addr = ip;
@@ -91,6 +112,40 @@ const char *users_get_first_ip(void)
 	return strdup(inet_ntoa(ip));
 }
 
+int find_user_by_ip6(struct in6_addr *v6Addr) 
+{
+	int i;
+        char v6AddrOut[32];
+
+	inet_ntop(AF_INET6, v6Addr, v6AddrOut, INET6_ADDRSTRLEN);
+
+	printf("Going to check address: %s in user list\n", v6AddrOut);
+	for (i = 0; i < usercount; i++) {
+		if (users[i].active &&
+			users[i].authenticated &&
+			!users[i].disabled &&
+			users[i].last_pkt + 60 > time(NULL) &&
+			(areV6AddressesEqual(v6Addr, &users[i].tun_ip6) == 0) ) {
+			   return i;
+		}
+	}
+	return -1;
+}
+
+int areV6AddressesEqual(struct in6_addr *v6Struct1, struct in6_addr *v6Struct2)
+{
+        int i;
+    
+	for (i = 0; i < 16; i++) {
+		printf("byte1 %d: %d byte2 %d: %d\n", i, v6Struct1->s6_addr[i], i, v6Struct2->s6_addr[i]);
+		if (v6Struct1->s6_addr[i] != v6Struct2->s6_addr[i]) {
+		    return -1;
+		}
+        }
+	return 0;
+}
+
+
 int find_user_by_ip(uint32_t ip)
 {
 	int ret;
diff --git a/src/user.h b/src/user.h
index b2ba704..bf160a6 100644
--- a/src/user.h
+++ b/src/user.h
@@ -45,6 +45,7 @@ struct tun_user {
 	int seed;
 	in_addr_t tun_ip;
 	struct sockaddr_storage host;
+	struct in6_addr tun_ip6;
 	socklen_t hostlen;
 	struct query q;
 	struct query q_sendrealsoon;
@@ -83,9 +84,11 @@ extern struct tun_user *users;
 int init_users(in_addr_t, int);
 const char* users_get_first_ip(void);
 int find_user_by_ip(uint32_t);
+int find_user_by_ip6(struct in6_addr *v6Addr);
 int all_users_waiting_to_send(void);
 int find_available_user(void);
 void user_switch_codec(int userid, const struct encoder *enc);
 void user_set_conn_type(int userid, enum connection c);
+int areV6AddressesEqual(struct in6_addr *, struct in6_addr *);
 
 #endif