From 8530e4c378a9d4b5d35fcf2807a864c25aed24fc Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 16 Nov 2015 00:43:16 +0100 Subject: [PATCH 1/2] On OSX and BSD, packets sent to the tun interface have to be prefixed by the protocol family --- src/main.c | 127 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 19 deletions(-) diff --git a/src/main.c b/src/main.c index 16fe9b7..00eeebc 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,10 @@ #define GT_BUFFER_SIZE (4*1024*1024) #define GT_TIMEOUT (1000) +#if defined(__APPLE__) || defined(__OpenBSD__) +# define BSD_TUN 1 +#endif + struct netio { int fd; struct { @@ -357,6 +361,31 @@ static void gt_set_signal (void) sigaction(SIGPIPE, &sa, NULL); } +static int get_ip_version (const uint8_t *data, size_t size) +{ + if (size<20) + return -1; + + return data[0]>>4; +} + +static void set_ip_size (uint8_t *data, size_t size) +{ + data[2] = 0xFF&(size>>8); + data[3] = 0xFF&(size); +} + +static ssize_t get_ip_size (const uint8_t *data, size_t size) +{ + switch (get_ip_version(data, size)) { + case 4: + return (data[2]<<8)|data[3]; + case -1: + return -1; + } + return 0; +} + static ssize_t fd_read (int fd, void *data, size_t size) { if (!size) @@ -451,6 +480,83 @@ static ssize_t fd_write_all (int fd, const void *data, size_t size) return done; } +static ssize_t fd_read_tun (int fd, void *data, size_t size) +{ +#ifndef BSD_TUN + return fd_read(fd, data, size); +#else + if (!size) + return -2; + + uint32_t family; + struct iovec iov[2] = { + { .iov_base = &family, .iov_len = sizeof family }, + { .iov_base = data, .iov_len = size } + }; + + ssize_t ret = readv(fd, iov, 2); + + if (ret==-1) { + if (errno==EAGAIN || errno==EINTR) + return -1; + + if (errno) + perror("readv"); + + return 0; + } + if (ret < (ssize_t) sizeof family) + return 0; + + return ret - sizeof family; +#endif +} + +static size_t fd_write_tun (int fd, const void *data, size_t size) +{ +#ifndef BSD_TUN + return fd_write(fd, data, size); +#else + if (!size) + return -2; + + uint32_t family; + + switch (get_ip_version(data, size)) { + case 4: + family = htonl(AF_INET); + break; + case 6: + family = htonl(AF_INET6); + break; + default: + return -1; + } + + struct iovec iov[2] = { + { .iov_base = &family, .iov_len = sizeof family }, + { .iov_base = (void *) data, .iov_len = size }, + }; + + ssize_t ret = writev(fd, iov, 2); + + if (ret==-1) { + if (errno==EAGAIN || errno==EINTR) + return -1; + + if (errno) + perror("writev"); + + return 0; + } + + if (ret < (ssize_t) sizeof family) + return 0; + + return ret - sizeof family; +#endif +} + static int encrypt_packet (struct crypto_ctx *ctx, uint8_t *packet, size_t size, buffer_t *buffer) { const size_t ws = size + crypto_aead_aes256gcm_ABYTES; @@ -519,23 +625,6 @@ static void dump_ip_header (uint8_t *data, size_t size) fprintf(stderr, "DUMP(%zu): %s\n", size, hex); } -static void set_ip_size (uint8_t *data, size_t size) -{ - data[2] = 0xFF&(size>>8); - data[3] = 0xFF&(size); -} - -static ssize_t get_ip_size (const uint8_t *data, size_t size) -{ - if (size<20) - return -1; - - if ((data[0]>>4)==4) - return (data[2]<<8)|data[3]; - - return 0; -} - static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile) { size_t size = sizeof(ctx->skey); @@ -780,7 +869,7 @@ int main (int argc, char **argv) if (buffer_write_size(&sock.write.buf) Date: Mon, 16 Nov 2015 01:51:49 +0100 Subject: [PATCH 2/2] Add support for the native OSX utun interface --- src/main.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index 00eeebc..ef2de46 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,12 @@ # include #endif +#ifdef __APPLE__ +# include +# include +# include +#endif + #include #ifndef O_CLOEXEC @@ -318,18 +324,52 @@ static int tun_create (char *name, int multiqueue) return fd; } +#elif defined(__APPLE__) +static int tun_create (_unused_ char *name, _unused_ int mq) +{ + struct ctl_info ctlInfo; + struct sockaddr_ctl sc; + int fd; + + for (unsigned dev_id = 0U; dev_id<32U; dev_id++) { + byte_set(&ctlInfo, 0, sizeof(ctlInfo)); + str_cpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)); + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (fd==-1) + return -1; + if (ioctl(fd, CTLIOCGINFO, &ctlInfo)==-1) { + close(fd); + continue; + } + sc.sc_id = ctlInfo.ctl_id; + sc.sc_len = sizeof(sc); + sc.sc_family = AF_SYSTEM; + sc.ss_sysaddr = AF_SYS_CONTROL; + sc.sc_unit = dev_id+1; + if (connect(fd, (struct sockaddr *) &sc, sizeof(sc))==-1) { + close(fd); + continue; + } + printf("tun name: /dev/utun%u\n", dev_id); + + return fd; + } + return -1; +} #else static int tun_create (_unused_ char *name, _unused_ int mq) { - for (unsigned dev_id = 0U; dev_id < 32U; dev_id++) { + for (unsigned dev_id = 0U; dev_id<32U; dev_id++) { char dev_path[11U]; snprintf(dev_path, sizeof(dev_path), "/dev/tun%u", dev_id); int fd = open(dev_path, O_RDWR); - if (fd!=-1) + if (fd!=-1) { + printf("tun name: /dev/tun%u\n", dev_id); return fd; + } } return -1; @@ -490,7 +530,7 @@ static ssize_t fd_read_tun (int fd, void *data, size_t size) uint32_t family; struct iovec iov[2] = { - { .iov_base = &family, .iov_len = sizeof family }, + { .iov_base = &family, .iov_len = sizeof(family) }, { .iov_base = data, .iov_len = size } }; @@ -505,10 +545,10 @@ static ssize_t fd_read_tun (int fd, void *data, size_t size) return 0; } - if (ret < (ssize_t) sizeof family) + if (ret<(ssize_t) sizeof(family)) return 0; - return ret - sizeof family; + return ret-sizeof(family); #endif } @@ -534,7 +574,7 @@ static size_t fd_write_tun (int fd, const void *data, size_t size) } struct iovec iov[2] = { - { .iov_base = &family, .iov_len = sizeof family }, + { .iov_base = &family, .iov_len = sizeof(family) }, { .iov_base = (void *) data, .iov_len = size }, }; @@ -550,10 +590,10 @@ static size_t fd_write_tun (int fd, const void *data, size_t size) return 0; } - if (ret < (ssize_t) sizeof family) + if (ret<(ssize_t) sizeof(family)) return 0; - return ret - sizeof family; + return ret-sizeof(family); #endif }