;;
FreeBSD)
- paths="$paths src/linux src/bsd/tunemu.c"
+ paths="$paths src/linux src/bsd/darwin src/bsd/openbsd"
;;
Darwin)
--- /dev/null
+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
+
--- /dev/null
+/*
+ * tunemu - Tun device emulation for Darwin
+ * Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tunemu.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <util.h>
+#include <pcap.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#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;
+}
--- /dev/null
+/*
+ * tunemu - Tun device emulation for Darwin
+ * Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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
#include "../xalloc.h"
#ifdef ENABLE_TUNEMU
-#include "tunemu.h"
+#include "darwin/tunemu.h"
#endif
#ifdef HAVE_NET_IF_UTUN_H
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
+++ /dev/null
-/*
- * tunemu - Tun device emulation for Darwin
- * Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "tunemu.h"
-
-#include <sys/socket.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <memory.h>
-#include <util.h>
-#include <pcap.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdint.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#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;
-}
+++ /dev/null
-/*
- * tunemu - Tun device emulation for Darwin
- * Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#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