From bc061f09c167ec40af75faab51299fee00db6a17 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Sun, 26 Dec 2021 16:25:21 -0500 Subject: [PATCH 01/17] Shifted to v0.8.0 --- CHANGELOG | 2 +- LICENSE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4b2490d4..35bda207 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,7 @@ iodine - https://code.kryo.se/iodine CHANGES: -master: +2021-12-26: 0.8.0 "Uncaptive portal" - Mac OS X: Support native utun VPN devices. Patch by Peter Sagerson, ported from OpenVPN by Catalin Patulea. - Fix compilation failure on kFreeBSD and Hurd, by Gregor Herrmann diff --git a/LICENSE b/LICENSE index 80845bae..224e7459 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2006-2020 iodine authors +Copyright (c) 2006-2021 iodine authors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice From 78b5b7d93fe00b89c698d6141932cbd83945a924 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Sun, 26 Dec 2021 16:37:05 -0500 Subject: [PATCH 02/17] switched to master branch update --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 35bda207..66aebd82 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ iodine - https://code.kryo.se/iodine CHANGES: +2021-12-26: master + - switched to master branch + 2021-12-26: 0.8.0 "Uncaptive portal" - Mac OS X: Support native utun VPN devices. Patch by Peter Sagerson, ported from OpenVPN by Catalin Patulea. From 8e206aead2fcac477bbeb57ba973a69a4422ced0 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Mon, 27 Dec 2021 15:15:01 -0500 Subject: [PATCH 03/17] v6 first pass --- src/client.c | 8 ++++---- src/client.h | 2 +- src/iodine.c | 10 ++++++++-- src/iodined.c | 10 +++++++--- src/tun.c | 11 ++++++++++- src/tun.h | 2 +- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/client.c b/src/client.c index 5f3eb781..a756c757 100644 --- a/src/client.c +++ b/src/client.c @@ -1374,7 +1374,7 @@ handshake_version(int dns_fd, int *seed) } static int -handshake_login(int dns_fd, int seed) +handshake_login(int dns_fd, int seed, int forward_v6) { char in[4096]; char login[16]; @@ -1405,7 +1405,7 @@ handshake_login(int dns_fd, int seed) server[64] = 0; client[64] = 0; - if (tun_setip(client, server, netmask) == 0 && + if (tun_setip(client, server, netmask, forward_v6) == 0 && tun_setmtu(mtu) == 0) { fprintf(stderr, "Server tunnel IP is %s\n", server); @@ -2326,7 +2326,7 @@ handshake_set_fragsize(int dns_fd, int fragsize) } int -client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize) +client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize, int forward_v6) { int seed; int upcodec; @@ -2349,7 +2349,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz return r; } - r = handshake_login(dns_fd, seed); + r = handshake_login(dns_fd, seed, forward_v6); if (r) { return r; } diff --git a/src/client.h b/src/client.h index 3dab6fb7..ac61a83a 100644 --- a/src/client.h +++ b/src/client.h @@ -35,7 +35,7 @@ void client_set_lazymode(int lazy_mode); void client_set_hostname_maxlen(int i); int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, - int fragsize); + int fragsize, int forward_v6); int client_tunnel(int tun_fd, int dns_fd); #endif diff --git a/src/iodine.c b/src/iodine.c index fbb64812..3f81495e 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -72,7 +72,7 @@ static void help(FILE *stream, bool verbose) { fprintf(stream, "iodine IP over DNS tunneling client\n\n" - "Usage: %s [-46fhrv] [-u user] [-t chrootdir] [-d device] [-P password]\n" + "Usage: %s [-46fhrvS] [-u user] [-t chrootdir] [-d device] [-P password]\n" " [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec]\n" " [-z context] [-F pidfile] [nameserver] topdomain\n", __progname); @@ -100,6 +100,7 @@ static void help(FILE *stream, bool verbose) " -t dir to chroot to directory dir\n" " -d device to set tunnel device name\n" " -z context, to apply specified SELinux context after initialization\n" + " -S enable forwarding of IPv6 packets within the tunnel\n" " -F pidfile to write pid to a file\n\n" "nameserver is the IP number/hostname of the relaying nameserver. If absent,\n" " /etc/resolv.conf is used\n" @@ -152,6 +153,7 @@ int main(int argc, char **argv) struct sockaddr_storage nameservaddr; int nameservaddr_len; int nameserv_family; + int forward_v6; nameserv_host = NULL; topdomain = NULL; @@ -176,6 +178,7 @@ int main(int argc, char **argv) selecttimeout = 4; hostname_maxlen = 0xFF; nameserv_family = AF_UNSPEC; + forward_v6 = 0; #ifdef WINDOWS32 WSAStartup(req_version, &wsa_data); @@ -192,7 +195,7 @@ int main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) { + while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:s")) != -1) { switch(choice) { case '4': nameserv_family = AF_INET; @@ -268,6 +271,9 @@ int main(int argc, char **argv) if (!lazymode) selecttimeout = 1; break; + case 'S': + forward_v6 = 1; + break; case 'I': selecttimeout = atoi(optarg); if (selecttimeout < 1) diff --git a/src/iodined.c b/src/iodined.c index f9555161..ff405a5d 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2274,7 +2274,7 @@ write_dns(int fd, struct query *q, const char *data, int datalen, char downenc) static void print_usage(FILE *stream) { fprintf(stream, - "Usage: %s [-46cDfsv] [-u user] [-t chrootdir] [-d device] [-m mtu]\n" + "Usage: %s [-46cDfsvS] [-u user] [-t chrootdir] [-d device] [-m mtu]\n" " [-z context] [-l ipv4 listen address] [-L ipv6 listen address]\n" " [-p port] [-n auto|external_ip] [-b dnsport] [-P password]\n" " [-F pidfile] [-i max idle time] tunnel_ip[/netmask] topdomain\n", @@ -2390,6 +2390,7 @@ main(int argc, char **argv) int dns4addr_len; struct sockaddr_storage dns6addr; int dns6addr_len; + int forward_v6; #ifdef HAVE_SYSTEMD int nb_fds; #endif @@ -2418,7 +2419,7 @@ main(int argc, char **argv) debug = 0; netmask = 27; pidfile = NULL; - + forward_v6 = 0; retval = 0; #ifdef WINDOWS32 @@ -2507,6 +2508,9 @@ main(int argc, char **argv) /* XXX: find better way of cleaning up ps(1) */ memset(optarg, 0, strlen(optarg)); break; + case 'S': + forward_v6 = 1; + break; case 'z': context = optarg; break; @@ -2674,7 +2678,7 @@ main(int argc, char **argv) } if (!skipipconfig) { const char *other_ip = users_get_first_ip(); - if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) { + if (tun_setip(argv[0], other_ip, netmask, forward_v6) != 0 || tun_setmtu(mtu) != 0) { retval = 1; free((void*) other_ip); goto cleanup; diff --git a/src/tun.c b/src/tun.c index 4c78895a..804fad7c 100644 --- a/src/tun.c +++ b/src/tun.c @@ -592,7 +592,7 @@ read_tun(int tun_fd, char *buf, size_t len) #endif int -tun_setip(const char *ip, const char *other_ip, int netbits) +tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) { char cmdline[512]; int netmask; @@ -687,6 +687,15 @@ tun_setip(const char *ip, const char *other_ip, int netbits) if_name, ip, inet_ntoa(net)); return system(cmdline); #endif + + if (forward_v6) { + snprintf(cmdline, sizeof(cmdline), + IFCONFIGPATH "ifconfig %s inet6 add ::%s/64", + if_name, + ip); + + fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip); + } } int diff --git a/src/tun.h b/src/tun.h index 8982a9f8..a57c007e 100644 --- a/src/tun.h +++ b/src/tun.h @@ -22,7 +22,7 @@ int open_tun(const char *); void close_tun(int); int write_tun(int, char *, size_t); ssize_t read_tun(int, char *, size_t); -int tun_setip(const char *, const char *, int); +int tun_setip(const char *, const char *, int, int); int tun_setmtu(const unsigned); #endif /* _TUN_H_ */ From 1e196bff4d23f9065bfc80cca374a451f0ba7cf3 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Mon, 27 Dec 2021 20:19:10 +0000 Subject: [PATCH 04/17] test file add --- test-file | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test-file diff --git a/test-file b/test-file new file mode 100644 index 00000000..e69de29b From 16e1b731f69284b0c9992ac755f9278de4cdd5cc Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Tue, 28 Dec 2021 03:14:05 +0000 Subject: [PATCH 05/17] Linux server interfaces populated with V6 addresses --- src/iodine.c | 2 +- src/iodined.c | 16 +++++++++++----- src/tun.c | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/iodine.c b/src/iodine.c index 3f81495e..2059779e 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -372,7 +372,7 @@ int main(int argc, char **argv) fprintf(stderr, "Sending DNS queries for %s to %s\n", topdomain, format_addr(&nameservaddr, nameservaddr_len)); - if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { + if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size, forward_v6)) { retval = 1; goto cleanup2; } diff --git a/src/iodined.c b/src/iodined.c index ff405a5d..0a02632a 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2437,7 +2437,7 @@ main(int argc, char **argv) srand(time(NULL)); fw_query_init(); - while ((choice = getopt(argc, argv, "46vcsfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) { + while ((choice = getopt(argc, argv, "46vcsfhDuS:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) { switch(choice) { case '4': addrfamily = AF_INET; @@ -2678,11 +2678,17 @@ main(int argc, char **argv) } if (!skipipconfig) { const char *other_ip = users_get_first_ip(); - if (tun_setip(argv[0], other_ip, netmask, forward_v6) != 0 || tun_setmtu(mtu) != 0) { - retval = 1; + if (tun_setip(argv[0], other_ip, netmask, forward_v6) || tun_setmtu(mtu) != 0) { + retval = 1; free((void*) other_ip); - goto cleanup; - } + goto cleanup; + + } + if ((mtu < 1280) && (forward_v6)) { + warnx("Interface mtu of %d below the 1280 threshold needed for IPv6 tunneling.\n", mtu); + warnx("Proceeding without IPv6 tunneling\n"); + } + free((void*) other_ip); } diff --git a/src/tun.c b/src/tun.c index 804fad7c..7c204044 100644 --- a/src/tun.c +++ b/src/tun.c @@ -595,9 +595,11 @@ int tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) { char cmdline[512]; + char v6_cmdline[512]; int netmask; struct in_addr net; int i; + int v6_r; #ifndef LINUX int r; #endif @@ -630,6 +632,18 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) # else display_ip = ip; # endif + fprintf(stderr, "Setting IPv6 of %s to ::%s\n", if_name, ip); + + snprintf(v6_cmdline, sizeof(cmdline), + IFCONFIGPATH "ifconfig %s inet6 add ::%s/64", + if_name, + display_ip); + + v6_r = system(v6_cmdline); + + if (v6_r != 0) { + return v6_r; + } snprintf(cmdline, sizeof(cmdline), IFCONFIGPATH "ifconfig %s %s %s netmask %s", if_name, From ab2bbd987faae55c8a1e50f18e8f1c6a7e860b47 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Thu, 30 Dec 2021 05:09:16 +0000 Subject: [PATCH 06/17] 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 0a02632a..b1378ac6 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 7c204044..9d2c16df 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 b0ecdbaf..cbe91fe8 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 b2ba7048..bf160a63 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 From 8ee729050282883479e985df73d664c0beb2896e Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Thu, 30 Dec 2021 00:28:53 -0500 Subject: [PATCH 07/17] removed comments --- src/iodine.c | 2 +- src/iodined.c | 3 --- src/tun.c | 6 ++++-- src/user.c | 2 -- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/iodine.c b/src/iodine.c index 2059779e..e8ebb665 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -195,7 +195,7 @@ int main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:s")) != -1) { + while ((choice = getopt(argc, argv, "46vfhruS:t:d:R:P:m:M:F:T:O:L:I")) != -1) { switch(choice) { case '4': nameserv_family = AF_INET; diff --git a/src/iodined.c b/src/iodined.c index b1378ac6..cc4f025f 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -666,12 +666,9 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds) } 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; diff --git a/src/tun.c b/src/tun.c index 9d2c16df..38c01de4 100644 --- a/src/tun.c +++ b/src/tun.c @@ -548,9 +548,9 @@ write_tun(int tun_fd, char *data, size_t len) data += 4; len -= 4; } else { + int i = data[4] & 0xf0; #ifdef LINUX - int i = data[4] & 0xf0; if (i == 64) { fprintf(stderr, "IPv4 packet\n"); // Look at the fifth bype @@ -581,7 +581,9 @@ write_tun(int tun_fd, char *data, size_t len) data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = 0x0A; + data[3] = 0x1E; + + } #endif } diff --git a/src/user.c b/src/user.c index cbe91fe8..c02f905b 100644 --- a/src/user.c +++ b/src/user.c @@ -119,7 +119,6 @@ int find_user_by_ip6(struct in6_addr *v6Addr) 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 && @@ -137,7 +136,6 @@ 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; } From 883ef8ba57ee6219270503a696d4cc1bbd3b3f6b Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Thu, 30 Dec 2021 00:32:32 -0500 Subject: [PATCH 08/17] another stray comment --- src/tun.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tun.c b/src/tun.c index 38c01de4..abe8076a 100644 --- a/src/tun.c +++ b/src/tun.c @@ -552,7 +552,6 @@ write_tun(int tun_fd, char *data, size_t len) #ifdef LINUX 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 @@ -561,7 +560,6 @@ write_tun(int tun_fd, char *data, size_t len) data[2] = 0x08; data[3] = 0x00; } else { /* 96 for IPV6 */ - fprintf(stderr, "IPv6 packet\n"); data[0] = 0x00; data[1] = 0x00; data[2] = 0x86; @@ -571,13 +569,11 @@ write_tun(int tun_fd, char *data, size_t len) // BSDs prefix with 32 bits address family // AF_INET for IPv4, AF_INET6 for IPv6 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; From 461c4c3a4103cc85d74e0ce9eb389926defacab9 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Thu, 30 Dec 2021 20:44:26 -0500 Subject: [PATCH 09/17] bugfix to shift non-variable options to end of list in getopt() --- src/iodine.c | 8 ++++---- src/iodined.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/iodine.c b/src/iodine.c index e8ebb665..3b9b76d4 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -195,7 +195,7 @@ int main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "46vfhruS:t:d:R:P:m:M:F:T:O:L:I")) != -1) { + while ((choice = getopt(argc, argv, "t:d:R:P:m:M:z:F:T:O:L:I:46vfhruS")) != -1) { switch(choice) { case '4': nameserv_family = AF_INET; @@ -220,6 +220,9 @@ int main(int argc, char **argv) case 'u': username = optarg; break; + case 'S': + forward_v6 = 1; + break; case 't': newroot = optarg; break; @@ -271,9 +274,6 @@ int main(int argc, char **argv) if (!lazymode) selecttimeout = 1; break; - case 'S': - forward_v6 = 1; - break; case 'I': selecttimeout = atoi(optarg); if (selecttimeout < 1) diff --git a/src/iodined.c b/src/iodined.c index cc4f025f..16c2fb07 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2451,7 +2451,7 @@ main(int argc, char **argv) srand(time(NULL)); fw_query_init(); - while ((choice = getopt(argc, argv, "46vcsSfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) { + while ((choice = getopt(argc, argv, "t:d:m:l:L:p:n:b:P:z:F:i:46vcsSfhDu")) != -1) { switch(choice) { case '4': addrfamily = AF_INET; From 00c842933a7b6cbd00f0df73591a0f92e40020b6 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Thu, 30 Dec 2021 21:06:28 -0500 Subject: [PATCH 10/17] reverted CHANGELOG in preparation for ipv6 submission --- CHANGELOG | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 66aebd82..4b2490d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,10 +5,7 @@ iodine - https://code.kryo.se/iodine CHANGES: -2021-12-26: master - - switched to master branch - -2021-12-26: 0.8.0 "Uncaptive portal" +master: - Mac OS X: Support native utun VPN devices. Patch by Peter Sagerson, ported from OpenVPN by Catalin Patulea. - Fix compilation failure on kFreeBSD and Hurd, by Gregor Herrmann From c9efbc0156bbda4cba8a5dbcc6c1c318e5d785a2 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Fri, 31 Dec 2021 02:13:22 +0000 Subject: [PATCH 11/17] added IPv6 usage in iodined --- src/iodined.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/iodined.c b/src/iodined.c index 16c2fb07..36b99e71 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2333,6 +2333,7 @@ static void help(FILE *stream) " -b port to forward normal DNS queries to (on localhost)\n" " -P password used for authentication (max 32 chars will be used)\n" " -F pidfile to write pid to a file\n" + " -S enable forwarding of IPv6 packets within the tunnel\n" " -i maximum idle time before shutting down\n\n" "tunnel_ip is the IP number of the local tunnel interface.\n" " /netmask sets the size of the tunnel network.\n" From a2d65f6ec4120e2a31378de38505eebc956e9a3b Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Fri, 31 Dec 2021 02:18:47 +0000 Subject: [PATCH 12/17] removing debug messages --- src/user.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/user.c b/src/user.c index c02f905b..3e00906b 100644 --- a/src/user.c +++ b/src/user.c @@ -87,8 +87,6 @@ int init_users(in_addr_t my_ip, int netbits) 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)); } From 9d86d0afdcf92d5c1bdaef99fc99de3d32beace6 Mon Sep 17 00:00:00 2001 From: chris hellberg Date: Thu, 30 Dec 2021 21:24:25 -0500 Subject: [PATCH 13/17] minor updates --- src/iodined.c | 4 ++-- test-file | 0 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 test-file diff --git a/src/iodined.c b/src/iodined.c index 36b99e71..9109571b 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2693,8 +2693,8 @@ main(int argc, char **argv) } if (!skipipconfig) { const char *other_ip = users_get_first_ip(); - if (tun_setip(argv[0], other_ip, netmask, forward_v6) || tun_setmtu(mtu) != 0) { - retval = 1; + if (tun_setip(argv[0], other_ip, netmask, forward_v6) != 0 || tun_setmtu(mtu) != 0) { + retval = 1; free((void*) other_ip); goto cleanup; diff --git a/test-file b/test-file deleted file mode 100644 index e69de29b..00000000 From 061fac44d2246d21959120b46b07eade0538417e Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Fri, 31 Dec 2021 04:15:04 +0000 Subject: [PATCH 14/17] fixed bug with initializing users structure. Wasn't allowing multiple users to connect V6 --- src/user.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/user.c b/src/user.c index 3e00906b..253694ec 100644 --- a/src/user.c +++ b/src/user.c @@ -44,7 +44,6 @@ int init_users(in_addr_t my_ip, int netbits) char newip[16]; char ip6Tmp[16]; char ip6Tmp2[18]; - char ipv4Tmp[16]; int maxusers; @@ -71,7 +70,12 @@ int init_users(in_addr_t my_ip, int netbits) for (i = 0; i < usercount; i++) { in_addr_t ip; users[i].id = i; + + memset(ip6Tmp,0,strlen(ip6Tmp)); + memset(ip6Tmp2,0,strlen(ip6Tmp2)); + snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); + ip = ipstart.s_addr + inet_addr(newip); if (ip == my_ip && skip == 0) { /* This IP was taken by iodined */ @@ -79,18 +83,14 @@ int init_users(in_addr_t my_ip, int netbits) 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); - memset(ip6Tmp2,0,strlen(ip6Tmp2)); } users[i].tun_ip = ip; + + inet_ntop(AF_INET, &ip, ip6Tmp, INET_ADDRSTRLEN); + snprintf(ip6Tmp2, sizeof(ip6Tmp2), "::%s", ip6Tmp); + inet_pton(AF_INET6, ip6Tmp2, &users[i].tun_ip6); + net.s_addr = ip; users[i].disabled = 0; users[i].authenticated = 0; From 3eb959c8fe04baa789e045b83a6aee0c12a50bd8 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Fri, 31 Dec 2021 04:37:56 +0000 Subject: [PATCH 15/17] fixed bug where IPv6 was always being set on the tunnel interface --- src/tun.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tun.c b/src/tun.c index abe8076a..0e658b5b 100644 --- a/src/tun.c +++ b/src/tun.c @@ -650,18 +650,20 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) # else display_ip = ip; # endif - fprintf(stderr, "Setting IPv6 of %s to ::%s\n", if_name, ip); + if (forward_v6) { + fprintf(stderr, "Setting IPv6 of %s to ::%s\n", if_name, ip); - snprintf(v6_cmdline, sizeof(cmdline), + snprintf(v6_cmdline, sizeof(cmdline), IFCONFIGPATH "ifconfig %s inet6 add ::%s/64", if_name, display_ip); - v6_r = system(v6_cmdline); + v6_r = system(v6_cmdline); - if (v6_r != 0) { - return v6_r; - } + if (v6_r != 0) { + return v6_r; + } + } snprintf(cmdline, sizeof(cmdline), IFCONFIGPATH "ifconfig %s %s %s netmask %s", if_name, From 846082f13e203240d668fe0877dc15444768c852 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Sun, 8 May 2022 19:45:32 +0000 Subject: [PATCH 16/17] further IPv6 changes --- src/Makefile | 2 +- src/client.c | 75 +++++++++++++++++- src/client.h | 4 +- src/common.c | 16 ++++ src/common.h | 2 + src/iodine.c | 13 +--- src/iodined.c | 96 ++++++++++++++++++----- src/tun.c | 205 +++++++++++++++++++++++++++++++++++++++++--------- src/tun.h | 4 +- src/user.c | 99 ++++++++++++++++++------ src/user.h | 5 +- 11 files changed, 427 insertions(+), 94 deletions(-) diff --git a/src/Makefile b/src/Makefile index c3f8c28c..df59a565 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ ARCH = `uname -m` HEAD_COMMIT = `git rev-parse --short HEAD` LIBPATH = -L. -LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH) +LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH) -lm CFLAGS += -std=c99 -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags` -DGITREVISION=\"$(HEAD_COMMIT)\" CFLAGS += -Wstrict-prototypes -Wtype-limits -Wmissing-declarations -Wmissing-prototypes diff --git a/src/client.c b/src/client.c index a756c757..8261b689 100644 --- a/src/client.c +++ b/src/client.c @@ -28,6 +28,8 @@ #include #include #include +#include + #ifdef WINDOWS32 #include "windows.h" @@ -101,6 +103,7 @@ static time_t lastdownstreamtime; static long send_query_sendcnt = -1; static long send_query_recvcnt = 0; static int hostname_maxlen = 0xFF; +static bool use_v6 = false; void client_init() @@ -1374,7 +1377,7 @@ handshake_version(int dns_fd, int *seed) } static int -handshake_login(int dns_fd, int seed, int forward_v6) +handshake_login(int dns_fd, int seed) { char in[4096]; char login[16]; @@ -1405,7 +1408,7 @@ handshake_login(int dns_fd, int seed, int forward_v6) server[64] = 0; client[64] = 0; - if (tun_setip(client, server, netmask, forward_v6) == 0 && + if (tun_setip(client, server, netmask) == 0 && tun_setmtu(mtu) == 0) { fprintf(stderr, "Server tunnel IP is %s\n", server); @@ -2326,7 +2329,7 @@ handshake_set_fragsize(int dns_fd, int fragsize) } int -client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize, int forward_v6) +client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize) { int seed; int upcodec; @@ -2349,7 +2352,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz return r; } - r = handshake_login(dns_fd, seed, forward_v6); + r = handshake_login(dns_fd, seed); if (r) { return r; } @@ -2414,8 +2417,72 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz handshake_set_fragsize(dns_fd, fragsize); if (!running) return -1; + + handshake_check_v6(dns_fd); + if (!running) + return -1; } return 0; } +static +void send_v6_probe(int dns_fd) +{ + char data[4096]; + + data[0] = userid; + + send_packet(dns_fd, 'g', data, sizeof(data)); +} + +int +handshake_check_v6(int dns_fd) +{ + char in[4096]; + char server6[1024]; + char client6[1024]; + int i; + int read; + int netmask6 = 0; + + fprintf(stderr, "Autoprobing server IPV6 tunnel support\n"); + + for (i = 0; running && i < 5; i++) { + + send_v6_probe(dns_fd); + + read = handshake_waitdns(dns_fd, in, sizeof(in), 'g', 'G', i+1); + + if (read > 0) { + + /* + * including a terminating dash to allow for future IPv6 options, e.g. + * netmask. Currently assumes /64. MTU is taken from the IPv4 handshake. + * A future IPv6-only implementation would need to pass mtu + * in the IPV6 handshake. + */ + + if (sscanf(in, "%512[^-]-%512[^-]-%d", server6, client6, &netmask6) == 3) { + + fprintf(stderr, "Server tunnel IPv6 is %s\n", server6); + fprintf(stderr, "Local tunnel IPv6 is %s\n", client6); + + if (tun_setip6(client6, server6, netmask6) == 0) { + + use_v6 = true; + return 0; + } else { + errx(4, "Failed to set IPv6 tunnel address"); + } + } else { + fprintf(stderr, "Received bad IPv6 tunnel handshake\n"); + } + } + + fprintf(stderr, "Retrying IPv6 tunnel handshake...\n"); + } + if (!running) + return -1; + return 0; +} diff --git a/src/client.h b/src/client.h index ac61a83a..aa0ea3b6 100644 --- a/src/client.h +++ b/src/client.h @@ -35,7 +35,7 @@ void client_set_lazymode(int lazy_mode); void client_set_hostname_maxlen(int i); int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, - int fragsize, int forward_v6); + int fragsize); int client_tunnel(int tun_fd, int dns_fd); - +int handshake_check_v6(int tun_fd); #endif diff --git a/src/common.c b/src/common.c index 37ae48dc..3eaff218 100644 --- a/src/common.c +++ b/src/common.c @@ -13,6 +13,8 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * */ #include @@ -557,3 +559,17 @@ fd_set_close_on_exec(int fd) } #endif +bool +isV6AddrSet(struct in6_addr *ip6) +{ + int i; + + for (i = 0; i < sizeof(ip6->s6_addr); i++) { + if (ip6->s6_addr[i] != 0) { + return true; + } + } + + return false; +} + diff --git a/src/common.h b/src/common.h index 0f990c13..15265323 100644 --- a/src/common.h +++ b/src/common.h @@ -33,6 +33,7 @@ extern const unsigned char raw_header[RAW_HDR_LEN]; #include +#include #ifdef WINDOWS32 #include "windows.h" #else @@ -129,6 +130,7 @@ void read_password(char*, size_t); int check_topdomain(char *, int, char **); int query_datalen(const char *qname, const char *topdomain); +bool isV6AddrSet(struct in6_addr *); #if defined(WINDOWS32) || defined(ANDROID) #ifndef ANDROID diff --git a/src/iodine.c b/src/iodine.c index 3b9b76d4..8e1a42f8 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -72,7 +72,7 @@ static void help(FILE *stream, bool verbose) { fprintf(stream, "iodine IP over DNS tunneling client\n\n" - "Usage: %s [-46fhrvS] [-u user] [-t chrootdir] [-d device] [-P password]\n" + "Usage: %s [-46fhrv] [-u user] [-t chrootdir] [-d device] [-P password]\n" " [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec]\n" " [-z context] [-F pidfile] [nameserver] topdomain\n", __progname); @@ -100,7 +100,6 @@ static void help(FILE *stream, bool verbose) " -t dir to chroot to directory dir\n" " -d device to set tunnel device name\n" " -z context, to apply specified SELinux context after initialization\n" - " -S enable forwarding of IPv6 packets within the tunnel\n" " -F pidfile to write pid to a file\n\n" "nameserver is the IP number/hostname of the relaying nameserver. If absent,\n" " /etc/resolv.conf is used\n" @@ -153,7 +152,6 @@ int main(int argc, char **argv) struct sockaddr_storage nameservaddr; int nameservaddr_len; int nameserv_family; - int forward_v6; nameserv_host = NULL; topdomain = NULL; @@ -178,7 +176,6 @@ int main(int argc, char **argv) selecttimeout = 4; hostname_maxlen = 0xFF; nameserv_family = AF_UNSPEC; - forward_v6 = 0; #ifdef WINDOWS32 WSAStartup(req_version, &wsa_data); @@ -195,7 +192,8 @@ int main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "t:d:R:P:m:M:z:F:T:O:L:I:46vfhruS")) != -1) { + while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) { + switch(choice) { case '4': nameserv_family = AF_INET; @@ -220,9 +218,6 @@ int main(int argc, char **argv) case 'u': username = optarg; break; - case 'S': - forward_v6 = 1; - break; case 't': newroot = optarg; break; @@ -372,7 +367,7 @@ int main(int argc, char **argv) fprintf(stderr, "Sending DNS queries for %s to %s\n", topdomain, format_addr(&nameservaddr, nameservaddr_len)); - if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size, forward_v6)) { + if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { retval = 1; goto cleanup2; } diff --git a/src/iodined.c b/src/iodined.c index 9109571b..cb6f803c 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -88,10 +88,16 @@ static int created_users; static int check_ip; static int my_mtu; static in_addr_t my_ip; + +char display_ip6[INET6_ADDRSTRLEN]; +char *display_ip6_buffer; +char *ip6_netmask_buffer; + +static struct in6_addr my_ip6; static int netmask; +static int ip6_netmask = 64; static in_addr_t ns_ip; - static int bind_port; static int debug; @@ -658,9 +664,9 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds) /* find target ip in packet, in is padded with 4 bytes TUN header */ header = (struct ip*) (in + 4); - ip_version = in[4] & 0xf0; + ip_version = get_ipversion(in[4]); - if (ip_version == 64) { /* IPv4 */ + if (ip_version == 4) { /* IPv4 */ header = (struct ip*) (in + 4); userid = find_user_by_ip(header->ip_dst.s_addr); } else { /* IPv6 */ @@ -674,6 +680,7 @@ static int tunnel_tun(int tun_fd, struct dnsfd *dns_fds) return 0; outlen = sizeof(out); + compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9); if (users[userid].conn == CONN_DNS_NULL) { @@ -1303,6 +1310,32 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query !users[userid].lazy) send_chunk_or_dataless(dns_fd, userid, &users[userid].q); + /* IPv6 tunnel address probe */ + } else if (in[0] == 'G' || in[0] == 'g') { + char client_ip6[INET6_ADDRSTRLEN]; + char display_my_ip6[INET6_ADDRSTRLEN]; + + read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, &base32_ops); + if (read < 1) { + write_dns(dns_fd, q, "BADLEN", 6, 'T'); + return; + } + + /* Ping packet, store userid */ + userid = unpacked[0]; + if (check_authenticated_user_and_ip(userid, q) != 0) { + write_dns(dns_fd, q, "BADIP", 5, 'T'); + return; /* illegal id */ + } + + inet_ntop(AF_INET6, &users[userid].tun_ip6, client_ip6, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &my_ip6, display_my_ip6, INET6_ADDRSTRLEN); + read = snprintf(out, sizeof(out), "%s-%s-%d-", + display_my_ip6, client_ip6, ip6_netmask); + + write_dns(dns_fd, q, out, read, users[userid].downenc); + return; + } else if ((in[0] >= '0' && in[0] <= '9') || (in[0] >= 'a' && in[0] <= 'f') || (in[0] >= 'A' && in[0] <= 'F')) { @@ -2288,10 +2321,10 @@ write_dns(int fd, struct query *q, const char *data, int datalen, char downenc) static void print_usage(FILE *stream) { fprintf(stream, - "Usage: %s [-46cDfsvS] [-u user] [-t chrootdir] [-d device] [-m mtu]\n" + "Usage: %s [-46cDfsv] [-u user] [-t chrootdir] [-d device] [-m mtu]\n" " [-z context] [-l ipv4 listen address] [-L ipv6 listen address]\n" " [-p port] [-n auto|external_ip] [-b dnsport] [-P password]\n" - " [-F pidfile] [-i max idle time] tunnel_ip[/netmask] topdomain\n", + " [-F pidfile] [-S ipv6 tunnel address] [-i max idle time] tunnel_ip[/netmask] topdomain\n", __progname); } @@ -2333,7 +2366,7 @@ static void help(FILE *stream) " -b port to forward normal DNS queries to (on localhost)\n" " -P password used for authentication (max 32 chars will be used)\n" " -F pidfile to write pid to a file\n" - " -S enable forwarding of IPv6 packets within the tunnel\n" + " -S IPv6 server address within the tunnel. Netmask fixed at /64\n" " -i maximum idle time before shutting down\n\n" "tunnel_ip is the IP number of the local tunnel interface.\n" " /netmask sets the size of the tunnel network.\n" @@ -2405,7 +2438,6 @@ main(int argc, char **argv) int dns4addr_len; struct sockaddr_storage dns6addr; int dns6addr_len; - int forward_v6; #ifdef HAVE_SYSTEMD int nb_fds; #endif @@ -2434,7 +2466,6 @@ main(int argc, char **argv) debug = 0; netmask = 27; pidfile = NULL; - forward_v6 = 0; retval = 0; #ifdef WINDOWS32 @@ -2452,7 +2483,8 @@ main(int argc, char **argv) srand(time(NULL)); fw_query_init(); - while ((choice = getopt(argc, argv, "t:d:m:l:L:p:n:b:P:z:F:i:46vcsSfhDu")) != -1) { + while ((choice = getopt(argc, argv, "46vcsfhDuS:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) { + switch(choice) { case '4': addrfamily = AF_INET; @@ -2524,7 +2556,7 @@ main(int argc, char **argv) memset(optarg, 0, strlen(optarg)); break; case 'S': - forward_v6 = 1; + display_ip6_buffer = optarg; break; case 'z': context = optarg; @@ -2553,10 +2585,28 @@ main(int argc, char **argv) my_ip = inet_addr(argv[0]); if (my_ip == INADDR_NONE) { - warnx("Bad IP address to use inside tunnel."); + warnx("Bad IP address to use inside tunnel."); usage(); } + + ip6_netmask_buffer = strchr(display_ip6_buffer, '/'); + if (ip6_netmask_buffer) { + if (atoi(ip6_netmask_buffer+1) != ip6_netmask) { + warnx("IPv6 address must be a 64-bit mask."); + usage(); + } + /* remove masklen */ + memcpy(display_ip6, display_ip6_buffer, strlen(display_ip6_buffer) - strlen(ip6_netmask_buffer)); + display_ip6[strlen(display_ip6)+1] = '\0'; + } + + /* IPV6 address sanity check */ + if (inet_pton(AF_INET6, display_ip6, &my_ip6) != 1) { + warnx("Bad IPv6 address to use inside tunnel."); + usage(); + } + topdomain = strdup(argv[1]); if (check_topdomain(topdomain, 1, &errormsg)) { warnx("Invalid topdomain: %s", errormsg); @@ -2685,7 +2735,7 @@ main(int argc, char **argv) dns_fds.v4fd = -1; dns_fds.v6fd = -1; - created_users = init_users(my_ip, netmask); + created_users = init_users(my_ip, netmask, my_ip6, ip6_netmask); if ((tun_fd = open_tun(device)) == -1) { /* nothing to clean up, just return */ @@ -2693,16 +2743,26 @@ main(int argc, char **argv) } if (!skipipconfig) { const char *other_ip = users_get_first_ip(); - if (tun_setip(argv[0], other_ip, netmask, forward_v6) != 0 || tun_setmtu(mtu) != 0) { + const char *display_other_ip6 = users_get_first_ip6(); + + + if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) { retval = 1; free((void*) other_ip); goto cleanup; - + } - if ((mtu < 1280) && (forward_v6)) { - warnx("Interface mtu of %d below the 1280 threshold needed for IPv6 tunneling.\n", mtu); - warnx("Proceeding without IPv6 tunneling\n"); - } + + if (tun_setip6(display_ip6, display_other_ip6, ip6_netmask) != 0 ) { + retval = 1; + goto cleanup; + + } + + if ((mtu < 1280) && (sizeof(display_ip6)) != 0) { + warnx("Interface mtu of %d below the 1280 threshold needed for IPv6 tunneling.\n", mtu); + warnx("Proceeding without IPv6 tunneling\n"); + } free((void*) other_ip); } diff --git a/src/tun.c b/src/tun.c index 0e658b5b..ec5c909b 100644 --- a/src/tun.c +++ b/src/tun.c @@ -35,6 +35,11 @@ #include #endif +#if defined FREEBSD || defined NETBSD +#include +#include +#endif + #ifndef IFCONFIGPATH #define IFCONFIGPATH "PATH=/sbin:/bin " #endif @@ -82,6 +87,7 @@ static char if_name[250]; #include #include + int open_tun(const char *tun_device) { @@ -452,7 +458,15 @@ open_tun(const char *tun_device) snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i); if ((tun_fd = open(tun_name, O_RDWR)) >= 0) { - fprintf(stderr, "Opened %s\n", tun_name); +#if defined FREEBSD || defined NETBSD + /* FreeBSD requires a packet header for + * IPv6 traffic + */ + if (ioctl(tun_fd, TUNSIFHEAD, &(int){1}) != 0) { + fprintf(stderr, "Not able to enable TUNSIFHEAD\n"); + break; + } +#endif /* LINUX */ snprintf(if_name, sizeof(if_name), "tun%d", i); fd_set_close_on_exec(tun_fd); return tun_fd; @@ -530,9 +544,12 @@ read_tun(int tun_fd, char *buf, size_t len) static int tun_uses_header(void) { -#if defined (FREEBSD) || defined (NETBSD) - /* FreeBSD/NetBSD has no header */ - return 0; +#if defined FREEBSD || defined NETBSD || defined OPENBSD + /* To enable IPv6 in FreeBSD tunnels, tunnel + * headers now enabled for that platform + */ + return 1; + #elif defined (DARWIN) /* Darwin tun has no header, Darwin utun does */ return !strncmp(if_name, "utun", 4); @@ -544,42 +561,83 @@ tun_uses_header(void) int write_tun(int tun_fd, char *data, size_t len) { + + int ip_version = 0; + if (!tun_uses_header()) { data += 4; len -= 4; } else { - int i = data[4] & 0xf0; + + ip_version = get_ipversion(data[4]); + + if (ip_version < 0) { + return 1; /* Cannot read IP version number from packet */ + } + #ifdef LINUX - - if (i == 64) { - // Look at the fifth bype + + if (ip_version == 4) { // Linux prefixes with 32 bits ethertype // 0x0800 for IPv4, 0x86DD for IPv6 data[0] = 0x00; data[1] = 0x00; data[2] = 0x08; data[3] = 0x00; - } else { /* 96 for IPV6 */ + } else { /* IPV6 */ data[0] = 0x00; data[1] = 0x00; data[2] = 0x86; data[3] = 0xDD; - } -#else /* OPENBSD and DARWIN(utun) */ + } +#elif defined (FREEBSD) || defined (OPENBSD) + // BSDs prefix with 32 bits address family // AF_INET for IPv4, AF_INET6 for IPv6 - if (i == 64) { + if (ip_version == 4) { data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; data[3] = 0x02; - } else { /* 96 for IPV6 */ + } else { /* IPV6 */ data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = 0x1E; + data[3] = 0x1C; } + +#elif defined NETBSD + + // BSDs prefix with 32 bits address family + // AF_INET for IPv4, AF_INET6 for IPv6 + if (ip_version == 4) { + data[0] = 0x00; + data[1] = 0x00; + data[2] = 0x00; + data[3] = 0x02; + } else { /* IPV6 */ + data[0] = 0x00; + data[1] = 0x00; + data[2] = 0x00; + data[3] = 0x18; + + } +#else /* DARWIN(utun) and all others */ + + // BSDs prefix with 32 bits address family + // AF_INET for IPv4, AF_INET6 for IPv6 + if (ip_version == 4) { + data[0] = 0x00; + data[1] = 0x00; + data[2] = 0x00; + data[3] = 0x02; + } else { /* IPV6 */ + data[0] = 0x00; + data[1] = 0x00; + data[2] = 0x00; + data[3] = 0x1E; + } #endif } @@ -610,14 +668,12 @@ read_tun(int tun_fd, char *buf, size_t len) #endif int -tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) +tun_setip(const char *ip, const char *other_ip, int netbits) { char cmdline[512]; - char v6_cmdline[512]; int netmask; struct in_addr net; int i; - int v6_r; #ifndef LINUX int r; #endif @@ -650,20 +706,7 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) # else display_ip = ip; # endif - if (forward_v6) { - fprintf(stderr, "Setting IPv6 of %s to ::%s\n", if_name, ip); - - snprintf(v6_cmdline, sizeof(cmdline), - IFCONFIGPATH "ifconfig %s inet6 add ::%s/64", - if_name, - display_ip); - v6_r = system(v6_cmdline); - - if (v6_r != 0) { - return v6_r; - } - } snprintf(cmdline, sizeof(cmdline), IFCONFIGPATH "ifconfig %s %s %s netmask %s", if_name, @@ -722,14 +765,89 @@ tun_setip(const char *ip, const char *other_ip, int netbits, int forward_v6) return system(cmdline); #endif - if (forward_v6) { - snprintf(cmdline, sizeof(cmdline), - IFCONFIGPATH "ifconfig %s inet6 add ::%s/64", - if_name, - ip); +} + +int +tun_setip6(char *display_ip6, const char *display_other_ip6, int netbits6) +{ + int v6_r; + struct in6_addr ip6; + char v6_cmdline[512]; + if (inet_pton(AF_INET6, display_ip6, &ip6) < 1){ + warnx("Error in IPv6 address"); + } + +#ifdef WINDOWS32 + /* + DWORD status; + DWORD ipdata[3]; + struct in_addr addr; + DWORD len; + */ +#endif + + if (netbits6 > 0) { + + fprintf(stderr, "Setting IPv6 of %s to %s\n", if_name, display_ip6); - fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip); +#if defined LINUX + snprintf(v6_cmdline, sizeof(v6_cmdline), + IFCONFIGPATH "ifconfig %s inet6 add %s/%d", + if_name, + display_ip6, netbits6); +#else + snprintf(v6_cmdline, sizeof(v6_cmdline), + IFCONFIGPATH "ifconfig %s inet6 %s/%d", + if_name, + display_ip6, netbits6); +#endif + + v6_r = system(v6_cmdline); + + if (v6_r != 0) { + return v6_r; + } else { + return 0; + } } + +#ifdef WINDOWS32 /* WINDOWS32 */ + + /* Set device as connected */ + fprintf(stderr, "Enabling interface '%s'\n", if_name); + status = 1; + r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, + sizeof(status), &status, sizeof(status), &len, NULL); + if (!r) { + fprintf(stderr, "Failed to enable interface\n"); + return -1; + } + + if (inet_aton(ip, &addr)) { + ipdata[0] = (DWORD) addr.s_addr; /* local ip addr */ + ipdata[1] = net.s_addr & ipdata[0]; /* network addr */ + ipdata[2] = (DWORD) net.s_addr; /* netmask */ + } else { + return -1; + } + + /* Tell ip/networkaddr/netmask to device for arp use */ + r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata, + sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL); + if (!r) { + fprintf(stderr, "Failed to set interface in TUN mode\n"); + return -1; + } + + /* use netsh to set ip address */ + fprintf(stderr, "Setting IP of interface '%s' to %s (can take a few seconds)...\n", if_name, ip); + snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address \"%s\" static %s %s", + if_name, ip, inet_ntoa(net)); + return system(cmdline); + + +#endif + return 0; } int @@ -757,3 +875,18 @@ tun_setmtu(const unsigned mtu) #endif } +int get_ipversion(char first_byte) +{ + + int v; + + v = first_byte & 0xf0; + + if (v == 64) { + return 4; + } else if (v == 96) { + return 6; + } else { + return -1; + } +} diff --git a/src/tun.h b/src/tun.h index a57c007e..43049ea8 100644 --- a/src/tun.h +++ b/src/tun.h @@ -22,7 +22,9 @@ int open_tun(const char *); void close_tun(int); int write_tun(int, char *, size_t); ssize_t read_tun(int, char *, size_t); -int tun_setip(const char *, const char *, int, int); +int tun_setip(const char *, const char *, int); +int tun_setip6(char *, const char *, int); int tun_setmtu(const unsigned); +int get_ipversion(char); #endif /* _TUN_H_ */ diff --git a/src/user.c b/src/user.c index 253694ec..8978165d 100644 --- a/src/user.c +++ b/src/user.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef WINDOWS32 #include @@ -37,25 +38,26 @@ struct tun_user *users; unsigned usercount; -int init_users(in_addr_t my_ip, int netbits) +int init_users(in_addr_t my_ip, int netbits, struct in6_addr my_ip6, int netbits6) { int i; + int i6; int skip = 0; + int skip6 = 0; char newip[16]; - char ip6Tmp[16]; - char ip6Tmp2[18]; 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. - */ + struct in6_addr ip6start; + unsigned ip6_netmask[16]; + bool ip6_enabled; + + ip6_enabled = isV6AddrSet(&my_ip6); + for (i = 0; i < netbits; i++) { netmask = (netmask << 1) | 1; } @@ -63,17 +65,39 @@ int init_users(in_addr_t my_ip, int netbits) net.s_addr = htonl(netmask); ipstart.s_addr = my_ip & net.s_addr; + /* Covert IPv6 netbits to IPv6 netmask and work + * out the network address from my IP address. Start + * assigning IPv6 address from the network address + 1 + */ + if (ip6_enabled == true) { + for (i6 = 0; i6 < netbits6 / 8; i6++) { + ip6_netmask[i6] |= 0xFF; + } + + ip6_netmask[netbits6 / 8] = pow(2, (netbits6 % 8 )) - 1; + ip6_netmask[netbits6 / 8] <<= (8-(netbits6 % 8)); + + for (i6 = 0; i6 < 16; i6++) { + ip6start.s6_addr[i6] = my_ip6.s6_addr[i6] & ip6_netmask[i6]; + } + } maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */ usercount = MIN(maxusers, USERS); users = calloc(usercount, sizeof(struct tun_user)); + /* + * IPv6 note: Current behavior is to populate the users structure + * with the IPv4 addresses that are expected to be used. + * In the future with IPv6-only tunnel transport, we should not be + * populating a /64 (or whatever mask) in the users structure + * and should shift to an on-demand scheme. For now + * we expect dual-stack and pre-allocate IPv6 addresses into the + * users struct as we do with IPv4. + */ for (i = 0; i < usercount; i++) { in_addr_t ip; users[i].id = i; - memset(ip6Tmp,0,strlen(ip6Tmp)); - memset(ip6Tmp2,0,strlen(ip6Tmp2)); - snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); ip = ipstart.s_addr + inet_addr(newip); @@ -82,15 +106,36 @@ 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); - } users[i].tun_ip = ip; - inet_ntop(AF_INET, &ip, ip6Tmp, INET_ADDRSTRLEN); - snprintf(ip6Tmp2, sizeof(ip6Tmp2), "::%s", ip6Tmp); - inet_pton(AF_INET6, ip6Tmp2, &users[i].tun_ip6); - + if (ip6_enabled == true) { + struct in6_addr temp_ip6; + /* + * start assigning host addresses from the network address + 1 + * unless that is my_ip, in which case, use the following address. + */ + memcpy(temp_ip6.s6_addr, ip6start.s6_addr, sizeof(ip6start.s6_addr)); + temp_ip6.s6_addr[15] = ip6start.s6_addr[15] + skip + 1 + i; + + if (v6AddressesEqual(&temp_ip6, &my_ip6) == true && + skip6 == 0) { + /* This IPv6 was taken by iodined */ + skip6++; + + /* + * We expect to start assigning addresses at the network address + 1 and + * to not worry about assigning more than 254 host addresses. If we did, we have to + * iterate through lower order bytes of ip6. This plus a few other corner cases + * is why we enourage/force/assume the user to specify a /64 V6 address + */ + + temp_ip6.s6_addr[15] = ip6start.s6_addr[15] + skip + 1 + i; + + } + memcpy(users[i].tun_ip6.s6_addr, temp_ip6.s6_addr, sizeof(temp_ip6.s6_addr)); + } net.s_addr = ip; users[i].disabled = 0; users[i].authenticated = 0; @@ -110,6 +155,18 @@ const char *users_get_first_ip(void) return strdup(inet_ntoa(ip)); } +const char *users_get_first_ip6(void) +{ + struct in6_addr ip6; + char display_ip6[INET6_ADDRSTRLEN]; + + memcpy(&ip6, &users[0].tun_ip6, sizeof(struct in6_addr)); + + inet_ntop(AF_INET6, &ip6, display_ip6, INET6_ADDRSTRLEN); + return strdup(display_ip6); +} + + int find_user_by_ip6(struct in6_addr *v6Addr) { int i; @@ -122,23 +179,23 @@ int find_user_by_ip6(struct in6_addr *v6Addr) users[i].authenticated && !users[i].disabled && users[i].last_pkt + 60 > time(NULL) && - (areV6AddressesEqual(v6Addr, &users[i].tun_ip6) == 0) ) { + v6AddressesEqual(v6Addr, &users[i].tun_ip6) == true) { return i; - } + } } return -1; } -int areV6AddressesEqual(struct in6_addr *v6Struct1, struct in6_addr *v6Struct2) +bool v6AddressesEqual(struct in6_addr *v6Struct1, struct in6_addr *v6Struct2) { int i; for (i = 0; i < 16; i++) { if (v6Struct1->s6_addr[i] != v6Struct2->s6_addr[i]) { - return -1; + return false; } } - return 0; + return true; } diff --git a/src/user.h b/src/user.h index bf160a63..4d1d2ad6 100644 --- a/src/user.h +++ b/src/user.h @@ -81,14 +81,15 @@ struct tun_user { extern struct tun_user *users; -int init_users(in_addr_t, int); +int init_users(in_addr_t, int, struct in6_addr, int); const char* users_get_first_ip(void); +const char* users_get_first_ip6(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 *); +bool v6AddressesEqual(struct in6_addr *, struct in6_addr *); #endif From ab7e5b865604d37c21085bbeca610dc14ae3aa92 Mon Sep 17 00:00:00 2001 From: Chris Hellberg Date: Mon, 9 May 2022 01:02:23 +0000 Subject: [PATCH 17/17] Updated README with IPv6 details and fixed a bug with IPV6 only enabled on one end of the tunnelx --- README.md | 10 +++++++++- src/client.c | 49 +++++++++++++++++++++++++++---------------------- src/iodined.c | 33 +++++++++++++++++++-------------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 179872d0..67875047 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ end of the tunnel. In this case, `ping 192.168.99.1` from the iodine client, and ### MISC. INFO #### IPv6 -The data inside the tunnel is IPv4 only. +The data inside the tunnel may be IPv4 or IPv6. The server listens to both IPv4 and IPv6 for incoming requests by default. Use options `-4` or `-6` to only listen on one protocol. Raw mode will be @@ -141,6 +141,14 @@ to your DNS setup. Extending the example above would look like this: t1ns IN A 10.15.213.99 t1ns IN AAAA 2001:db8::1001:99 +On the server, specify -S followed by an IPv6 address that will be the server end +of the IPv6 pool to allocate to clients. The server only supports a /64 subnet +mask, which is assumed and can be omitted. The first 64 bits are the network from +which IPv6 addresses are allocated from. + +The client will automatically check for IPv6 capability on the server and +assign the allocated address to its tunnel interface. No flags are needed. + #### Routing It is possible to route all traffic through the DNS tunnel. To do this, first add a host route to the nameserver used by iodine over the wired/wireless diff --git a/src/client.c b/src/client.c index 8261b689..39ee20b6 100644 --- a/src/client.c +++ b/src/client.c @@ -2440,44 +2440,49 @@ int handshake_check_v6(int dns_fd) { char in[4096]; - char server6[1024]; - char client6[1024]; + char server6[INET6_ADDRSTRLEN]; + char client6[INET6_ADDRSTRLEN]; int i; int read; int netmask6 = 0; + int length_recieved; fprintf(stderr, "Autoprobing server IPV6 tunnel support\n"); for (i = 0; running && i < 5; i++) { - send_v6_probe(dns_fd); + send_v6_probe(dns_fd); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'g', 'G', i+1); + read = handshake_waitdns(dns_fd, in, sizeof(in), 'g', 'G', i+1); if (read > 0) { - /* - * including a terminating dash to allow for future IPv6 options, e.g. - * netmask. Currently assumes /64. MTU is taken from the IPv4 handshake. - * A future IPv6-only implementation would need to pass mtu - * in the IPV6 handshake. - */ + /* + * including a terminating dash to allow for future IPv6 options, e.g. + * netmask. Currently assumes /64. MTU is taken from the IPv4 handshake. + * A future IPv6-only implementation would need to pass mtu + * in the IPV6 handshake. + */ - if (sscanf(in, "%512[^-]-%512[^-]-%d", server6, client6, &netmask6) == 3) { + if (sscanf(in, "%512[^-]-%512[^-]-%d", server6, client6, &netmask6) == 3) { - fprintf(stderr, "Server tunnel IPv6 is %s\n", server6); - fprintf(stderr, "Local tunnel IPv6 is %s\n", client6); + fprintf(stderr, "Server tunnel IPv6 is %s\n", server6); + fprintf(stderr, "Local tunnel IPv6 is %s\n", client6); - if (tun_setip6(client6, server6, netmask6) == 0) { + length_recieved = strlen(client6); + if (length_recieved > 2) { + if (tun_setip6(client6, server6, netmask6) == 0) { - use_v6 = true; - return 0; - } else { - errx(4, "Failed to set IPv6 tunnel address"); - } - } else { - fprintf(stderr, "Received bad IPv6 tunnel handshake\n"); - } + use_v6 = true; + return 0; + + } else { + errx(4, "Failed to set IPv6 tunnel address"); + } + } else { + fprintf(stderr, "Received bad IPv6 tunnel handshake\n"); + } + } } fprintf(stderr, "Retrying IPv6 tunnel handshake...\n"); diff --git a/src/iodined.c b/src/iodined.c index cb6f803c..9add3ad6 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -90,8 +90,8 @@ static int my_mtu; static in_addr_t my_ip; char display_ip6[INET6_ADDRSTRLEN]; -char *display_ip6_buffer; -char *ip6_netmask_buffer; +char *display_ip6_buffer = NULL; +char *ip6_netmask_buffer = NULL; static struct in6_addr my_ip6; static int netmask; @@ -2590,21 +2590,25 @@ main(int argc, char **argv) } - ip6_netmask_buffer = strchr(display_ip6_buffer, '/'); - if (ip6_netmask_buffer) { - if (atoi(ip6_netmask_buffer+1) != ip6_netmask) { - warnx("IPv6 address must be a 64-bit mask."); - usage(); + if (display_ip6_buffer != NULL) { + + ip6_netmask_buffer = strchr(display_ip6_buffer, '/'); + + if (ip6_netmask_buffer != NULL) { + if (atoi(ip6_netmask_buffer+1) != ip6_netmask) { + warnx("IPv6 address must be a 64-bit mask."); + usage(); } /* remove masklen */ memcpy(display_ip6, display_ip6_buffer, strlen(display_ip6_buffer) - strlen(ip6_netmask_buffer)); display_ip6[strlen(display_ip6)+1] = '\0'; - } + } - /* IPV6 address sanity check */ - if (inet_pton(AF_INET6, display_ip6, &my_ip6) != 1) { + /* IPV6 address sanity check */ + if (inet_pton(AF_INET6, display_ip6, &my_ip6) != 1) { warnx("Bad IPv6 address to use inside tunnel."); usage(); + } } topdomain = strdup(argv[1]); @@ -2753,10 +2757,11 @@ main(int argc, char **argv) } - if (tun_setip6(display_ip6, display_other_ip6, ip6_netmask) != 0 ) { - retval = 1; - goto cleanup; - + if (display_ip6_buffer != NULL) { + if (tun_setip6(display_ip6, display_other_ip6, ip6_netmask) != 0 ) { + retval = 1; + goto cleanup; + } } if ((mtu < 1280) && (sizeof(display_ip6)) != 0) {