Allow linking with multiple device drivers.

Apart from the platform specific tun/tap driver, link with the dummy and
raw_socket devices, and optionally with support for UML and VDE devices.
At runtime, the DeviceType option can be used to select which driver to
use.
This commit is contained in:
Guus Sliepen 2011-12-04 01:20:59 +01:00
parent 5672863e59
commit 178e52f76e
19 changed files with 281 additions and 96 deletions

View file

@ -2,11 +2,20 @@
sbin_PROGRAMS = tincd
EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c vde/device.c
EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h
tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c \
dummy_device.c raw_socket_device.c
if UML
tincd_SOURCES += uml_device.c
endif
if VDE
tincd_SOURCES += vde_device.c
endif
if TUNEMU
tincd_SOURCES += bsd/tunemu.c

View file

@ -58,7 +58,7 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
static device_type_t device_type = DEVICE_TYPE_TUN;
#endif
bool setup_device(void) {
static bool setup_device(void) {
char *type;
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
@ -175,7 +175,7 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
switch(device_type) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
@ -190,7 +190,7 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
switch(device_type) {
@ -282,7 +282,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
@ -351,8 +351,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Windows tap driver in a Cygwin environment
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2009 Guus Sliepen <guus@tinc-vpn.org>
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -45,7 +45,7 @@ static uint64_t device_total_out = 0;
static pid_t reader_pid;
static int sp[2];
bool setup_device(void) {
static bool setup_device(void) {
HKEY key, key2;
int i, err;
@ -214,7 +214,7 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
close(sp[0]);
close(sp[1]);
CloseHandle(device_handle);
@ -225,7 +225,7 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
@ -244,7 +244,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
long lenout;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
@ -260,8 +260,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -1,7 +1,7 @@
/*
net.h -- generic header for device.c
device.h -- generic header for device.c
Copyright (C) 2001-2005 Ivo Timmermans
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
2001-2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -28,10 +28,19 @@ extern char *device;
extern char *iface;
extern bool setup_device(void);
extern void close_device(void);
extern bool read_packet(struct vpn_packet_t *);
extern bool write_packet(struct vpn_packet_t *);
extern void dump_device_stats(void);
typedef struct devops_t {
bool (*setup)(void);
void (*close)(void);
bool (*read)(struct vpn_packet_t *);
bool (*write)(struct vpn_packet_t *);
void (*dump_stats)(void);
} devops_t;
extern const devops_t os_devops;
extern const devops_t dummy_devops;
extern const devops_t raw_socket_devops;
extern const devops_t uml_devops;
extern const devops_t vde_devops;
extern devops_t devops;
#endif /* __TINC_DEVICE_H__ */

View file

@ -1,6 +1,6 @@
/*
device.c -- Dummy device
Copyright (C) 2009 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -23,33 +23,40 @@
#include "logger.h"
#include "net.h"
int device_fd = -1;
char *device = "dummy";
char *iface = "dummy";
static char *device_info = "dummy device";
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
bool setup_device(void) {
static bool setup_device(void) {
device = "dummy";
iface = "dummy";
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
void close_device(void) {
static void close_device(void) {
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
return false;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
device_total_out += packet->len;
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t dummy_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Linux ethertap and tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2009 Guus Sliepen <guus@tinc-vpn.org>
2001-2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -51,7 +51,7 @@ static char *device_info;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
bool setup_device(void) {
static bool setup_device(void) {
struct ifreq ifr;
bool t1q = false;
@ -121,14 +121,14 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
switch(device_type) {
@ -175,7 +175,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
@ -211,8 +211,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -83,7 +83,7 @@ static DWORD WINAPI tapreader(void *bla) {
}
}
bool setup_device(void) {
static bool setup_device(void) {
HKEY key, key2;
int i;
@ -210,18 +210,18 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
CloseHandle(device_handle);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
return false;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
long lenout;
OVERLAPPED overlapped = {0};
@ -238,8 +238,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -289,7 +289,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
/* check input from kernel */
if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
if(read_packet(&packet)) {
if(devops.read(&packet)) {
errors = 0;
packet.priority = 0;
route(myself, &packet);

View file

@ -518,7 +518,7 @@ void send_packet(const node_t *n, vpn_packet_t *packet) {
if(n == myself) {
if(overwrite_mac)
memcpy(packet->data, mymac.x, ETH_ALEN);
write_packet(packet);
devops.write(packet);
return;
}

View file

@ -1,7 +1,7 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com>
@ -45,6 +45,7 @@
#include "xalloc.h"
char *myport;
devops_t devops;
bool read_rsa_public_key(connection_t *c) {
FILE *fp;
@ -276,7 +277,7 @@ void load_all_subnets(void) {
static bool setup_myself(void) {
config_t *cfg;
subnet_t *subnet;
char *name, *hostname, *mode, *afname, *cipher, *digest;
char *name, *hostname, *mode, *afname, *cipher, *digest, *type;
char *fname = NULL;
char *address = NULL;
char *envp[5];
@ -539,7 +540,28 @@ static bool setup_myself(void) {
/* Open device */
if(!setup_device())
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "dummy"))
devops = dummy_devops;
else if(!strcasecmp(type, "raw_socket"))
devops = raw_socket_devops;
#ifdef ENABLE_UML
else if(!strcasecmp(type, "uml"))
devops = uml_devops;
#endif
#ifdef ENABLE_VDE
else if(!strcasecmp(type, "vde"))
devops = vde_devops;
#endif
else {
logger(LOG_ERR, "Unknown device type %s!", type);
return false;
}
} else {
devops = os_devops;
}
if(!devops.setup())
return false;
/* Run tinc-up script to further initialize the tap interface */
@ -702,7 +724,7 @@ void close_network_connections(void) {
for(i = 0; i < 4; i++)
free(envp[i]);
close_device();
devops.close();
return;
}

View file

@ -511,7 +511,7 @@ static RETSIGTYPE sigusr1_handler(int a) {
}
static RETSIGTYPE sigusr2_handler(int a) {
dump_device_stats();
devops.dump_stats();
dump_nodes();
dump_edges();
dump_subnets();

View file

@ -1,7 +1,7 @@
/*
device.c -- raw socket
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2009 Guus Sliepen <guus@tinc-vpn.org>
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -30,16 +30,12 @@
#include "route.h"
#include "xalloc.h"
int device_fd = -1;
char *device = NULL;
char *iface = NULL;
static char ifrname[IFNAMSIZ];
static char *device_info;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
bool setup_device(void) {
static bool setup_device(void) {
struct ifreq ifr;
struct sockaddr_ll sa;
@ -81,14 +77,14 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
@ -107,7 +103,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
@ -122,8 +118,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t raw_socket_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -35,7 +35,7 @@
#define DEFAULT_DEVICE "/dev/tun"
int device_fd = -1;
int ip_fd = -1, if_fd = -1;
static int ip_fd = -1, if_fd = -1;
char *device = NULL;
char *iface = NULL;
static char *device_info = NULL;
@ -43,7 +43,7 @@ static char *device_info = NULL;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
bool setup_device(void) {
static bool setup_device(void) {
int ppa;
char *ptr;
@ -105,7 +105,7 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
close(if_fd);
close(ip_fd);
close(device_fd);
@ -114,7 +114,7 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
@ -149,7 +149,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
@ -164,8 +164,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -650,7 +650,7 @@ int main2(int argc, char **argv) {
/* Shutdown properly. */
ifdebug(CONNECTIONS)
dump_device_stats();
devops.dump_stats();
close_network_connections();

View file

@ -1,7 +1,7 @@
/*
device.c -- UML network socket
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2009 Guus Sliepen <guus@tinc-vpn.org>
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
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
@ -30,14 +30,11 @@
#include "route.h"
#include "xalloc.h"
int device_fd = -1;
static int listen_fd = -1;
static int request_fd = -1;
static int data_fd = -1;
static int write_fd = -1;
static int state = 0;
char *device = NULL;
char *iface = NULL;
static char *device_info;
extern char *identname;
@ -57,7 +54,7 @@ static struct request {
static struct sockaddr_un data_sun;
bool setup_device(void) {
static bool setup_device(void) {
struct sockaddr_un listen_sun;
static const int one = 1;
struct {
@ -170,7 +167,7 @@ void close_device(void) {
if(iface) free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
switch(state) {
@ -252,7 +249,7 @@ bool read_packet(vpn_packet_t *packet) {
}
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
if(state != 2) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet",
packet->len, device_info);
@ -276,8 +273,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t uml_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -29,13 +29,10 @@
#include "route.h"
#include "xalloc.h"
int device_fd = -1;
static struct vdepluglib plug;
static struct vdeconn *conn = NULL;
static int port = 0;
static char *group = NULL;
char *device = NULL;
char *iface = NULL;
static char *device_info;
extern char *identname;
@ -44,7 +41,7 @@ extern volatile bool running;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
bool setup_device(void) {
static bool setup_device(void) {
libvdeplug_dynopen(plug);
if(!plug.dl_handle) {
@ -85,7 +82,7 @@ bool setup_device(void) {
return true;
}
void close_device(void) {
static void close_device(void) {
if(conn)
plug.vde_close(conn);
@ -97,7 +94,7 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int lenin = plug.vde_recv(conn, packet->data, MTU, 0);
if(lenin <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
@ -112,7 +109,7 @@ bool read_packet(vpn_packet_t *packet) {
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
if(plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
if(errno != EINTR && errno != EAGAIN) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
@ -127,8 +124,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t vde_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};