From: Kirill Isakov Date: Mon, 2 May 2022 07:00:13 +0000 (+0600) Subject: Move macOS-specific code into a subdirectory X-Git-Url: https://www.tinc-vpn.org/git/?a=commitdiff_plain;h=f86a5f1d70206321b01ec60f6a69f8cbf1a2b732;p=tinc Move macOS-specific code into a subdirectory --- diff --git a/.ci/tidy/run.sh b/.ci/tidy/run.sh index cf055568..a2439f7d 100755 --- a/.ci/tidy/run.sh +++ b/.ci/tidy/run.sh @@ -13,7 +13,7 @@ Linux) ;; FreeBSD) - paths="$paths src/linux src/bsd/tunemu.c" + paths="$paths src/linux src/bsd/darwin src/bsd/openbsd" ;; Darwin) diff --git a/src/bsd/darwin/meson.build b/src/bsd/darwin/meson.build new file mode 100644 index 00000000..5672fcd0 --- /dev/null +++ b/src/bsd/darwin/meson.build @@ -0,0 +1,9 @@ +dep_tunemu = dependency('tunemu', required: opt_tunemu, static: static) +dep_pcap = dependency('pcap', required: opt_tunemu, static: static) + +if dep_tunemu.found() and dep_pcap.found() + deps_tincd += [dep_tunemu, dep_pcap] + src_tincd += files('tunemu.c') + cdata.set('ENABLE_TUNEMU', 1) +endif + diff --git a/src/bsd/darwin/tunemu.c b/src/bsd/darwin/tunemu.c new file mode 100644 index 00000000..4e3fbc7d --- /dev/null +++ b/src/bsd/darwin/tunemu.c @@ -0,0 +1,378 @@ +/* + * tunemu - Tun device emulation for Darwin + * Copyright (C) 2009 Friedrich Schöller + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "tunemu.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPPPROTO_CTL 1 + +#define PPP_IP 0x21 +#define PPP_IPV6 0x57 + +#define SC_LOOP_TRAFFIC 0x00000200 + +#define PPPIOCNEWUNIT _IOWR('t', 62, int) +#define PPPIOCSFLAGS _IOW('t', 89, int) +#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) +#define PPPIOCATTCHAN _IOW('t', 56, int) +#define PPPIOCGCHAN _IOR('t', 55, int) +#define PPPIOCCONNECT _IOW('t', 58, int) +#define PPPIOCGUNIT _IOR('t', 86, int) + +struct sockaddr_ppp { + uint8_t ppp_len; + uint8_t ppp_family; + uint16_t ppp_proto; + uint32_t ppp_cookie; +}; + +enum NPmode { + NPMODE_PASS, + NPMODE_DROP, + NPMODE_ERROR, + NPMODE_QUEUE +}; + +struct npioctl { + int protocol; + enum NPmode mode; +}; + +#define PPP_KEXT_PATH "/System/Library/Extensions/PPP.kext" + +#define ERROR_BUFFER_SIZE 1024 + +char tunemu_error[ERROR_BUFFER_SIZE]; + +static int pcap_use_count = 0; +static pcap_t *pcap = NULL; + +static size_t data_buffer_length = 0; +static uint8_t *data_buffer = NULL; + +static void tun_error(char *format, ...) ATTR_FORMAT(printf, 1, 2); +static void tun_error(char *format, ...) { + va_list vl; + va_start(vl, format); + vsnprintf(tunemu_error, sizeof(tunemu_error), format, vl); + va_end(vl); +} + +static void tun_noerror() { + *tunemu_error = 0; +} + +static void closeall() { + int fd = getdtablesize(); + + while(fd--) { + close(fd); + } + + open("/dev/null", O_RDWR, 0); + dup(0); + dup(0); +} + +static int ppp_load_kext() { + int pid = fork(); + + if(pid < 0) { + tun_error("fork for ppp kext: %s", strerror(errno)); + return -1; + } + + if(pid == 0) { + closeall(); + execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL); + exit(1); + } + + int status; + + while(waitpid(pid, &status, 0) < 0) { + if(errno == EINTR) { + continue; + } + + tun_error("waitpid for ppp kext: %s", strerror(errno)); + return -1; + } + + if(WEXITSTATUS(status) != 0) { + tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH); + return -1; + } + + tun_noerror(); + return 0; +} + +static int ppp_new_instance() { + // create ppp socket + int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); + + if(ppp_sockfd < 0) { + if(ppp_load_kext() < 0) { + return -1; + } + + ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); + + if(ppp_sockfd < 0) { + tun_error("creating ppp socket: %s", strerror(errno)); + return -1; + } + } + + // connect to ppp procotol + struct sockaddr_ppp pppaddr; + pppaddr.ppp_len = sizeof(struct sockaddr_ppp); + pppaddr.ppp_family = AF_PPP; + pppaddr.ppp_proto = PPPPROTO_CTL; + pppaddr.ppp_cookie = 0; + + if(connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) { + tun_error("connecting ppp socket: %s", strerror(errno)); + close(ppp_sockfd); + return -1; + } + + tun_noerror(); + return ppp_sockfd; +} + +static int ppp_new_unit(int *unit_number) { + int fd = ppp_new_instance(); + + if(fd < 0) { + return -1; + } + + // create ppp unit + if(ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) { + tun_error("creating ppp unit: %s", strerror(errno)); + close(fd); + return -1; + } + + tun_noerror(); + return fd; +} + +static int ppp_setup_unit(int unit_fd) { + // send traffic to program + int flags = SC_LOOP_TRAFFIC; + + if(ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) { + tun_error("setting ppp loopback mode: %s", strerror(errno)); + return -1; + } + + // allow packets + struct npioctl npi; + npi.protocol = PPP_IP; + npi.mode = NPMODE_PASS; + + if(ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) { + tun_error("starting ppp unit: %s", strerror(errno)); + return -1; + } + + tun_noerror(); + return 0; +} + +static int open_pcap() { + if(pcap != NULL) { + pcap_use_count++; + return 0; + } + + char errbuf[PCAP_ERRBUF_SIZE]; + pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf); + pcap_use_count = 1; + + if(pcap == NULL) { + tun_error("opening pcap: %s", errbuf); + return -1; + } + + tun_noerror(); + return 0; +} + +static void close_pcap() { + if(pcap == NULL) { + return; + } + + pcap_use_count--; + + if(pcap_use_count == 0) { + pcap_close(pcap); + pcap = NULL; + } +} + +static void allocate_data_buffer(size_t size) { + if(data_buffer_length < size) { + free(data_buffer); + data_buffer_length = size; + data_buffer = malloc(data_buffer_length); + } +} + +static void make_device_name(tunemu_device device, int unit_number) { + snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number); +} + +static int check_device_name(tunemu_device device) { + if(strlen(device) < 4) { + return -1; + } + + int unit_number = atoi(device + 3); + + if(unit_number < 0 || unit_number > 999) { + return -1; + } + + tunemu_device compare; + make_device_name(compare, unit_number); + + if(strcmp(device, compare) != 0) { + return -1; + } + + return 0; +} + +int tunemu_open(tunemu_device device) { + int ppp_unit_number = -1; + + if(device[0] != 0) { + if(check_device_name(device) < 0) { + tun_error("invalid device name \"%s\"", device); + return -1; + } + + ppp_unit_number = atoi(device + 3); + } + + int ppp_unit_fd = ppp_new_unit(&ppp_unit_number); + + if(ppp_unit_fd < 0) { + return -1; + } + + if(ppp_setup_unit(ppp_unit_fd) < 0) { + close(ppp_unit_fd); + return -1; + } + + if(open_pcap() < 0) { + close(ppp_unit_fd); + return -1; + } + + make_device_name(device, ppp_unit_number); + + return ppp_unit_fd; +} + +int tunemu_close(int ppp_sockfd) { + int ret = close(ppp_sockfd); + + if(ret == 0) { + close_pcap(); + } + + return ret; +} + +ssize_t tunemu_read(int ppp_sockfd, uint8_t *buffer, size_t buflen) { + allocate_data_buffer(buflen + 2); + + ssize_t length = read(ppp_sockfd, data_buffer, buflen + 2); + + if(length < 0) { + tun_error("reading packet: %s", strerror(errno)); + return length; + } + + tun_noerror(); + + length -= 2; + + if(length < 0) { + return 0; + } + + memcpy(buffer, data_buffer + 2, length); + + return length; +} + +ssize_t tunemu_write(uint8_t *buffer, size_t buflen) { + allocate_data_buffer(buflen + 4); + + data_buffer[0] = 0x02; + data_buffer[1] = 0x00; + data_buffer[2] = 0x00; + data_buffer[3] = 0x00; + + memcpy(data_buffer + 4, buffer, buflen); + + if(pcap == NULL) { + tun_error("pcap not open"); + return -1; + } + + ssize_t length = pcap_inject(pcap, data_buffer, buflen + 4); + + if(length < 0) { + tun_error("injecting packet: %s", pcap_geterr(pcap)); + return length; + } + + tun_noerror(); + + length -= 4; + + if(length < 0) { + return 0; + } + + return length; +} diff --git a/src/bsd/darwin/tunemu.h b/src/bsd/darwin/tunemu.h new file mode 100644 index 00000000..9f9edb01 --- /dev/null +++ b/src/bsd/darwin/tunemu.h @@ -0,0 +1,34 @@ +/* + * tunemu - Tun device emulation for Darwin + * Copyright (C) 2009 Friedrich Schöller + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef TUNEMU_H +#define TUNEMU_H + +#include "../../system.h" + +typedef char tunemu_device[7]; + +extern char tunemu_error[]; + +int tunemu_open(tunemu_device dev); +int tunemu_close(int fd); +ssize_t tunemu_read(int fd, uint8_t *buffer, size_t buflen); +ssize_t tunemu_write(uint8_t *buffer, size_t buflen); + +#endif diff --git a/src/bsd/device.c b/src/bsd/device.c index badd77d7..c0642f57 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -28,7 +28,7 @@ #include "../xalloc.h" #ifdef ENABLE_TUNEMU -#include "tunemu.h" +#include "darwin/tunemu.h" #endif #ifdef HAVE_NET_IF_UTUN_H diff --git a/src/bsd/meson.build b/src/bsd/meson.build index d6205f4f..e6062dc8 100644 --- a/src/bsd/meson.build +++ b/src/bsd/meson.build @@ -13,18 +13,7 @@ check_functions += [ src_tincd += files('device.c') -if os_name == 'openbsd' - subdir('openbsd') -endif - -if os_name == 'darwin' - dep_tunemu = dependency('tunemu', required: opt_tunemu, static: static) - dep_pcap = dependency('pcap', required: opt_tunemu, static: static) - - if dep_tunemu.found() and dep_pcap.found() - deps_tincd += [dep_tunemu, dep_pcap] - src_tincd += files('tunemu.c') - cdata.set('ENABLE_TUNEMU', 1) - endif +if os_name in ['openbsd', 'darwin'] + subdir(os_name) endif diff --git a/src/bsd/tunemu.c b/src/bsd/tunemu.c deleted file mode 100644 index 4e3fbc7d..00000000 --- a/src/bsd/tunemu.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * tunemu - Tun device emulation for Darwin - * Copyright (C) 2009 Friedrich Schöller - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#include "tunemu.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PPPPROTO_CTL 1 - -#define PPP_IP 0x21 -#define PPP_IPV6 0x57 - -#define SC_LOOP_TRAFFIC 0x00000200 - -#define PPPIOCNEWUNIT _IOWR('t', 62, int) -#define PPPIOCSFLAGS _IOW('t', 89, int) -#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) -#define PPPIOCATTCHAN _IOW('t', 56, int) -#define PPPIOCGCHAN _IOR('t', 55, int) -#define PPPIOCCONNECT _IOW('t', 58, int) -#define PPPIOCGUNIT _IOR('t', 86, int) - -struct sockaddr_ppp { - uint8_t ppp_len; - uint8_t ppp_family; - uint16_t ppp_proto; - uint32_t ppp_cookie; -}; - -enum NPmode { - NPMODE_PASS, - NPMODE_DROP, - NPMODE_ERROR, - NPMODE_QUEUE -}; - -struct npioctl { - int protocol; - enum NPmode mode; -}; - -#define PPP_KEXT_PATH "/System/Library/Extensions/PPP.kext" - -#define ERROR_BUFFER_SIZE 1024 - -char tunemu_error[ERROR_BUFFER_SIZE]; - -static int pcap_use_count = 0; -static pcap_t *pcap = NULL; - -static size_t data_buffer_length = 0; -static uint8_t *data_buffer = NULL; - -static void tun_error(char *format, ...) ATTR_FORMAT(printf, 1, 2); -static void tun_error(char *format, ...) { - va_list vl; - va_start(vl, format); - vsnprintf(tunemu_error, sizeof(tunemu_error), format, vl); - va_end(vl); -} - -static void tun_noerror() { - *tunemu_error = 0; -} - -static void closeall() { - int fd = getdtablesize(); - - while(fd--) { - close(fd); - } - - open("/dev/null", O_RDWR, 0); - dup(0); - dup(0); -} - -static int ppp_load_kext() { - int pid = fork(); - - if(pid < 0) { - tun_error("fork for ppp kext: %s", strerror(errno)); - return -1; - } - - if(pid == 0) { - closeall(); - execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL); - exit(1); - } - - int status; - - while(waitpid(pid, &status, 0) < 0) { - if(errno == EINTR) { - continue; - } - - tun_error("waitpid for ppp kext: %s", strerror(errno)); - return -1; - } - - if(WEXITSTATUS(status) != 0) { - tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH); - return -1; - } - - tun_noerror(); - return 0; -} - -static int ppp_new_instance() { - // create ppp socket - int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); - - if(ppp_sockfd < 0) { - if(ppp_load_kext() < 0) { - return -1; - } - - ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); - - if(ppp_sockfd < 0) { - tun_error("creating ppp socket: %s", strerror(errno)); - return -1; - } - } - - // connect to ppp procotol - struct sockaddr_ppp pppaddr; - pppaddr.ppp_len = sizeof(struct sockaddr_ppp); - pppaddr.ppp_family = AF_PPP; - pppaddr.ppp_proto = PPPPROTO_CTL; - pppaddr.ppp_cookie = 0; - - if(connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) { - tun_error("connecting ppp socket: %s", strerror(errno)); - close(ppp_sockfd); - return -1; - } - - tun_noerror(); - return ppp_sockfd; -} - -static int ppp_new_unit(int *unit_number) { - int fd = ppp_new_instance(); - - if(fd < 0) { - return -1; - } - - // create ppp unit - if(ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) { - tun_error("creating ppp unit: %s", strerror(errno)); - close(fd); - return -1; - } - - tun_noerror(); - return fd; -} - -static int ppp_setup_unit(int unit_fd) { - // send traffic to program - int flags = SC_LOOP_TRAFFIC; - - if(ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) { - tun_error("setting ppp loopback mode: %s", strerror(errno)); - return -1; - } - - // allow packets - struct npioctl npi; - npi.protocol = PPP_IP; - npi.mode = NPMODE_PASS; - - if(ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) { - tun_error("starting ppp unit: %s", strerror(errno)); - return -1; - } - - tun_noerror(); - return 0; -} - -static int open_pcap() { - if(pcap != NULL) { - pcap_use_count++; - return 0; - } - - char errbuf[PCAP_ERRBUF_SIZE]; - pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf); - pcap_use_count = 1; - - if(pcap == NULL) { - tun_error("opening pcap: %s", errbuf); - return -1; - } - - tun_noerror(); - return 0; -} - -static void close_pcap() { - if(pcap == NULL) { - return; - } - - pcap_use_count--; - - if(pcap_use_count == 0) { - pcap_close(pcap); - pcap = NULL; - } -} - -static void allocate_data_buffer(size_t size) { - if(data_buffer_length < size) { - free(data_buffer); - data_buffer_length = size; - data_buffer = malloc(data_buffer_length); - } -} - -static void make_device_name(tunemu_device device, int unit_number) { - snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number); -} - -static int check_device_name(tunemu_device device) { - if(strlen(device) < 4) { - return -1; - } - - int unit_number = atoi(device + 3); - - if(unit_number < 0 || unit_number > 999) { - return -1; - } - - tunemu_device compare; - make_device_name(compare, unit_number); - - if(strcmp(device, compare) != 0) { - return -1; - } - - return 0; -} - -int tunemu_open(tunemu_device device) { - int ppp_unit_number = -1; - - if(device[0] != 0) { - if(check_device_name(device) < 0) { - tun_error("invalid device name \"%s\"", device); - return -1; - } - - ppp_unit_number = atoi(device + 3); - } - - int ppp_unit_fd = ppp_new_unit(&ppp_unit_number); - - if(ppp_unit_fd < 0) { - return -1; - } - - if(ppp_setup_unit(ppp_unit_fd) < 0) { - close(ppp_unit_fd); - return -1; - } - - if(open_pcap() < 0) { - close(ppp_unit_fd); - return -1; - } - - make_device_name(device, ppp_unit_number); - - return ppp_unit_fd; -} - -int tunemu_close(int ppp_sockfd) { - int ret = close(ppp_sockfd); - - if(ret == 0) { - close_pcap(); - } - - return ret; -} - -ssize_t tunemu_read(int ppp_sockfd, uint8_t *buffer, size_t buflen) { - allocate_data_buffer(buflen + 2); - - ssize_t length = read(ppp_sockfd, data_buffer, buflen + 2); - - if(length < 0) { - tun_error("reading packet: %s", strerror(errno)); - return length; - } - - tun_noerror(); - - length -= 2; - - if(length < 0) { - return 0; - } - - memcpy(buffer, data_buffer + 2, length); - - return length; -} - -ssize_t tunemu_write(uint8_t *buffer, size_t buflen) { - allocate_data_buffer(buflen + 4); - - data_buffer[0] = 0x02; - data_buffer[1] = 0x00; - data_buffer[2] = 0x00; - data_buffer[3] = 0x00; - - memcpy(data_buffer + 4, buffer, buflen); - - if(pcap == NULL) { - tun_error("pcap not open"); - return -1; - } - - ssize_t length = pcap_inject(pcap, data_buffer, buflen + 4); - - if(length < 0) { - tun_error("injecting packet: %s", pcap_geterr(pcap)); - return length; - } - - tun_noerror(); - - length -= 4; - - if(length < 0) { - return 0; - } - - return length; -} diff --git a/src/bsd/tunemu.h b/src/bsd/tunemu.h deleted file mode 100644 index 7dcd2d59..00000000 --- a/src/bsd/tunemu.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * tunemu - Tun device emulation for Darwin - * Copyright (C) 2009 Friedrich Schöller - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#ifndef TUNEMU_H -#define TUNEMU_H - -#include "../system.h" - -typedef char tunemu_device[7]; - -extern char tunemu_error[]; - -int tunemu_open(tunemu_device dev); -int tunemu_close(int fd); -ssize_t tunemu_read(int fd, uint8_t *buffer, size_t buflen); -ssize_t tunemu_write(uint8_t *buffer, size_t buflen); - -#endif