]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 14 Jul 2012 13:13:21 +0000 (15:13 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 14 Jul 2012 13:13:21 +0000 (15:13 +0200)
1  2 
THANKS
doc/tinc.texi
src/bsd/device.c

diff --combined THANKS
index 6fa8f9c869d32c6a4d7009c8c1a3f7bf73e8be08,10eaca61e9c06e4d7f742600c646e79e986ab9bf..0e7e6928c89a317b16039c422a2486aff5fdad37
--- 1/THANKS
--- 2/THANKS
+++ b/THANKS
@@@ -10,7 -10,6 +10,7 @@@ We would like to thank the following pe
  * Delf Eldkraft
  * dnk
  * Enrique Zanardi
 +* Erik Tews
  * Flynn Marquardt
  * Grzegorz Dymarek
  * Hans Bayle
@@@ -36,6 -35,7 +36,7 @@@
  * Nick Hibma
  * Nick Patavalis
  * Paul Littlefield
+ * Philipp Babel
  * Robert van der Meulen
  * Rumko
  * Scott Lamb
diff --combined doc/tinc.texi
index b595aec1741f0b6ffaac91519065238513e97ab0,5cff2a66204b0dfbd92f44c301f05943e46158fd..90d3c281588b0f7712d78d5ca8a5ec120c9dbcf8
@@@ -65,7 -65,6 +65,7 @@@ permission notice identical to this one
  * Installation::
  * Configuration::
  * Running tinc::
 +* Controlling tinc::
  * Technical information::
  * Platform specific information::
  * About us::
@@@ -262,7 -261,7 +262,7 @@@ alias char-major-10-200 tu
  @subsection Configuration of FreeBSD kernels
  
  For FreeBSD version 4.1 and higher, tun and tap drivers are included in the default kernel configuration.
- Using tap devices is recommended.
+ The tap driver can be loaded with @code{kldload if_tap}, or by adding @code{if_tap_load="YES"} to @file{/boot/loader.conf}. 
  
  
  @c ==================================================================
@@@ -276,6 -275,7 +276,7 @@@ which adds a tap device to OpenBSD whic
  but with recent versions of OpenBSD,
  a tun device can act as a tap device by setting the link0 option with ifconfig.
  
  @c ==================================================================
  @node       Configuration of NetBSD kernels
  @subsection Configuration of NetBSD kernels
@@@ -338,7 -338,6 +339,7 @@@ having them installed, configure will g
  * OpenSSL::
  * zlib::
  * lzo::
 +* libevent::
  @end menu
  
  
@@@ -451,27 -450,6 +452,27 @@@ make sure you build development and run
  default).
  
  
 +@c ==================================================================
 +@node       libevent
 +@subsection libevent
 +
 +@cindex libevent
 +For the main event loop, tinc uses the libevent library.
 +
 +If this library is not installed, you wil get an error when configuring
 +tinc for build.
 +
 +You can use your operating system's package manager to install this if
 +available.  Make sure you install the development AND runtime versions
 +of this package.
 +
 +If you have to install libevent manually, you can get the source code
 +from @url{http://monkey.org/~provos/libevent/}.  Instructions on how to configure,
 +build and install this package are included within the package.  Please
 +make sure you build development and runtime libraries (which is the
 +default).
 +
 +
  @c
  @c
  @c
@@@ -928,21 -906,6 +929,21 @@@ but which would have to be forwarded b
  When combined with the IndirectData option,
  packets for nodes for which we do not have a meta connection with are also dropped.
  
 +@cindex ECDSAPrivateKeyFile
 +@item ECDSAPrivateKeyFile = <@var{path}> (@file{@value{sysconfdir}/tinc/@var{netname}/ecdsa_key.priv})
 +The file in which the private ECDSA key of this tinc daemon resides.
 +This is only used if ExperimentalProtocol is enabled.
 +
 +@cindex ExperimentalProtocol
 +@item ExperimentalProtocol = <yes|no> (no) [experimental]
 +When this option is enabled, experimental protocol enhancements will be used.
 +Ephemeral ECDH will be used for key exchanges,
 +and ECDSA will be used instead of RSA for authentication.
 +When enabled, an ECDSA key must have been generated before with
 +@samp{tincctl generate-ecdsa-keys}.
 +The experimental protocol may change at any time,
 +and there is no guarantee that tinc will run stable when it is used.
 +
  @cindex Forwarding
  @item Forwarding = <off|internal|kernel> (internal) [experimental]
  This option selects the way indirect packets are forwarded.
@@@ -1076,7 -1039,7 +1077,7 @@@ accidental eavesdropping if you are edi
  @cindex PrivateKeyFile
  @item PrivateKeyFile = <@var{path}> (@file{@value{sysconfdir}/tinc/@var{netname}/rsa_key.priv})
  This is the full path name of the RSA private key file that was
 -generated by @samp{tincd --generate-keys}.  It must be a full path, not a
 +generated by @samp{tincctl generate-keys}.  It must be a full path, not a
  relative directory.
  
  Note that there must be exactly one of PrivateKey
@@@ -1225,7 -1188,7 +1226,7 @@@ This is the RSA public key for this hos
  @cindex PublicKeyFile
  @item PublicKeyFile = <@var{path}> [obsolete]
  This is the full path name of the RSA public key file that was generated
 -by @samp{tincd --generate-keys}.  It must be a full path, not a relative
 +by @samp{tincctl generate-keys}.  It must be a full path, not a relative
  directory.
  
  @cindex PEM format
@@@ -1260,6 -1223,7 +1261,6 @@@ example: netmask 255.255.255.0 would be
  /22. This conforms to standard CIDR notation as described in
  @uref{ftp://ftp.isi.edu/in-notes/rfc1519.txt, RFC1519}
  
 -@cindex Subnet weight
  A Subnet can be given a weight to indicate its priority over identical Subnets
  owned by different nodes. The default weight is 10. Lower values indicate
  higher priority. Packets will be sent to the node with the highest priority,
@@@ -1267,12 -1231,15 +1268,12 @@@ unless that node is not reachable, in w
  priority will be tried, and so on.
  
  @cindex TCPonly
 -@item TCPonly = <yes|no> (no) [deprecated]
 +@item TCPonly = <yes|no> (no)
  If this variable is set to yes, then the packets are tunnelled over a
  TCP connection instead of a UDP connection.  This is especially useful
  for those who want to run a tinc daemon from behind a masquerading
  firewall, or if UDP packet routing is disabled somehow.
  Setting this options also implicitly sets IndirectData.
 -
 -Since version 1.0.10, tinc will automatically detect whether communication via
 -UDP is possible or not.
  @end table
  
  
@@@ -1361,6 -1328,10 +1362,6 @@@ this is set to the port number it uses 
  @item SUBNET
  When a subnet becomes (un)reachable, this is set to the subnet.
  
 -@cindex WEIGHT
 -@item WEIGHT
 -When a subnet becomes (un)reachable, this is set to the subnet weight.
 -
  @end table
  
  
@@@ -1407,7 -1378,7 +1408,7 @@@ Now that you have already created the m
  you can easily create a public/private keypair by entering the following command:
  
  @example
 -tincd -n @var{netname} -K
 +tincctl -n @var{netname} generate-keys
  @end example
  
  Tinc will generate a public and a private key and ask you where to put them.
@@@ -1636,7 -1607,7 +1637,7 @@@ Address = 4.5.6.
  A, B, C and D all have generated a public/private keypair with the following command:
  
  @example
 -tincd -n company -K
 +tincctl -n company generate-keys
  @end example
  
  The private key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
@@@ -1702,6 -1673,12 +1703,6 @@@ This will also disable the automatic re
  Set debug level to @var{level}.  The higher the debug level, the more gets
  logged.  Everything goes via syslog.
  
 -@item -k, --kill[=@var{signal}]
 -Attempt to kill a running tincd (optionally with the specified @var{signal} instead of SIGTERM) and exit.
 -Use it in conjunction with the -n option to make sure you kill the right tinc daemon.
 -Under native Windows the optional argument is ignored,
 -the service will always be stopped and removed.
 -
  @item -n, --net=@var{netname}
  Use configuration for net @var{netname}.
  This will let tinc read all configuration files from
  Specifying . for @var{netname} is the same as not specifying any @var{netname}.
  @xref{Multiple networks}.
  
 -@item -K, --generate-keys[=@var{bits}]
 -Generate public/private keypair of @var{bits} length. If @var{bits} is not specified,
 -2048 is the default. tinc will ask where you want to store the files,
 -but will default to the configuration directory (you can use the -c or -n option
 -in combination with -K). After that, tinc will quit.
 +@item --pidfile=@var{filename}
 +Store a cookie in @var{filename} which allows tincctl to authenticate.
 +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}.
@@@ -1728,6 -1706,9 +1729,6 @@@ This will prevent sensitive data like s
  Write log entries to a file instead of to the system logging facility.
  If @var{file} is omitted, the default is @file{@value{localstatedir}/log/tinc.@var{netname}.log}.
  
 -@item --pidfile=@var{file}
 -Write PID to @var{file} instead of @file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
 -
  @item --bypass-security
  Disables encryption and authentication.
  Only useful for debugging.
@@@ -1781,6 -1762,19 +1782,6 @@@ New outgoing connections specified in @
  If the --logfile option is used, this will also close and reopen the log file,
  useful when log rotation is used.
  
 -@item INT
 -Temporarily increases debug level to 5.
 -Send this signal again to revert to the original level.
 -
 -@item USR1
 -Dumps the connection list to syslog.
 -
 -@item USR2
 -Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
 -
 -@item WINCH
 -Purges all information remembered about unreachable nodes.
 -
  @end table
  
  @c ==================================================================
@@@ -1844,7 -1838,7 +1845,7 @@@ Do you have a firewall or a NAT device 
  If so, check that it allows TCP and UDP traffic on port 655.
  If it masquerades and the host running tinc is behind it, make sure that it forwards TCP and UDP traffic to port 655 to the host running tinc.
  You can add @samp{TCPOnly = yes} to your host config file to force tinc to only use a single TCP connection,
 -this works through most firewalls and NATs. Since version 1.0.10, tinc will automatically fall back to TCP if direct communication via UDP is not possible.
 +this works through most firewalls and NATs.
  
  @end itemize
  
@@@ -1943,8 -1937,6 +1944,8 @@@ or if that is not the case, try changin
  
  @itemize
  @item If you see this only sporadically, it is harmless and caused by a node sending packets using an old key.
 +@item If you see this often and another node is not reachable anymore, then a NAT (masquerading firewall) is changing the source address of UDP packets.
 +You can add @samp{TCPOnly = yes} to host configuration files to force all VPN traffic to go over a TCP connection.
  @end itemize
  
  @item Got bad/bogus/unauthorized REQUEST from foo (1.2.3.4 port 12345)
@@@ -1975,213 -1967,6 +1976,213 @@@ Be sure to include the following inform
  @item The output of any command that fails to work as it should (like ping or traceroute).
  @end itemize
  
 +@c ==================================================================
 +@node    Controlling tinc
 +@chapter Controlling tinc
 +
 +You can control and inspect a running tincd through the tincctl
 +command. A quick example:
 +
 +@example
 +tincctl -n @var{netname} reload
 +@end example
 +
 +@menu
 +* tincctl runtime options::
 +* tincctl environment variables::
 +* tincctl commands::
 +* tincctl examples::
 +* tincctl top::
 +@end menu
 +
 +
 +@c ==================================================================
 +@node    tincctl runtime options
 +@section tincctl runtime options
 +
 +@c from the manpage
 +@table @option
 +@item -c, --config=@var{path}
 +Read configuration options from the directory @var{path}.  The default is
 +@file{@value{sysconfdir}/tinc/@var{netname}/}.
 +
 +@item -n, --net=@var{netname}
 +Use configuration for net @var{netname}. @xref{Multiple networks}.
 +
 +@item --pidfile=@var{filename}
 +Use the cookie from @var{filename} to authenticate with a running tinc daemon.
 +If unspecified, the default is
 +@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
 +
 +@item --help
 +Display a short reminder of runtime options and commands, then terminate.
 +
 +@item --version
 +Output version information and exit.
 +
 +@end table
 +
 +@c ==================================================================
 +@node    tincctl environment variables
 +@section tincctl environment variables
 +
 +@table @env
 +@cindex NETNAME
 +@item NETNAME
 +If no netname is specified on the command line with the @option{-n} option,
 +the value of this environment variable is used.
 +@end table
 +
 +@c ==================================================================
 +@node    tincctl commands
 +@section tincctl commands
 +
 +@c from the manpage
 +@table @code
 +
 +@item start
 +Start @samp{tincd}.
 +
 +@item stop
 +Stop @samp{tincd}.
 +
 +@item restart
 +Restart @samp{tincd}.
 +
 +@item reload
 +Partially rereads configuration files. Connections to hosts whose host
 +config files are removed are closed. New outgoing connections specified
 +in @file{tinc.conf} will be made.
 +
 +@item pid
 +Shows the PID of the currently running @samp{tincd}.
 +
 +@item generate-keys [@var{bits}]
 +Generate public/private keypair of @var{bits} length. If @var{bits} is not specified,
 +1024 is the default. tinc will ask where you want to store the files,
 +but will default to the configuration directory (you can use the -c or -n
 +option).
 +
 +@item dump nodes
 +Dump a list of all known nodes in the VPN.
 +
 +@item dump edges
 +Dump a list of all known connections in the VPN.
 +
 +@item dump subnets
 +Dump a list of all known subnets in the VPN.
 +
 +@item dump connections
 +Dump a list of all meta connections with ourself.
 +
 +@item dump graph
 +Dump a graph of the VPN in dotty format.
 +
 +@item purge
 +Purges all information remembered about unreachable nodes.
 +
 +@item debug @var{level}
 +Sets debug level to @var{level}.
 +
 +@item log [@var{level}]
 +Capture log messages from a running tinc daemon.
 +An optional debug level can be given that will be applied only for log messages sent to tincctl.
 +
 +@item retry
 +Forces tinc to try to connect to all uplinks immediately.
 +Usually tinc attempts to do this itself,
 +but increases the time it waits between the attempts each time it failed,
 +and if tinc didn't succeed to connect to an uplink the first time after it started,
 +it defaults to the maximum time of 15 minutes.
 +
 +@item disconnect @var{node}
 +Closes the meta connection with the given @var{node}.
 +
 +@item top
 +If tincctl is compiled with libcurses support, this will display live traffic statistics for all the known nodes,
 +similar to the UNIX top command.
 +See below for more information.
 +
 +@item pcap
 +Dump VPN traffic going through the local tinc node in pcap-savefile format to standard output,
 +from where it can be redirected to a file or piped through a program that can parse it directly,
 +such as tcpdump.
 +
 +@end table
 +
 +@c ==================================================================
 +@node    tincctl examples
 +@section tincctl examples
 +
 +Examples of some commands:
 +
 +@example
 +tincctl -n vpn dump graph | circo -Txlib
 +tincctl -n vpn pcap | tcpdump -r -
 +tincctl -n vpn top
 +@end example
 +
 +@c ==================================================================
 +@node    tincctl top
 +@section tincctl top
 +
 +The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
 +It displays a list of all the known nodes in the left-most column,
 +and the amount of bytes and packets read from and sent to each node in the other columns.
 +By default, the information is updated every second.
 +The behaviour of the top command can be changed using the following keys:
 +
 +@table @key
 +
 +@item s
 +Change the interval between updates.
 +After pressing the @key{s} key, enter the desired interval in seconds, followed by enter.
 +Fractional seconds are honored.
 +Intervals lower than 0.1 seconds are not allowed.
 +
 +@item c
 +Toggle between displaying current traffic rates (in packets and bytes per second)
 +and cummulative traffic (total packets and bytes since the tinc daemon started).
 +
 +@item n
 +Sort the list of nodes by name.
 +
 +@item i
 +Sort the list of nodes by incoming amount of bytes.
 +
 +@item I
 +Sort the list of nodes by incoming amount of packets.
 +
 +@item o
 +Sort the list of nodes by outgoing amount of bytes.
 +
 +@item O
 +Sort the list of nodes by outgoing amount of packets.
 +
 +@item t
 +Sort the list of nodes by sum of incoming and outgoing amount of bytes.
 +
 +@item T
 +Sort the list of nodes by sum of incoming and outgoing amount of packets.
 +
 +@item b
 +Show amount of traffic in bytes.
 +
 +@item k
 +Show amount of traffic in kilobytes.
 +
 +@item M
 +Show amount of traffic in megabytes.
 +
 +@item G
 +Show amount of traffic in gigabytes.
 +
 +@item q
 +Quit.
 +
 +@end table
 +
 +
  @c ==================================================================
  @node    Technical information
  @chapter Technical information
diff --combined src/bsd/device.c
index f8a559686f75b7b55a2b7b1b1309450a7761a264,d6dd055428491f815e75fb5fa403b3ea8f59cf56..c50005b2661f3d2b3bed45c9070c388d69d29e1d
  #include "bsd/tunemu.h"
  #endif
  
- #define DEFAULT_DEVICE "/dev/tun0"
+ #define DEFAULT_TUN_DEVICE "/dev/tun0"
+ #if defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
+ #define DEFAULT_TAP_DEVICE "/dev/tap0"
+ #else
+ #define DEFAULT_TAP_DEVICE "/dev/tun0"
+ #endif
  
  typedef enum device_type {
        DEVICE_TYPE_TUN,
@@@ -61,8 -66,12 +66,12 @@@ static device_type_t device_type = DEVI
  static bool setup_device(void) {
        char *type;
  
-       if(!get_config_string(lookup_config(config_tree, "Device"), &device))
-               device = xstrdup(DEFAULT_DEVICE);
+       if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
+               if(routing_mode == RMODE_ROUTER)
+                       device = xstrdup(DEFAULT_TUN_DEVICE);
+               else
+                       device = xstrdup(DEFAULT_TAP_DEVICE);
+       }
  
        if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
                iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
@@@ -81,7 -90,7 +90,7 @@@
                else if(!strcasecmp(type, "tap"))
                        device_type = DEVICE_TYPE_TAP;
                else {
 -                      logger(LOG_ERR, "Unknown device type %s!", type);
 +                      logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
                        return false;
                }
        } else {
        }
  
        if(device_fd < 0) {
 -              logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
 +              logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
                return false;
        }
  
                {       
                        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(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
                                return false;
                        }
                }
                {
                        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(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
                                return false;
                        }
                }
  #endif
        }
  
 -      logger(LOG_INFO, "%s is a %s", device, device_info);
 +      logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
  
        return true;
  }
