Import Upstream version 1.0.10
This commit is contained in:
parent
5d002cc66a
commit
fa871d431d
152 changed files with 15479 additions and 25408 deletions
165
src/bsd/device.c
165
src/bsd/device.c
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2008 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.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
|
||||
|
|
@ -13,11 +14,9 @@
|
|||
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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$Id: device.c 1398 2004-11-01 15:18:53Z guus $
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
|
@ -27,6 +26,11 @@
|
|||
#include "net.h"
|
||||
#include "route.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef HAVE_TUNEMU
|
||||
#include "bsd/tunemu.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DEVICE "/dev/tun0"
|
||||
|
||||
|
|
@ -34,15 +38,20 @@ typedef enum device_type {
|
|||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TUNIFHEAD,
|
||||
DEVICE_TYPE_TAP,
|
||||
#ifdef HAVE_TUNEMU
|
||||
DEVICE_TYPE_TUNEMU,
|
||||
#endif
|
||||
} device_type_t;
|
||||
|
||||
int device_fd = -1;
|
||||
char *device;
|
||||
char *iface;
|
||||
char *device_info;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
static int device_total_in = 0;
|
||||
static int device_total_out = 0;
|
||||
#if defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD)
|
||||
#if defined(TUNEMU)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
||||
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
|
||||
#else
|
||||
static device_type_t device_type = DEVICE_TYPE_TUN;
|
||||
|
|
@ -51,22 +60,19 @@ static device_type_t device_type = DEVICE_TYPE_TUN;
|
|||
bool setup_device(void) {
|
||||
char *type;
|
||||
|
||||
cp();
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
|
||||
device = DEFAULT_DEVICE;
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
|
||||
|
||||
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
|
||||
logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "tun"))
|
||||
/* use default */;
|
||||
#ifdef HAVE_TUNEMU
|
||||
else if(!strcasecmp(type, "tunemu"))
|
||||
device_type = DEVICE_TYPE_TUNEMU;
|
||||
#endif
|
||||
else if(!strcasecmp(type, "tunnohead"))
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
else if(!strcasecmp(type, "tunifhead"))
|
||||
|
|
@ -74,7 +80,7 @@ bool setup_device(void) {
|
|||
else if(!strcasecmp(type, "tap"))
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
else {
|
||||
logger(LOG_ERR, _("Unknown device type %s!"), type);
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -82,6 +88,23 @@ bool setup_device(void) {
|
|||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
|
||||
switch(device_type) {
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU: {
|
||||
char dynamic_name[256] = "";
|
||||
device_fd = tunemu_open(dynamic_name);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(device_type) {
|
||||
default:
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
|
|
@ -90,7 +113,7 @@ bool setup_device(void) {
|
|||
{
|
||||
const int zero = 0;
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -102,14 +125,14 @@ bool setup_device(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
device_info = _("Generic BSD tun device");
|
||||
device_info = "Generic BSD tun device";
|
||||
break;
|
||||
case DEVICE_TYPE_TUNIFHEAD:
|
||||
#ifdef TUNSIFHEAD
|
||||
{
|
||||
const int one = 1;
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -121,35 +144,67 @@ bool setup_device(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
device_info = _("Generic BSD tun device");
|
||||
device_info = "Generic BSD tun device";
|
||||
break;
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
overwrite_mac = true;
|
||||
device_info = _("Generic BSD tap device");
|
||||
device_info = "Generic BSD tap device";
|
||||
#ifdef TAPGIFNAME
|
||||
{
|
||||
struct ifreq ifr;
|
||||
if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) {
|
||||
if(iface)
|
||||
free(iface);
|
||||
iface = xstrdup(ifr.ifr_name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
device_info = "BSD tunemu device";
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
logger(LOG_INFO, _("%s is a %s"), device, device_info);
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
cp();
|
||||
switch(device_type) {
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
tunemu_close(device_fd);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
close(device_fd);
|
||||
}
|
||||
|
||||
close(device_fd);
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
cp();
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
|
||||
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(device_type == DEVICE_TYPE_TUNEMU)
|
||||
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
|
||||
else
|
||||
#else
|
||||
lenin = read(device_fd, packet->data + 14, MTU - 14);
|
||||
#endif
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -165,7 +220,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_ ("Unknown IP version %d while reading packet from %s %s"),
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -178,7 +233,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
|
||||
|
||||
if((lenin = readv(device_fd, vector, 2)) <= 0) {
|
||||
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -196,7 +251,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_ ("Unknown address family %x while reading packet from %s %s"),
|
||||
"Unknown address family %x while reading packet from %s %s",
|
||||
ntohl(type), device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -207,7 +262,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -221,23 +276,20 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"),
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet)
|
||||
{
|
||||
cp();
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -259,13 +311,13 @@ bool write_packet(vpn_packet_t *packet)
|
|||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_("Unknown address family %x while writing packet to %s %s"),
|
||||
"Unknown address family %x while writing packet to %s %s",
|
||||
af, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(writev(device_fd, vector, 2) < 0) {
|
||||
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -274,12 +326,22 @@ bool write_packet(vpn_packet_t *packet)
|
|||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -289,11 +351,8 @@ bool write_packet(vpn_packet_t *packet)
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void)
|
||||
{
|
||||
cp();
|
||||
|
||||
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
|
||||
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
|
||||
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
|
||||
}
|
||||
|
|
|
|||
386
src/bsd/tunemu.c
Normal file
386
src/bsd/tunemu.c
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* 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
|
||||
{
|
||||
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;
|
||||
}
|
||||
32
src/bsd/tunemu.h
Normal file
32
src/bsd/tunemu.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
typedef char tunemu_device[7];
|
||||
|
||||
extern char tunemu_error[];
|
||||
|
||||
int tunemu_open(tunemu_device dev);
|
||||
int tunemu_close(int fd);
|
||||
int tunemu_read(int fd, char *buffer, int length);
|
||||
int tunemu_write(int fd, char *buffer, int length);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue