X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fbsd%2Ftunemu.c;fp=src%2Fbsd%2Ftunemu.c;h=0000000000000000000000000000000000000000;hb=1c1ea3e501944f1e49cb65add689d9cd6dea8af6;hp=1ce9007491fd377d20b11d01142b9c6845be4690;hpb=7f7b53dc2011fc8ceda1e0678d9f78b1dbd8c1d1;p=meshlink diff --git a/src/bsd/tunemu.c b/src/bsd/tunemu.c deleted file mode 100644 index 1ce90074..00000000 --- a/src/bsd/tunemu.c +++ /dev/null @@ -1,386 +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 -{ - u_int8_t ppp_len; - u_int8_t ppp_family; - u_int16_t ppp_proto; - u_int32_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 int data_buffer_length = 0; -static char *data_buffer = NULL; - -static void tun_error(char *format, ...) -{ - va_list vl; - va_start(vl, format); - vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, 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(int 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; -} - -int tunemu_read(int ppp_sockfd, char *buffer, int length) -{ - allocate_data_buffer(length + 2); - - length = read(ppp_sockfd, data_buffer, length + 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; -} - -int tunemu_write(int ppp_sockfd, char *buffer, int length) -{ - allocate_data_buffer(length + 4); - - data_buffer[0] = 0x02; - data_buffer[1] = 0x00; - data_buffer[2] = 0x00; - data_buffer[3] = 0x00; - - memcpy(data_buffer + 4, buffer, length); - - if (pcap == NULL) - { - tun_error("pcap not open"); - return -1; - } - - length = pcap_inject(pcap, data_buffer, length + 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; -}