@@@ -195,20 -204,20 +204,20 @@@ static void close_device(void) 
  }
  
  static bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
        switch(device_type) {
                case DEVICE_TYPE_TUN:
  #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
                        if(device_type == DEVICE_TYPE_TUNEMU)
 -                              lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
 +                              inlen = tunemu_read(device_fd, packet->data + 14, MTU - 14);
                        else
  #endif
 -                              lenin = read(device_fd, packet->data + 14, MTU - 14);
 +                              inlen = read(device_fd, packet->data + 14, MTU - 14);
  
 -                      if(lenin <= 0) {
 -                              logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
 +                      if(inlen <= 0) {
 +                              logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
                                        packet->data[13] = 0xDD;
                                        break;
                                default:
 -                                      ifdebug(TRAFFIC) logger(LOG_ERR,
 +                                      logger(DEBUG_TRAFFIC, LOG_ERR,
                                                           "Unknown IP version %d while reading packet from %s %s",
                                                           packet->data[14] >> 4, device_info, device);
                                        return false;
                        }
  
 -                      packet->len = lenin + 14;
 +                      packet->len = inlen + 14;
                        break;
  
                case DEVICE_TYPE_TUNIFHEAD: {
                        u_int32_t type;
 -                      struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
 +                      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,
 +                      if((inlen = readv(device_fd, vector, 2)) <= 0) {
 +                              logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
                                        break;
  
                                default:
 -                                      ifdebug(TRAFFIC) logger(LOG_ERR,
 +                                      logger(DEBUG_TRAFFIC, LOG_ERR,
                                                           "Unknown address family %x while reading packet from %s %s",
                                                           ntohl(type), device_info, device);
                                        return false;
                        }
  
 -                      packet->len = lenin + 10;
 +                      packet->len = inlen + 10;
                        break;
                }
  
                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,
 +                      if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
 +                              logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  
 -                      packet->len = lenin;
 +                      packet->len = inlen;
                        break;
  
                default:
                
        device_total_in += packet->len;
  
 -      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
 +      logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
                           packet->len, device_info);
  
        return true;
  }
  
  static bool write_packet(vpn_packet_t *packet) {
 -      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
 +      logger(DEBUG_TRAFFIC, 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(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  
                case DEVICE_TYPE_TUNIFHEAD: {
                        u_int32_t type;
 -                      struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, packet->len - 14}};
 +                      struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, packet->len - 14}};
                        int af;
                        
                        af = (packet->data[12] << 8) + packet->data[13];
                                        type = htonl(AF_INET6);
                                        break;
                                default:
 -                                      ifdebug(TRAFFIC) logger(LOG_ERR,
 +                                      logger(DEBUG_TRAFFIC, LOG_ERR,
                                                           "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(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                                           strerror(errno));
                                return false;
                        }
                        
                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(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  #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,
 +                              logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  }
  
  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);
 +      logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
 +      logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
 +      logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
  }
  
  const devops_t os_devops = {