diff --git a/src/main.c b/src/main.c index 16fe9b7..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 @@ -29,6 +35,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 { @@ -314,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; @@ -357,6 +401,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 +520,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 +665,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 +909,7 @@ int main (int argc, char **argv) if (buffer_write_size(&sock.write.buf)