Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
version of tinc.
+Version 1.0.16 July 23 2011
+
+ * Fixed a performance issue with TCP communication under Windows.
+
+ * Fixed code that, during network outages, would cause tinc to exit when it
+ thought two nodes with identical Names were on the VPN.
+
Version 1.0.15 June 24 2011
* Improved logging to file.
* Menno Smits
* Michael Tokarev
* Miles Nordin
+* Nick Hibma
* Nick Patavalis
* Paul Littlefield
* Robert van der Meulen
;;
esac
+AC_ARG_ENABLE(uml,
+ AS_HELP_STRING([--enable-uml], [enable support for User Mode Linux]),
+ [ AC_DEFINE(ENABLE_UML, 1, [Support for UML])
+ uml=true
+ ]
+)
+
+AC_ARG_ENABLE(vde,
+ AS_HELP_STRING([--enable-vde], [enable support for Virtual Distributed Ethernet]),
+ [ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break])
+ AC_DEFINE(ENABLE_VDE, 1, [Support for VDE])
+ vde=true
+ ]
+)
+
AC_ARG_ENABLE(tunemu,
AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]),
[ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])]
)
+AM_CONDITIONAL(UML, test "$uml" = true)
+AM_CONDITIONAL(VDE, test "$vde" = true)
AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
AC_CACHE_SAVE
AC_HEADER_STDC
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
-AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
+AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
[], [], [#include "have.h"]
)
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
If your computer has more than one IPv4 or IPv6 address,
.Nm tinc
will by default listen on all of them for incoming connections.
-It is possible to bind only to a single address with this variable.
+Multiple
+.Va BindToAddress
+variables may be specified,
+in which case listening sockets for each specified address are made.
.Pp
This option may not work on all platforms.
.Pp
This option may not work on all platforms.
+.It Va Broadcast Li = yes | no Po yes Pc Bq experimental
+When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+
.It Va ConnectTo Li = Ar name
Specifies which other tinc daemon to connect to on startup.
Multiple
won't try to connect to other daemons at all,
and will instead just listen for incoming connections.
+.It Va DecrementTTL Li = yes | no Po yes Pc
+When enabled,
+.Nm tinc
+will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
.It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
The virtual network device to use.
.Nm tinc
The info pages of the tinc package contain more information
about configuring the virtual network device.
-.It Va DeviceType Li = tun | tunnohead | tunifhead | tap Po only supported on BSD platforms Pc
+.It Va DeviceType Li = Ar type Pq platform dependent
The type of the virtual network device.
-Tinc will normally automatically select the right type, and this option should not be used.
-However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
-using this option might help.
+Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
+However, this option can be used to select one of the special interface types, if support for them is compiled in.
+.Bl -tag -width indent
+
+.It dummy
+Use a dummy interface.
+No packets are ever read or written to a virtual network device.
+Useful for testing, or when setting up a node that only forwards packets for other nodes.
+
+.It raw_socket
+Open a raw socket, and bind it to a pre-existing
+.Va Interface
+(eth0 by default).
+All packets are read from this interface.
+Packets received for the local node are written to the raw socket.
+However, at least on Linux, the operating system does not process IP packets destined for the local host.
+
+.It uml Pq not compiled in by default
+Create a UNIX socket with the filename specified by
+.Va Device ,
+or
+.Pa @localstatedir@/run/ Ns Ar NETNAME Ns Pa .umlsocket
+if not specified.
+.Nm tinc
+will wait for a User Mode Linux instance to connect to this socket.
+
+.It vde Pq not compiled in by default
+Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
+using the UNIX socket specified by
+.Va Device ,
+or
+.Pa @localstatedir@/run/vde.ctl
+if not specified.
+.El
+
+Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
+it can be used to change the way packets are interpreted:
+
.Bl -tag -width indent
-.It tun
+.It tun Pq BSD and Linux
Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below).
-.It tunnohead
+.It tunnohead Pq BSD
Set type to tun without an address family header.
Tinc will expect packets read from the virtual network device to start with an IP header.
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
-.It tunifhead
+.It tunifhead Pq BSD
Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
-.It tap
+.It tap Pq BSD and Linux
Set type to tap.
Tinc will expect packets read from the virtual network device
to start with an Ethernet header.
@item BindToAddress = <@var{address}> [experimental]
If your computer has more than one IPv4 or IPv6 address, tinc
will by default listen on all of them for incoming connections.
-It is possible to bind only to a single address with this variable.
+Multiple BindToAddress variables may be specified,
+in which case listening sockets for each specified address are made.
This option may not work on all platforms.
This option may not work on all platforms.
+@cindex Broadcast
+@item Broadcast = <yes | no> (yes) [experimental]
+When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
+
@cindex ConnectTo
@item ConnectTo = <@var{name}>
Specifies which other tinc daemon to connect to on startup.
tinc won't try to connect to other daemons at all,
and will instead just listen for incoming connections.
+@cindex DecrementTTL
+@item DecrementTTL = <yes | no> (yes)
+When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
+before forwarding a received packet to the virtual network device or to another node,
+and will drop packets that have a TTL value of zero,
+in which case it will send an ICMP Time Exceeded packet back.
+
@cindex Device
@item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
The virtual network device to use.
See also @ref{Device files}.
@cindex DeviceType
-@item DeviceType = <tun|tunnohead|tunifhead|tap> (only supported on BSD platforms)
+@item DeviceType = <@var{type}> (platform dependent)
The type of the virtual network device.
-Tinc will normally automatically select the right type, and this option should not be used.
-However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
-using this option might help.
+Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
+However, this option can be used to select one of the special interface types, if support for them is compiled in.
@table @asis
-@item tun
+@cindex dummy
+@item dummy
+Use a dummy interface.
+No packets are ever read or written to a virtual network device.
+Useful for testing, or when setting up a node that only forwards packets for other nodes.
+
+@cindex raw_socket
+@item raw_socket
+Open a raw socket, and bind it to a pre-existing
+@var{Interface} (eth0 by default).
+All packets are read from this interface.
+Packets received for the local node are written to the raw socket.
+However, at least on Linux, the operating system does not process IP packets destined for the local host.
+
+@cindex UML
+@item uml (not compiled in by default)
+Create a UNIX socket with the filename specified by
+@var{Device}, or @file{@value{localstatedir}/run/@var{netname}.umlsocket}
+if not specified.
+Tinc will wait for a User Mode Linux instance to connect to this socket.
+
+@cindex VDE
+@item vde (not compiled in by default)
+Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
+using the UNIX socket specified by
+@var{Device}, or @file{@value{localstatedir}/run/vde.ctl}
+if not specified.
+@end table
+
+Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
+it can be used to change the way packets are interpreted:
+
+@table @asis
+@item tun (BSD and Linux)
Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below).
@cindex tunnohead
-@item tunnohead
+@item tunnohead (BSD)
Set type to tun without an address family header.
Tinc will expect packets read from the virtual network device to start with an IP header.
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
@cindex tunifhead
-@item tunifhead
+@item tunifhead (BSD)
Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
-@item tap
+@item tap (BSD and Linux)
Set type to tap.
Tinc will expect packets read from the virtual network device
to start with an Ethernet header.
If unspecified, the default is
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
+@item -o, --option=[@var{HOST}.]@var{KEY}=@var{VALUE}
+Without specifying a @var{HOST}, this will set server configuration variable @var{KEY} to @var{VALUE}.
+If specified as @var{HOST}.@var{KEY}=@var{VALUE},
+this will set the host configuration variable @var{KEY} of the host named @var{HOST} to @var{VALUE}.
+This option can be used more than once to specify multiple configuration variables.
+
@item -L, --mlock
Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
.Nd tinc VPN daemon
.Sh SYNOPSIS
.Nm
-.Op Fl cdDKnLRU
+.Op Fl cdDKnoLRU
.Op Fl -config Ns = Ns Ar DIR
.Op Fl -no-detach
.Op Fl -debug Ns Op = Ns Ar LEVEL
.Op Fl -net Ns = Ns Ar NETNAME
+.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
.Op Fl -mlock
.Op Fl -logfile Ns Op = Ns Ar FILE
.Op Fl -bypass-security
.Ar NETNAME
is the same as not specifying any
.Ar NETNAME .
+.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
+Without specifying a
+.Ar HOST ,
+this will set server configuration variable
+.Ar KEY
+to
+.Ar VALUE .
+If specified as
+.Ar HOST.KEY=VALUE ,
+this will set the host configuration variable
+.Ar KEY
+of the host named
+.Ar HOST
+to
+.Ar VALUE .
+This option can be used more than once to specify multiple configuration variables.
.It Fl L, -mlock
Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
sbin_PROGRAMS = tincd tincctl sptps_test
-EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
+EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
tincd_SOURCES = \
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
buffer.c conf.c connection.c control.c edge.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
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
- 2001-2011 Guus Sliepen <guus@tinc-vpn.org>
+ 2001-2012 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify
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))
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
switch(device_type) {
default:
device_type = DEVICE_TYPE_TUN;
return true;
}
-void close_device(void) {
+static void close_device(void) {
switch(device_type) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
free(iface);
}
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
int inlen;
switch(device_type) {
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);
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,
+};
#include "xalloc.h"
splay_tree_t *connection_tree; /* Meta connections */
-connection_t *broadcast;
+connection_t *everyone;
static int connection_compare(const connection_t *a, const connection_t *b) {
return a < b ? -1 : a == b ? 0 : 1;
void init_connections(void) {
connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection);
- broadcast = new_connection();
- broadcast->name = xstrdup("everyone");
- broadcast->hostname = xstrdup("BROADCAST");
+ everyone = new_connection();
+ everyone->name = xstrdup("everyone");
+ everyone->hostname = xstrdup("BROADCAST");
}
void exit_connections(void) {
splay_delete_tree(connection_tree);
- free_connection(broadcast);
+ free_connection(everyone);
}
connection_t *new_connection(void) {
} connection_t;
extern splay_tree_t *connection_tree;
-extern connection_t *broadcast;
+extern connection_t *everyone;
extern void init_connections(void);
extern void exit_connections(void);
/*
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
static pid_t reader_pid;
static int sp[2];
-bool setup_device(void) {
+static bool setup_device(void) {
HKEY key, key2;
int i, err;
return true;
}
-void close_device(void) {
+static void close_device(void) {
close(sp[0]);
close(sp[1]);
CloseHandle(device_handle);
free(iface);
}
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
int inlen;
if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
return true;
}
-bool write_packet(vpn_packet_t *packet) {
+static bool write_packet(vpn_packet_t *packet) {
long outlen;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
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,
+};
/*
- 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
extern uint64_t device_out_packets;
extern uint64_t device_out_bytes;
-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__ */
/*
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
#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,
+};
#define ICMP_NET_UNKNOWN 6
#endif
+#ifndef ICMP_TIME_EXCEEDED
+#define ICMP_TIME_EXCEEDED 11
+#endif
+
+#ifndef ICMP_EXC_TTL
+#define ICMP_EXC_TTL 0
+#endif
+
#ifndef ICMP_NET_UNREACH
#define ICMP_NET_UNREACH 0
#endif
/*
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-2012 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
static device_type_t device_type;
char *device = NULL;
char *iface = NULL;
+static char *type = NULL;
static char ifrname[IFNAMSIZ];
static char *device_info;
uint64_t device_out_packets = 0;
uint64_t device_out_bytes = 0;
-bool setup_device(void) {
+static bool setup_device(void) {
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = xstrdup(DEFAULT_DEVICE);
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
struct ifreq ifr = {{{0}}};
- if(routing_mode == RMODE_ROUTER) {
+ get_config_string(lookup_config(config_tree, "DeviceType"), &type);
+
+ if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
+ logger(LOG_ERR, "Unknown device type %s!", type);
+ return false;
+ }
+
+ if((type && !strcasecmp(type, "tun")) || (!type && routing_mode == RMODE_ROUTER)) {
ifr.ifr_flags = IFF_TUN;
device_type = DEVICE_TYPE_TUN;
device_info = "Linux tun/tap device (tun mode)";
return true;
}
-void close_device(void) {
+static void close_device(void) {
close(device_fd);
+ free(type);
free(device);
free(iface);
}
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
int inlen;
switch(device_type) {
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);
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_in_bytes);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
}
+
+const devops_t os_devops = {
+ .setup = setup_device,
+ .close = close_device,
+ .read = read_packet,
+ .write = write_packet,
+ .dump_stats = dump_device_stats,
+};
}
}
-bool setup_device(void) {
+static bool setup_device(void) {
HKEY key, key2;
int i;
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 outlen;
OVERLAPPED overlapped = {0};
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,
+};
for(snode = n->subnet_tree->head; snode; snode = snext) {
snext = snode->next;
s = snode->data;
- send_del_subnet(broadcast, s);
+ send_del_subnet(everyone, s);
if(!strictsubnets)
subnet_del(n, s);
}
enext = enode->next;
e = enode->data;
if(!tunnelserver)
- send_del_edge(broadcast, e);
+ send_del_edge(everyone, e);
edge_del(e);
}
}
if(c->edge) {
if(report && !tunnelserver)
- send_del_edge(broadcast, c->edge);
+ send_del_edge(everyone, c->edge);
edge_del(c->edge);
e = lookup_edge(c->node, myself);
if(e) {
if(!tunnelserver)
- send_del_edge(broadcast, e);
+ send_del_edge(everyone, e);
edge_del(e);
}
}
next = node->next;
subnet = node->data;
if(subnet->expires == 1) {
- send_del_subnet(broadcast, subnet);
+ send_del_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, false);
subnet_del(subnet->owner, subnet);
} else if(subnet->expires == -1) {
subnet->expires = 0;
} else {
- send_add_subnet(broadcast, subnet);
+ send_add_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, true);
}
static int priority = 0;
int origpriority = origpkt->priority;
#endif
- int sock;
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
/* Determine which socket we have to use */
- for(sock = 0; sock < listen_sockets; sock++)
- if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family)
- break;
-
- if(sock >= listen_sockets)
- sock = 0; /* If none is available, just use the first and hope for the best. */
+ if(n->address.sa.sa_family != listen_socket[n->sock].sa.sa.sa_family) {
+ for(int sock = 0; sock < listen_sockets; sock++) {
+ if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) {
+ n->sock = sock;
+ break;
+ }
+ }
+ }
/* Send the packet */
#if defined(SOL_IP) && defined(IP_TOS)
if(priorityinheritance && origpriority != priority
- && listen_socket[sock].sa.sa.sa_family == AF_INET) {
+ && listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
- if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority)) /* SO_PRIORITY doesn't seem to work */
+ if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
#endif
- if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[n->sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
memcpy(packet->data, mymac.x, ETH_ALEN);
n->out_packets++;
n->out_bytes += packet->len;
- write_packet(packet);
+ devops.write(packet);
return;
}
return;
}
+ n->sock = (intptr_t)data;
+
receive_udppacket(n, &pkt);
}
packet.priority = 0;
- if(read_packet(&packet)) {
+ if(devops.read(&packet)) {
myself->in_packets++;
myself->in_bytes += packet.len;
route(myself, &packet);
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com>
char *myport;
static struct event device_ev;
+devops_t devops;
bool node_read_ecdsa_public_key(node_t *n) {
if(ecdsa_active(&n->ecdsa))
fp = fopen(fname, "r");
if(!fp) {
- logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
- fname, strerror(errno));
+ logger(LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
free(fname);
return false;
}
fp = fopen(fname, "r");
if(!fp) {
- logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s",
- fname, strerror(errno));
+ logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
free(fname);
return false;
}
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];
myself->options |= OPTION_CLAMP_MSS;
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
+ get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
+ get_config_bool(lookup_config(config_tree, "Broadcast"), &broadcast);
#if !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance)
/* Open device */
- if(!setup_device())
+ devops = os_devops;
+
+ 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
+ }
+
+ if(!devops.setup())
return false;
if(device_fd >= 0) {
if (event_add(&device_ev, NULL) < 0) {
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
- close_device();
+ devops.close();
return false;
}
}
/* Open sockets */
- get_config_string(lookup_config(config_tree, "BindToAddress"), &address);
+ listen_sockets = 0;
+ cfg = lookup_config(config_tree, "BindToAddress");
- hint.ai_family = addressfamily;
- hint.ai_socktype = SOCK_STREAM;
- hint.ai_protocol = IPPROTO_TCP;
- hint.ai_flags = AI_PASSIVE;
+ do {
+ get_config_string(cfg, &address);
+ if(cfg)
+ cfg = lookup_config_next(config_tree, cfg);
- err = getaddrinfo(address, myport, &hint, &ai);
+ hint.ai_family = addressfamily;
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_protocol = IPPROTO_TCP;
+ hint.ai_flags = AI_PASSIVE;
- if(err || !ai) {
- logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
- gai_strerror(err));
- return false;
- }
+ err = getaddrinfo(address, myport, &hint, &ai);
+ free(address);
- listen_sockets = 0;
+ if(err || !ai) {
+ logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
+ gai_strerror(err));
+ return false;
+ }
- for(aip = ai; aip; aip = aip->ai_next) {
- listen_socket[listen_sockets].tcp =
- setup_listen_socket((sockaddr_t *) aip->ai_addr);
+ for(aip = ai; aip; aip = aip->ai_next) {
+ if(listen_sockets >= MAXSOCKETS) {
+ logger(LOG_ERR, "Too many listening sockets");
+ return false;
+ }
- if(listen_socket[listen_sockets].tcp < 0)
- continue;
+ listen_socket[listen_sockets].tcp =
+ setup_listen_socket((sockaddr_t *) aip->ai_addr);
- listen_socket[listen_sockets].udp =
- setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
+ if(listen_socket[listen_sockets].tcp < 0)
+ continue;
- if(listen_socket[listen_sockets].udp < 0) {
- close(listen_socket[listen_sockets].tcp);
- continue;
- }
+ listen_socket[listen_sockets].udp =
+ setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
- event_set(&listen_socket[listen_sockets].ev_tcp,
- listen_socket[listen_sockets].tcp,
- EV_READ|EV_PERSIST,
- handle_new_meta_connection, NULL);
- if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
- logger(LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
+ if(listen_socket[listen_sockets].udp < 0) {
+ close(listen_socket[listen_sockets].tcp);
+ continue;
+ }
- event_set(&listen_socket[listen_sockets].ev_udp,
- listen_socket[listen_sockets].udp,
- EV_READ|EV_PERSIST,
- handle_incoming_vpn_data, NULL);
- if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
- logger(LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
+ event_set(&listen_socket[listen_sockets].ev_tcp,
+ listen_socket[listen_sockets].tcp,
+ EV_READ|EV_PERSIST,
+ handle_new_meta_connection, NULL);
+ if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
+ logger(LOG_ERR, "event_add failed: %s", strerror(errno));
+ abort();
+ }
- ifdebug(CONNECTIONS) {
- hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
- logger(LOG_NOTICE, "Listening on %s", hostname);
- free(hostname);
- }
+ event_set(&listen_socket[listen_sockets].ev_udp,
+ listen_socket[listen_sockets].udp,
+ EV_READ|EV_PERSIST,
+ handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
+ if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
+ logger(LOG_ERR, "event_add failed: %s", strerror(errno));
+ abort();
+ }
- memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
- listen_sockets++;
+ ifdebug(CONNECTIONS) {
+ hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
+ logger(LOG_NOTICE, "Listening on %s", hostname);
+ free(hostname);
+ }
- if(listen_sockets >= MAXSOCKETS) {
- logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
- break;
+ memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
+ listen_sockets++;
}
- }
- freeaddrinfo(ai);
+ freeaddrinfo(ai);
+ } while(cfg);
if(listen_sockets)
logger(LOG_NOTICE, "Ready");
for(i = 0; i < 4; i++)
free(envp[i]);
- close_device();
+ devops.close();
return;
}
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
#include "utils.h"
#include "xalloc.h"
-#include <assert.h>
-
/* Needed on Mac OS/X */
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
return true;
}
-static bool bind_to_address(connection_t *c) {
- char *node;
- struct addrinfo *ai_list;
- struct addrinfo *ai_ptr;
- struct addrinfo ai_hints;
- int status;
-
- assert(c != NULL);
- assert(c->socket >= 0);
-
- node = NULL;
- if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
- &node))
- return true;
-
- assert(node != NULL);
-
- memset(&ai_hints, 0, sizeof(ai_hints));
- ai_hints.ai_family = c->address.sa.sa_family;
- /* We're called from `do_outgoing_connection' only. */
- ai_hints.ai_socktype = SOCK_STREAM;
- ai_hints.ai_protocol = IPPROTO_TCP;
-
- ai_list = NULL;
-
- status = getaddrinfo(node, /* service = */ NULL,
- &ai_hints, &ai_list);
- if(status) {
- logger(LOG_WARNING, "Error looking up %s port %s: %s",
- node, "any", gai_strerror(status));
- free(node);
- return false;
- }
- assert(ai_list != NULL);
-
- status = -1;
- for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
- status = bind(c->socket,
- ai_list->ai_addr, ai_list->ai_addrlen);
- if(!status)
- break;
- }
-
-
- if(status) {
- logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno));
- } else ifdebug(CONNECTIONS) {
- logger(LOG_DEBUG, "Successfully bound outgoing "
- "TCP socket to %s", node);
- }
-
- free(node);
- freeaddrinfo(ai_list);
-
- return status ? false : true;
-}
-
int setup_listen_socket(const sockaddr_t *sa) {
int nfd;
char *addrstr;
return -1;
}
+#ifdef FD_CLOEXEC
+ fcntl(nfd, F_SETFD, FD_CLOEXEC);
+#endif
+
/* Optimize TCP settings */
option = 1;
return -1;
}
+#ifdef FD_CLOEXEC
+ fcntl(nfd, F_SETFD, FD_CLOEXEC);
+#endif
+
#ifdef O_NONBLOCK
{
int flags = fcntl(nfd, F_GETFL);
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+#ifdef FD_CLOEXEC
+ fcntl(c->socket, F_SETFD, FD_CLOEXEC);
+#endif
+
if(c->socket == -1) {
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
goto begin;
#endif
bind_to_interface(c->socket);
- bind_to_address(c);
/* Optimize TCP settings */
char *name; /* name of this node */
uint32_t options; /* options turned on for this node */
+ int sock; /* Socket to use for outgoing UDP packets */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */
#include "system.h"
+#include <openssl/obj_mac.h>
+
#include "digest.h"
#include "prf.h"
request[len++] = '\n';
- if(c == broadcast) {
+ if(c == everyone) {
broadcast_meta(NULL, request, len);
return true;
} else
if(tunnelserver)
send_add_edge(c, c->edge);
else
- send_add_edge(broadcast, c->edge);
+ send_add_edge(everyone, c->edge);
/* Run MST and SSSP algorithms */
e = lookup_edge(to, myself);
if(e) {
if(!tunnelserver)
- send_del_edge(broadcast, e);
+ send_del_edge(everyone, e);
edge_del(e);
}
}
splay_node_t *node;
connection_t *c;
- send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
+ send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
/*
device.c -- raw socket
Copyright (C) 2002-2005 Ivo Timmermans,
- 2002-2009 Guus Sliepen <guus@tinc-vpn.org>
+ 2002-2012 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
#include "system.h"
+#ifdef HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
+#endif
#include "conf.h"
#include "device.h"
#include "route.h"
#include "xalloc.h"
-int device_fd = -1;
-char *device = NULL;
-char *iface = NULL;
-static char ifrname[IFNAMSIZ];
+#if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET)
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;
}
memset(&ifr, 0, sizeof ifr);
+
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
close(device_fd);
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 inlen;
if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
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);
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,
+};
+
+#else
+
+static bool not_supported(void) {
+ logger(LOG_ERR, "Raw socket device not supported on this platform");
+ return false;
+}
+
+const devops_t raw_socket_devops = {
+ .setup = not_supported,
+ .close = NULL,
+ .read = NULL,
+ .write = NULL,
+ .dump_stats = NULL,
+};
+#endif
rmode_t routing_mode = RMODE_ROUTER;
fmode_t forwarding_mode = FMODE_INTERNAL;
+bool decrement_ttl = true;
bool directonly = false;
bool priorityinheritance = false;
int macexpire = 600;
bool overwrite_mac = false;
+bool broadcast = true;
mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
bool pcap = false;
if(!checklength(source, packet, ether_size + ip_size))
return;
- if(((packet->data[30] & 0xf0) == 0xe0) || (
+ if(broadcast && (((packet->data[30] & 0xf0) == 0xe0) || (
packet->data[30] == 255 &&
packet->data[31] == 255 &&
packet->data[32] == 255 &&
- packet->data[33] == 255))
+ packet->data[33] == 255)))
broadcast_packet(source, packet);
else
route_ipv4_unicast(source, packet);
return;
}
- if(packet->data[38] == 255)
+ if(broadcast && packet->data[38] == 255)
broadcast_packet(source, packet);
else
route_ipv6_unicast(source, packet);
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet) {
- broadcast_packet(source, packet);
+ if(broadcast)
+ broadcast_packet(source, packet);
return;
}
}
}
+static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
+ uint16_t type = packet->data[12] << 8 | packet->data[13];
+
+ switch (type) {
+ case ETH_P_IP:
+ if(!checklength(source, packet, 14 + 32))
+ return false;
+
+ if(packet->data[22] < 1) {
+ route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
+ return false;
+ }
+
+ uint16_t old = packet->data[22] << 8 | packet->data[23];
+ packet->data[22]--;
+ uint16_t new = packet->data[22] << 8 | packet->data[23];
+
+ uint32_t checksum = packet->data[24] << 8 | packet->data[25];
+ checksum += old + (~new & 0xFFFF);
+ while(checksum >> 16)
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ packet->data[24] = checksum >> 8;
+ packet->data[25] = checksum & 0xff;
+
+ return true;
+
+ case ETH_P_IPV6:
+ if(!checklength(source, packet, 14 + 40))
+ return false;
+
+ if(packet->data[21] < 1) {
+ route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
+ return false;
+ }
+
+ packet->data[21]--;
+
+ return true;
+
+ default:
+ return true;
+ }
+}
+
void route(node_t *source, vpn_packet_t *packet) {
if(pcap)
send_pcap(packet);
if(!checklength(source, packet, ether_size))
return;
+ if(decrement_ttl && source != myself)
+ if(!do_decrement_ttl(source, packet))
+ return;
+
switch (routing_mode) {
case RMODE_ROUTER:
{
extern rmode_t routing_mode;
extern fmode_t forwarding_mode;
+extern bool decrement_ttl;
extern bool directonly;
extern bool overwrite_mac;
+extern bool broadcast;
extern bool priorityinheritance;
extern int macexpire;
extern bool pcap;
/*
device.c -- Interaction with Solaris tun device
Copyright (C) 2001-2005 Ivo Timmermans,
- 2001-2011 Guus Sliepen <guus@tinc-vpn.org>
+ 2001-2012 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
#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;
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;
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
ppa = 0;
ptr = device;
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(ip_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
/* Assign a new PPA and get its unit number. */
if((ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0) {
logger(LOG_ERR, "Can't assign new interface: %s", strerror(errno));
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(if_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
if(ioctl(if_fd, I_PUSH, "ip") < 0) {
logger(LOG_ERR, "Can't push IP module: %s", strerror(errno));
return false;
return true;
}
-void close_device(void) {
+static void close_device(void) {
close(if_fd);
close(ip_fd);
close(device_fd);
free(iface);
}
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
int inlen;
if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
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);
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,
+};
{"user", required_argument, NULL, 'U'},
{"logfile", optional_argument, NULL, 4},
{"pidfile", required_argument, NULL, 5},
+ {"option", required_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
};
program_name);
else {
printf("Usage: %s [option]...\n\n", program_name);
- printf( " -c, --config=DIR Read configuration options from DIR.\n"
- " -D, --no-detach Don't fork and detach.\n"
- " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n"
- " -n, --net=NETNAME Connect to net NETNAME.\n"
- " -L, --mlock Lock tinc into main memory.\n"
- " --logfile[=FILENAME] Write log entries to a logfile.\n"
- " --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n"
- " --bypass-security Disables meta protocol security, for debugging.\n"
- " -o [HOST.]KEY=VALUE Set global/host configuration value.\n"
- " -R, --chroot chroot to NET dir at startup.\n"
- " -U, --user=USER setuid to given USER at startup.\n" " --help Display this help and exit.\n"
- " --version Output version information and exit.\n\n");
+ printf( " -c, --config=DIR Read configuration options from DIR.\n"
+ " -D, --no-detach Don't fork and detach.\n"
+ " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n"
+ " -n, --net=NETNAME Connect to net NETNAME.\n"
+ " -L, --mlock Lock tinc into main memory.\n"
+ " --logfile[=FILENAME] Write log entries to a logfile.\n"
+ " --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n"
+ " --bypass-security Disables meta protocol security, for debugging.\n"
+ " -o, --option[HOST.]KEY=VALUE Set global/host configuration value.\n"
+ " -R, --chroot chroot to NET dir at startup.\n"
+ " -U, --user=USER setuid to given USER at startup.\n" " --help Display this help and exit.\n"
+ " --version Output version information and exit.\n\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
}
InitializeCriticalSection(&mutex);
EnterCriticalSection(&mutex);
#endif
+ char *priority = NULL;
if(!detach())
return 1;
/* Change process priority */
- char *priority = NULL;
-
if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) {
if(!strcasecmp(priority, "Normal")) {
if (setpriority(NORMAL_PRIORITY_CLASS) != 0) {
/* Shutdown properly. */
ifdebug(CONNECTIONS)
- dump_device_stats();
+ devops.dump_stats();
close_network_connections();
/*
device.c -- UML network socket
Copyright (C) 2002-2005 Ivo Timmermans,
- 2002-2009 Guus Sliepen <guus@tinc-vpn.org>
+ 2002-2012 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
#include "logger.h"
#include "utils.h"
#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;
-extern bool running;
+extern volatile bool running;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
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 {
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(write_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
setsockopt(write_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(write_fd, F_SETFL, O_NONBLOCK) < 0) {
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(data_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0) {
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
if(iface) free(iface);
}
-bool read_packet(vpn_packet_t *packet) {
+static bool read_packet(vpn_packet_t *packet) {
int inlen;
switch(state) {
case 0: {
struct sockaddr sa;
- int salen = sizeof sa;
+ socklen_t salen = sizeof sa;
request_fd = accept(listen_fd, &sa, &salen);
if(request_fd < 0) {
return false;
}
+#ifdef FD_CLOEXEC
+ fcntl(request_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
running = false;
return true;
}
+
+ default:
+ logger(LOG_ERR, "Invalid value for state variable in " __FILE__);
+ abort();
}
}
-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);
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,
+};
/*
device.c -- VDE plug
- Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
+ Copyright (C) 2012 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
#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;
-extern bool running;
+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) {
device_fd = plug.vde_datafd(conn);
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
logger(LOG_INFO, "%s is a %s", device, device_info);
if(routing_mode == RMODE_ROUTER)
return true;
}
-void close_device(void) {
+static void close_device(void) {
if(conn)
plug.vde_close(conn);
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));
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));
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,
+};