1
0
mirror of https://github.com/yarrick/iodine.git synced 2024-11-25 06:26:05 +03:00

further IPv6 changes

This commit is contained in:
Chris Hellberg 2022-05-08 19:45:32 +00:00
parent 3eb959c8fe
commit 846082f13e
11 changed files with 427 additions and 94 deletions

View File

@ -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

View File

@ -28,6 +28,8 @@
#include <fcntl.h>
#include <zlib.h>
#include <time.h>
#include <stdbool.h>
#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;
}

View File

@ -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

View File

@ -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 <time.h>
@ -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;
}

View File

@ -33,6 +33,7 @@
extern const unsigned char raw_header[RAW_HDR_LEN];
#include <stdarg.h>
#include <stdbool.h>
#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

View File

@ -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;
}

View File

@ -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);
}

205
src/tun.c
View File

@ -35,6 +35,11 @@
#include <netinet/ip.h>
#endif
#if defined FREEBSD || defined NETBSD
#include <sys/ioctl.h>
#include <net/if_tun.h>
#endif
#ifndef IFCONFIGPATH
#define IFCONFIGPATH "PATH=/sbin:/bin "
#endif
@ -82,6 +87,7 @@ static char if_name[250];
#include <net/if.h>
#include <linux/if_tun.h>
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,41 +561,82 @@ 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] = 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);
}
fprintf(stderr, "Setting IP of %s to %s\n", 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);
#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;
}
}

View File

@ -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_ */

View File

@ -23,6 +23,7 @@
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#ifdef WINDOWS32
#include <winsock2.h>
@ -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;
}

View File

@ -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