]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' into 1.1
authorGuus Sliepen <guus@sliepen.eu.org>
Wed, 16 Sep 2009 17:55:47 +0000 (19:55 +0200)
committerGuus Sliepen <guus@sliepen.eu.org>
Wed, 16 Sep 2009 17:55:47 +0000 (19:55 +0200)
Conflicts:
have.h
lib/dropin.c
lib/fake-getaddrinfo.c
lib/pidfile.c
src/Makefile.am
src/bsd/device.c
src/conf.c
src/connection.c
src/connection.h
src/graph.c
src/mingw/device.c
src/net.c
src/net_setup.c
src/node.c
src/protocol_key.c
src/protocol_misc.c
src/tincd.c

86 files changed:
NEWS
README
configure.in
doc/Makefile.am
doc/tinc.texi
doc/tincctl.8.in [new file with mode: 0644]
doc/tincd.8.in
have.h
lib/Makefile.am
lib/avl_tree.c
lib/dropin.c
lib/fake-getaddrinfo.c
lib/fake-getnameinfo.c
lib/list.c
lib/pidfile.c [deleted file]
lib/pidfile.h [deleted file]
lib/utils.c
po/POTFILES.in
po/nl.po
src/Makefile.am
src/bsd/device.c
src/conf.c
src/conf.h
src/connection.c
src/connection.h
src/control.c [new file with mode: 0644]
src/control.h [new file with mode: 0644]
src/control_common.h [new file with mode: 0644]
src/cygwin/device.c
src/edge.c
src/edge.h
src/event.c [deleted file]
src/event.h [deleted file]
src/gcrypt/cipher.c [new file with mode: 0644]
src/gcrypt/cipher.h [new file with mode: 0644]
src/gcrypt/crypto.c [new file with mode: 0644]
src/gcrypt/crypto.h [new file with mode: 0644]
src/gcrypt/digest.c [new file with mode: 0644]
src/gcrypt/digest.h [new file with mode: 0644]
src/gcrypt/rsa.c [new file with mode: 0644]
src/gcrypt/rsa.h [new file with mode: 0644]
src/gcrypt/rsagen.c [new file with mode: 0644]
src/gcrypt/rsagen.h [new file with mode: 0644]
src/graph.c
src/graph.h
src/linux/device.c
src/logger.c
src/meta.c
src/meta.h
src/mingw/device.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/node.c
src/node.h
src/openssl/cipher.c [new file with mode: 0644]
src/openssl/cipher.h [new file with mode: 0644]
src/openssl/crypto.c [new file with mode: 0644]
src/openssl/crypto.h [new file with mode: 0644]
src/openssl/digest.c [new file with mode: 0644]
src/openssl/digest.h [new file with mode: 0644]
src/openssl/rsa.c [new file with mode: 0644]
src/openssl/rsa.h [new file with mode: 0644]
src/openssl/rsagen.c [new file with mode: 0644]
src/openssl/rsagen.h [new file with mode: 0644]
src/process.c
src/process.h
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_misc.c
src/protocol_subnet.c
src/raw_socket/device.c
src/route.c
src/route.h
src/solaris/device.c
src/subnet.c
src/subnet.h
src/tincctl.c [new file with mode: 0644]
src/tincd.c
src/uml_socket/device.c

diff --git a/NEWS b/NEWS
index 736f5e69db55fb690f78262365a4a7086fdc593a..a993df5ca8b09f85b6fa79197bee939da496bbea 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+Version 1.1-cvs              Work in progress
+
+ * Use libevent to handle I/O events and timeouts.
+
+ * Use splay trees instead of AVL trees.
+
 Version 1.0.9                Dec 26 2008
 
  * Fixed tinc as a service under Windows 2003.
diff --git a/README b/README
index 23b24581dd56073977b820192d66ee276617701e..c324e2b7726f9be28e889975f37a0c357f89d04c 100644 (file)
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
-This is the README file for tinc version 1.0.9. Installation
+This is the README file for tinc version 1.1-cvs. Installation
 instructions may be found in the INSTALL file.
 
-tinc is Copyright (C) 1998-2008 by:
+tinc is Copyright (C) 1998-2009 by:
 
 Ivo Timmermans,
 Guus Sliepen <guus@tinc-vpn.org>,
@@ -55,7 +55,7 @@ should be changed into "Device", and "Device" should be changed into
 Compatibility
 -------------
 
-Version 1.0.9 is compatible with 1.0pre8, 1.0 and later, but not with older
+Version 1.1-cvs is compatible with 1.0pre8, 1.0 and later, but not with older
 versions of tinc.
 
 
@@ -78,6 +78,9 @@ Since 1.0, the lzo library is also used for optional compression. You need this
 library whether or not you plan to enable compression. You can find it at
 http://www.oberhumer.com/opensource/lzo/.
 
+Since 1.1, the libevent library is used for the main event loop. You can find
+it at http://monkey.org/~provos/libevent/.
+
 In order to compile tinc, you will need a GNU C compiler environment.
 
 
index 1ff36b3f8ebf96fa39457c04bb61992edda47689..0561af8b8f7e9272ca4bf27e9fa20cd337c92a6f 100644 (file)
@@ -2,20 +2,17 @@ dnl Process this file with autoconf to produce a configure script.
 
 dnl $Id$
 
-AC_PREREQ(2.61)
+AC_PREREQ(2.59)
 AC_INIT
 AC_CONFIG_SRCDIR([src/tincd.c])
-AM_INIT_AUTOMAKE(tinc, 1.0-cvs)
+AC_GNU_SOURCE
+AM_INIT_AUTOMAKE(tinc, 1.1-cvs)
 AC_CONFIG_HEADERS([config.h])
 AM_MAINTAINER_MODE
 
 AM_GNU_GETTEXT([external])
 AM_GNU_GETTEXT_VERSION(0.14.1)
 
-# Enable GNU extensions.
-# Define this here, not in acconfig's @TOP@ section, since definitions
-# in the latter don't make it into the configure-time tests.
-AC_GNU_SOURCE
 AC_DEFINE([__USE_BSD], 1, [Enable BSD extensions])
 
 ALL_LINGUAS="nl"
@@ -100,12 +97,15 @@ fi
 
 dnl Checks for libraries.
 
+AC_CHECK_LIB(event, event_init,
+  [], [AC_MSG_ERROR(libevent is required)])
+
 dnl Checks for header files.
 dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
 
 AC_HEADER_STDC
 AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/socket.h sys/time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h])
-AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h],
+AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
   [], [], [#include "have.h"]
 )
 AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
@@ -133,7 +133,7 @@ dnl Checks for library functions.
 AC_FUNC_MEMCMP
 AC_FUNC_ALLOCA
 AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system unsetenv vsyslog writev],
+AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time unsetenv vsyslog writev],
   [], [], [#include "have.h"]
 )
 AC_FUNC_MALLOC
@@ -156,10 +156,20 @@ AC_CACHE_SAVE
 
 dnl These are defined in files in m4/
 
-tinc_OPENSSL
+AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
+
 tinc_ZLIB
 tinc_LZO
 
+if test "$with_libgcrypt" = yes; then
+       AM_PATH_LIBGCRYPT([1.4.0], [], [])
+       ln -sf gcrypt/cipher.c gcrypt/cipher.h gcrypt/crypto.c gcrypt/crypto.h gcrypt/digest.c gcrypt/digest.h gcrypt/rsa.c gcrypt/rsa.h gcrypt/rsagen.c gcrypt/rsagen.h src/
+else
+       tinc_OPENSSL
+       ln -sf openssl/cipher.c openssl/cipher.h openssl/crypto.c openssl/crypto.h openssl/digest.c openssl/digest.h openssl/rsa.c openssl/rsa.h openssl/rsagen.c openssl/rsagen.h src/
+fi
+       
+
 dnl Check if support for jumbograms is requested 
 AC_ARG_ENABLE(jumbograms,
   AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
index 7c49d844b6f8e90f7da66c39ea777a020d816cf6..66de6d93c2e1b223f87494d4c4c35a1f39520dde 100644 (file)
@@ -2,11 +2,11 @@
 
 info_TEXINFOS = tinc.texi
 
-man_MANS = tincd.8 tinc.conf.5
+man_MANS = tincd.8 tincctl.8 tinc.conf.5
 
-EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config.tar.gz
+EXTRA_DIST = tincinclude.texi.in tincd.8.in tincctl.8.in tinc.conf.5.in sample-config.tar.gz
 
-CLEANFILES = *.html tinc.info tincd.8 tinc.conf.5 tincinclude.texi
+CLEANFILES = *.html tinc.info tincd.8 tincctl.8 tinc.conf.5 tincinclude.texi
 
 # Use `ginstall' in the definition of man_MANS to avoid
 # confusion with the `install' target.  The install rule transforms `ginstall'
@@ -25,6 +25,9 @@ texi2html: tinc.texi
 tincd.8.html: tincd.8
        w3mman2html $< > $@
 
+tincctl.8.html: tincctl.8
+       w3mman2html $< > $@
+
 tinc.conf.5.html: tinc.conf.5
        w3mman2html $< > $@
 
@@ -37,6 +40,9 @@ substitute = sed \
 tincd.8: tincd.8.in
        $(substitute) tincd.8.in > tincd.8
 
+tincctl.8: tincctl.8.in
+       $(substitute) tincctl.8.in > tincctl.8
+
 tinc.conf.5: tinc.conf.5.in
        $(substitute) tinc.conf.5.in > tinc.conf.5
 
index 5cd4a4004466473ee7b6a648cbe52a16d4d4575a..13784335f37ea36d0efd6bde215c91c4fdbb5428 100644 (file)
@@ -71,6 +71,7 @@ permission notice identical to this one.
 * Installation::
 * Configuration::
 * Running tinc::
+* Controlling tinc::
 * Technical information::
 * Platform specific information::
 * About us::
@@ -343,6 +344,7 @@ having them installed, configure will give you an error message, and stop.
 * OpenSSL::
 * zlib::
 * lzo::
+* libevent::
 @end menu
 
 
@@ -455,6 +457,27 @@ make sure you build development and runtime libraries (which is the
 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
@@ -922,7 +945,7 @@ accidental eavesdropping if you are editting the configuration file.
 @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
@@ -1008,7 +1031,7 @@ This is the RSA public key for this host.
 @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
@@ -1191,7 +1214,7 @@ Now that you have already created the main configuration file and your host conf
 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.
@@ -1420,7 +1443,7 @@ Address = 4.5.6.7
 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},
@@ -1486,20 +1509,12 @@ This will also disable the automatic restart mechanism for fatal errors.
 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}. @xref{Multiple networks}.
 
-@item -K, --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
-in combination with -K). After that, tinc will quit.
+@item --controlsocket=@var{filename}
+Open control socket at @var{filename}. If unspecified, the default is
+@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
 
 @item -L, --mlock
 Lock tinc into main memory.
@@ -1509,9 +1524,6 @@ This will prevent sensitive data like shared private keys to be written to the 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.
@@ -1551,31 +1563,11 @@ You can also send the following signals to a running tincd process:
 @c from the manpage
 @table @samp
 
-@item ALRM
-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 HUP
 Partially rereads configuration files.
 Connections to hosts whose host config file are removed are closed.
 New outgoing connections specified in @file{tinc.conf} will be made.
 
-@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 ==================================================================
@@ -1770,6 +1762,110 @@ Be sure to include the following information in your bugreport:
 @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 @samp{tincd} through the @samp{tincctl}
+command. A quick example:
+
+@example
+tincctl -n @var{netname} reload
+@end example
+
+@menu
+* tincctl runtime options::
+* tincctl commands::
+@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 --controlsocket=@var{filename}
+Open control socket at @var{filename}. If unspecified, the default is
+@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
+
+@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 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 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.
+
+@end table
+
+
 @c ==================================================================
 @node    Technical information
 @chapter Technical information
diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in
new file mode 100644 (file)
index 0000000..493adfd
--- /dev/null
@@ -0,0 +1,127 @@
+.Dd 2007-07-20
+.Dt TINCCTL 8
+.\" Manual page created by:
+.\" Scott Lamb
+.Sh NAME
+.Nm tincctl
+.Nd tinc VPN control
+.Sh SYNOPSIS
+.Nm
+.Op Fl cn
+.Op Fl -config Ns = Ns Ar DIR
+.Op Fl -net Ns = Ns Ar NETNAME
+.Op Fl -controlsocket Ns = Ns Ar FILENAME
+.Op Fl -help
+.Op Fl -version
+.Ar COMMAND
+.Sh DESCRIPTION
+This is the control program of tinc, a secure virtual private network (VPN)
+project.
+.Nm
+communicates with
+.Xr tincd 8
+to alter and inspect the running VPN's state.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl n, -net Ns = Ns Ar NETNAME
+Communicate with tincd(8) connected with
+.Ar NETNAME .
+.It Fl -controlsocket Ns = Ns Ar FILENAME
+Open control socket at
+.Ar FILENAME .
+If unspecified, the default is
+.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .control.
+.It Fl -help
+Display short list of options.
+.It Fl -version
+Output version information and exit.
+.El
+.Sh COMMANDS
+.zZ
+.Bl -tag -width indent
+.It start
+Start
+.Xr tincd 8 .
+.It stop
+Stop
+.Xr tincd 8 .
+.It restart
+Restart
+.Xr tincd 8 .
+.It reload
+Partially rereads configuration files. Connections to hosts whose host
+config files are removed are closed. New outgoing connections specified
+in
+.Xr tinc.conf 5
+will be made.
+.It pid
+Shows the PID of the currently running
+.Xr tincd 8 .
+.It generate-keys Op bits
+Generate public/private RSA keypair and exit.
+If
+.Ar bits
+is omitted, the default length will be 1024 bits.
+When saving keys to existing files, tinc will not delete the old keys;
+you have to remove them manually.
+.It dump nodes
+Dump a list of all known nodes in the VPN.
+.It dump edges
+Dump a list of all known connections in the VPN.
+.It dump subnets
+Dump a list of all known subnets in the VPN.
+.It dump connections
+Dump a list of all meta connections with ourself.
+.It dump graph
+Dump a graph of the VPN in
+.Xr dotty 1
+format.
+.It purge
+Purges all information remembered about unreachable nodes.
+.It debug Ar N
+Sets debug level to
+.Ar N .
+.It retry
+Forces
+.Xr tincd 8
+to try to connect to all uplinks immediately.
+Usually
+.Xr tincd 8
+attempts to do this itself,
+but increases the time it waits between the attempts each time it failed,
+and if
+.Xr tincd 8
+didn't succeed to connect to an uplink the first time after it started,
+it defaults to the maximum time of 15 minutes.
+.It reload
+Partially rereads configuration files.
+Connections to hosts whose host config files are removed are closed.
+New outgoing connections specified in
+.Pa tinc.conf
+will be made.
+.El
+.Sh BUGS
+The "start" and "restart" commands are not yet implemented.
+.Pp
+If you find any bugs, report them to tinc@tinc-vpn.org.
+.Sh SEE ALSO
+.Xr tincd 8 ,
+.Xr tinc.conf 5 ,
+.Xr dotty 1 ,
+.Pa http://www.tinc-vpn.org/ ,
+.Pa http://www.cabal.org/ .
+.Pp
+The full documentation for tinc is maintained as a Texinfo manual.
+If the info and tinc programs are properly installed at your site,
+the command
+.Ic info tinc
+should give you access to the complete manual.
+.Pp
+tinc comes with ABSOLUTELY NO WARRANTY.
+This is free software, and you are welcome to redistribute it under certain conditions;
+see the file COPYING for details.
+.Sh AUTHORS
+.An "Ivo Timmermans"
+.An "Guus Sliepen" Aq guus@tinc-vpn.org
+.Pp
+And thanks to many others for their contributions to tinc!
index 7e168fd0c1e41d34b0ed4a7ff8185267c480ead3..966cc77ee0981e85b9ea66dba63828385b3a273e 100644 (file)
@@ -8,16 +8,13 @@
 .Nd tinc VPN daemon
 .Sh SYNOPSIS
 .Nm
-.Op Fl cdDkKnLRU
+.Op Fl cdDKnLRU
 .Op Fl -config Ns = Ns Ar DIR
 .Op Fl -no-detach
 .Op Fl -debug Ns Op = Ns Ar LEVEL
-.Op Fl -kill Ns Op = Ns Ar SIGNAL
 .Op Fl -net Ns = Ns Ar NETNAME
-.Op Fl -generate-keys Ns Op = Ns Ar BITS
 .Op Fl -mlock
 .Op Fl -logfile Ns Op = Ns Ar FILE
-.Op Fl -pidfile Ns = Ns Ar FILE
 .Op Fl -bypass-security
 .Op Fl -chroot
 .Op Fl -user Ns = Ns Ar USER
@@ -53,24 +50,9 @@ If not mentioned otherwise, this will show log messages on the standard error ou
 Increase debug level or set it to
 .Ar LEVEL
 (see below).
-.It Fl k, -kill Ns Op = Ns Ar SIGNAL
-Attempt to kill a running
-.Nm
-(optionally with the specified
-.Ar SIGNAL
-instead of SIGTERM) and exit.
-Under Windows (not Cygwin) the optional argument is ignored,
-the service will always be stopped and removed.
 .It Fl n, -net Ns = Ns Ar NETNAME
 Connect to net
 .Ar NETNAME .
-.It Fl K, -generate-keys Ns Op = Ns Ar BITS
-Generate public/private RSA keypair and exit.
-If
-.Ar BITS
-is omitted, the default length will be 1024 bits.
-When saving keys to existing files, tinc will not delete the old keys,
-you have to remove them manually.
 .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.
@@ -80,12 +62,13 @@ If
 .Ar FILE
 is omitted, the default is
 .Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
-.It Fl -pidfile Ns = Ns Ar FILE
-Write PID to
+.It Fl -controlsocket Ns = Ns Ar FILENAME
+Open control socket at
+.Ar FILENAME .
+If
 .Ar FILE
-instead of
-.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid.
-Under Windows this option will be ignored.
+is omitted, the default is
+.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .control.
 .It Fl -bypass-security
 Disables encryption and authentication of the meta protocol.
 Only useful for debugging.
@@ -104,33 +87,12 @@ Output version information and exit.
 .El
 .Sh SIGNALS
 .Bl -tag -width indent
-.It ALRM
-Forces
-.Nm
-to try to connect to all uplinks immediately.
-Usually
-.Nm
-attempts to do this itself,
-but increases the time it waits between the attempts each time it failed,
-and if
-.Nm
-didn't succeed to connect to an uplink the first time after it started,
-it defaults to the maximum time of 15 minutes.
 .It HUP
 Partially rereads configuration files.
 Connections to hosts whose host config file are removed are closed.
 New outgoing connections specified in
 .Pa tinc.conf
 will be made.
-.It INT
-Temporarily increases debug level to 5.
-Send this signal again to revert to the original level.
-.It USR1
-Dumps the connection list to syslog.
-.It USR2
-Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
-.It WINCH
-Purges all information remembered about unreachable nodes.
 .El
 .Sh DEBUG LEVELS
 The tinc daemon can send a lot of messages to the syslog.
@@ -177,6 +139,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
 .Sh TODO
 A lot, especially security auditing.
 .Sh SEE ALSO
+.Xr tincctl 8 ,
 .Xr tinc.conf 5 ,
 .Pa http://www.tinc-vpn.org/ ,
 .Pa http://www.cabal.org/ .
diff --git a/have.h b/have.h
index 7e2930dcbbca15e95162f5a052a11cbd98f0d657..43a9147ae3431ac3444351b52a9fa3017ec44987 100644 (file)
--- a/have.h
+++ b/have.h
 #include <sys/time.h>
 #endif
 
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
index 57436fd5a798d6f2749477e149f674225eadb187..5dfeda5fde6a52b0284307fc7eae90319b8c0939 100644 (file)
@@ -5,11 +5,11 @@ noinst_LIBRARIES = libvpn.a
 
 INCLUDES = @INCLUDES@ -I. -I$(top_builddir)
 
-libvpn_a_SOURCES = xmalloc.c pidfile.c utils.c getopt.c getopt1.c list.c avl_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c
+libvpn_a_SOURCES = xmalloc.c utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c
 
 libvpn_a_LIBADD = @LIBOBJS@ @ALLOCA@
 libvpn_a_DEPENDENCIES = $(libvpn_a_LIBADD)
 
-noinst_HEADERS = xalloc.h pidfile.h utils.h getopt.h list.h avl_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h gettext.h ipv6.h ipv4.h ethernet.h
+noinst_HEADERS = xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h gettext.h ipv6.h ipv4.h ethernet.h
 
 EXTRA_DIST = 
index 3bfdfeeeecaf1f23cd0252facf2692eabc816d13..c1856c7f40ccf107d5fa2c656afb312a6f959804 100644 (file)
@@ -54,8 +54,7 @@
 #ifndef AVL_DEPTH
 static int lg(unsigned int u) __attribute__ ((__const__));
 
-static int lg(unsigned int u)
-{
+static int lg(unsigned int u) {
        int r = 1;
 
        if(!u)
@@ -90,8 +89,7 @@ static int lg(unsigned int u)
 
 /* Internal helper functions */
 
-static int avl_check_balance(const avl_node_t *node)
-{
+static int avl_check_balance(const avl_node_t *node) {
 #ifdef AVL_DEPTH
        int d;
 
@@ -118,8 +116,7 @@ static int avl_check_balance(const avl_node_t *node)
 #endif
 }
 
-static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
-{
+static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *child;
        avl_node_t *gchild;
        avl_node_t *parent;
@@ -262,8 +259,7 @@ static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
 
 /* (De)constructors */
 
-avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete)
-{
+avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
        avl_tree_t *tree;
 
        tree = xmalloc_and_zero(sizeof(avl_tree_t));
@@ -273,18 +269,15 @@ avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete)
        return tree;
 }
 
-void avl_free_tree(avl_tree_t *tree)
-{
+void avl_free_tree(avl_tree_t *tree) {
        free(tree);
 }
 
-avl_node_t *avl_alloc_node(void)
-{
+avl_node_t *avl_alloc_node(void) {
        return xmalloc_and_zero(sizeof(avl_node_t));
 }
 
-void avl_free_node(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
        if(node->data && tree->delete)
                tree->delete(node->data);
 
@@ -293,8 +286,7 @@ void avl_free_node(avl_tree_t *tree, avl_node_t *node)
 
 /* Searching */
 
-void *avl_search(const avl_tree_t *tree, const void *data)
-{
+void *avl_search(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
 
        node = avl_search_node(tree, data);
@@ -302,8 +294,7 @@ void *avl_search(const avl_tree_t *tree, const void *data)
        return node ? node->data : NULL;
 }
 
-void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result)
-{
+void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
        avl_node_t *node;
 
        node = avl_search_closest_node(tree, data, result);
@@ -311,8 +302,7 @@ void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result)
        return node ? node->data : NULL;
 }
 
-void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data)
-{
+void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
 
        node = avl_search_closest_smaller_node(tree, data);
@@ -320,8 +310,7 @@ void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data)
        return node ? node->data : NULL;
 }
 
-void *avl_search_closest_greater(const avl_tree_t *tree, const void *data)
-{
+void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
 
        node = avl_search_closest_greater_node(tree, data);
@@ -329,8 +318,7 @@ void *avl_search_closest_greater(const avl_tree_t *tree, const void *data)
        return node ? node->data : NULL;
 }
 
-avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data)
-{
+avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
        int result;
 
@@ -340,8 +328,7 @@ avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data)
 }
 
 avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
-                                                                       int *result)
-{
+                                                                       int *result) {
        avl_node_t *node;
        int c;
 
@@ -383,8 +370,7 @@ avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
 }
 
 avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
-                                                                                       const void *data)
-{
+                                                                                       const void *data) {
        avl_node_t *node;
        int result;
 
@@ -397,8 +383,7 @@ avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
 }
 
 avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
-                                                                                       const void *data)
-{
+                                                                                       const void *data) {
        avl_node_t *node;
        int result;
 
@@ -412,8 +397,7 @@ avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
 
 /* Insertion and deletion */
 
-avl_node_t *avl_insert(avl_tree_t *tree, void *data)
-{
+avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
        avl_node_t *closest, *new;
        int result;
 
@@ -452,8 +436,7 @@ avl_node_t *avl_insert(avl_tree_t *tree, void *data)
        return new;
 }
 
-avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node)
-{
+avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *closest;
        int result;
 
@@ -486,15 +469,13 @@ avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node)
        return node;
 }
 
-void avl_insert_top(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
        node->prev = node->next = node->parent = NULL;
        tree->head = tree->tail = tree->root = node;
 }
 
 void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
-                                          avl_node_t *node)
-{
+                                          avl_node_t *node) {
        if(!before) {
                if(tree->tail)
                        avl_insert_after(tree, tree->tail, node);
@@ -523,8 +504,7 @@ void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
        avl_rebalance(tree, before);
 }
 
-void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
-{
+void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
        if(!after) {
                if(tree->head)
                        avl_insert_before(tree, tree->head, node);
@@ -553,8 +533,7 @@ void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
        avl_rebalance(tree, after);
 }
 
-avl_node_t *avl_unlink(avl_tree_t *tree, void *data)
-{
+avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
        avl_node_t *node;
 
        node = avl_search_node(tree, data);
@@ -565,8 +544,7 @@ avl_node_t *avl_unlink(avl_tree_t *tree, void *data)
        return node;
 }
 
-void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *parent;
        avl_node_t **superparent;
        avl_node_t *subst, *left, *right;
@@ -634,14 +612,12 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
 #endif
 }
 
-void avl_delete_node(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
        avl_unlink_node(tree, node);
        avl_free_node(tree, node);
 }
 
-void avl_delete(avl_tree_t *tree, void *data)
-{
+void avl_delete(avl_tree_t *tree, void *data) {
        avl_node_t *node;
 
        node = avl_search_node(tree, data);
@@ -652,8 +628,7 @@ void avl_delete(avl_tree_t *tree, void *data)
 
 /* Fast tree cleanup */
 
-void avl_delete_tree(avl_tree_t *tree)
-{
+void avl_delete_tree(avl_tree_t *tree) {
        avl_node_t *node, *next;
 
        for(node = tree->head; node; node = next) {
@@ -666,8 +641,7 @@ void avl_delete_tree(avl_tree_t *tree)
 
 /* Tree walking */
 
-void avl_foreach(const avl_tree_t *tree, avl_action_t action)
-{
+void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
        avl_node_t *node, *next;
 
        for(node = tree->head; node; node = next) {
@@ -676,8 +650,7 @@ void avl_foreach(const avl_tree_t *tree, avl_action_t action)
        }
 }
 
-void avl_foreach_node(const avl_tree_t *tree, avl_action_t action)
-{
+void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
        avl_node_t *node, *next;
 
        for(node = tree->head; node; node = next) {
@@ -689,13 +662,11 @@ void avl_foreach_node(const avl_tree_t *tree, avl_action_t action)
 /* Indexing */
 
 #ifdef AVL_COUNT
-unsigned int avl_count(const avl_tree_t *tree)
-{
+unsigned int avl_count(const avl_tree_t *tree) {
        return AVL_NODE_COUNT(tree->root);
 }
 
-avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index)
-{
+avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
        avl_node_t *node;
        unsigned int c;
 
@@ -717,8 +688,7 @@ avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index)
        return NULL;
 }
 
-unsigned int avl_index(const avl_node_t *node)
-{
+unsigned int avl_index(const avl_node_t *node) {
        avl_node_t *next;
        unsigned int index;
 
@@ -734,8 +704,7 @@ unsigned int avl_index(const avl_node_t *node)
 }
 #endif
 #ifdef AVL_DEPTH
-unsigned int avl_depth(const avl_tree_t *tree)
-{
+unsigned int avl_depth(const avl_tree_t *tree) {
        return AVL_NODE_DEPTH(tree->root);
 }
 #endif
index 1c2592dfd5231b4d43751fa1a241250d29c767b4..4ad32378bdbb541c90ac9e1303d8da059ff9988a 100644 (file)
@@ -38,8 +38,7 @@
   Unless the argument noclose is non-zero, daemon() will redirect
   standard input, standard output and standard error to /dev/null.
 */
-int daemon(int nochdir, int noclose)
-{
+int daemon(int nochdir, int noclose) {
 #ifdef HAVE_FORK
        pid_t pid;
        int fd;
@@ -97,8 +96,7 @@ int daemon(int nochdir, int noclose)
   current directory name.  If the environment variable PWD is set, and
   its value is correct, then that value will be returned.
 */
-char *get_current_dir_name(void)
-{
+char *get_current_dir_name(void) {
        size_t size;
        char *buf;
        char *r;
index 10672b7e6f07eee8749a120c66eeff1a2703cbf8..df3d34764dc9680dd1d625cd10ed94e2bdfb19d0 100644 (file)
@@ -16,9 +16,9 @@
 #include "fake-getaddrinfo.h"
 #include "xalloc.h"
 
+
 #if !HAVE_DECL_GAI_STRERROR
-char *gai_strerror(int ecode)
-{
+char *gai_strerror(int ecode) {
        switch (ecode) {
                case EAI_NODATA:
                        return "No address associated with hostname";
@@ -33,8 +33,7 @@ char *gai_strerror(int ecode)
 #endif /* !HAVE_GAI_STRERROR */
 
 #if !HAVE_DECL_FREEADDRINFO
-void freeaddrinfo(struct addrinfo *ai)
-{
+void freeaddrinfo(struct addrinfo *ai) {
        struct addrinfo *next;
 
        while(ai) {
@@ -46,8 +45,7 @@ void freeaddrinfo(struct addrinfo *ai)
 #endif /* !HAVE_FREEADDRINFO */
 
 #if !HAVE_DECL_GETADDRINFO
-static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr)
-{
+static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
        struct addrinfo *ai;
 
        ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
@@ -62,8 +60,7 @@ static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr)
        return ai;
 }
 
-int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
-{
+int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
        struct addrinfo *prev = NULL;
        struct hostent *hp;
        struct in_addr in = {0};
index 804717309c809c05953a425f9c2e4ce5c9121e25..1eba49253ea387638844de3457e2efbdeb008e4e 100644 (file)
@@ -16,8 +16,7 @@
 
 #if !HAVE_DECL_GETNAMEINFO
 
-int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
-{
+int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
        struct sockaddr_in *sin = (struct sockaddr_in *)sa;
        struct hostent *hp;
        int len;
index 2f9f611db39b327464735e3c9f3e4253453cc1a0..c5dccb79cd67982050ca2ad300e6cba9ad6f9ef8 100644 (file)
@@ -27,8 +27,7 @@
 
 /* (De)constructors */
 
-list_t *list_alloc(list_action_t delete)
-{
+list_t *list_alloc(list_action_t delete) {
        list_t *list;
 
        list = xmalloc_and_zero(sizeof(list_t));
@@ -37,18 +36,15 @@ list_t *list_alloc(list_action_t delete)
        return list;
 }
 
-void list_free(list_t *list)
-{
+void list_free(list_t *list) {
        free(list);
 }
 
-list_node_t *list_alloc_node(void)
-{
+list_node_t *list_alloc_node(void) {
        return xmalloc_and_zero(sizeof(list_node_t));
 }
 
-void list_free_node(list_t *list, list_node_t *node)
-{
+void list_free_node(list_t *list, list_node_t *node) {
        if(node->data && list->delete)
                list->delete(node->data);
 
@@ -57,8 +53,7 @@ void list_free_node(list_t *list, list_node_t *node)
 
 /* Insertion and deletion */
 
-list_node_t *list_insert_head(list_t *list, void *data)
-{
+list_node_t *list_insert_head(list_t *list, void *data) {
        list_node_t *node;
 
        node = list_alloc_node();
@@ -78,8 +73,7 @@ list_node_t *list_insert_head(list_t *list, void *data)
        return node;
 }
 
-list_node_t *list_insert_tail(list_t *list, void *data)
-{
+list_node_t *list_insert_tail(list_t *list, void *data) {
        list_node_t *node;
 
        node = list_alloc_node();
@@ -99,8 +93,7 @@ list_node_t *list_insert_tail(list_t *list, void *data)
        return node;
 }
 
-void list_unlink_node(list_t *list, list_node_t *node)
-{
+void list_unlink_node(list_t *list, list_node_t *node) {
        if(node->prev)
                node->prev->next = node->next;
        else
@@ -114,34 +107,29 @@ void list_unlink_node(list_t *list, list_node_t *node)
        list->count--;
 }
 
-void list_delete_node(list_t *list, list_node_t *node)
-{
+void list_delete_node(list_t *list, list_node_t *node) {
        list_unlink_node(list, node);
        list_free_node(list, node);
 }
 
-void list_delete_head(list_t *list)
-{
+void list_delete_head(list_t *list) {
        list_delete_node(list, list->head);
 }
 
-void list_delete_tail(list_t *list)
-{
+void list_delete_tail(list_t *list) {
        list_delete_node(list, list->tail);
 }
 
 /* Head/tail lookup */
 
-void *list_get_head(list_t *list)
-{
+void *list_get_head(list_t *list) {
        if(list->head)
                return list->head->data;
        else
                return NULL;
 }
 
-void *list_get_tail(list_t *list)
-{
+void *list_get_tail(list_t *list) {
        if(list->tail)
                return list->tail->data;
        else
@@ -150,8 +138,7 @@ void *list_get_tail(list_t *list)
 
 /* Fast list deletion */
 
-void list_delete_list(list_t *list)
-{
+void list_delete_list(list_t *list) {
        list_node_t *node, *next;
 
        for(node = list->head; node; node = next) {
@@ -164,8 +151,7 @@ void list_delete_list(list_t *list)
 
 /* Traversing */
 
-void list_foreach_node(list_t *list, list_action_node_t action)
-{
+void list_foreach_node(list_t *list, list_action_node_t action) {
        list_node_t *node, *next;
 
        for(node = list->head; node; node = next) {
@@ -174,8 +160,7 @@ void list_foreach_node(list_t *list, list_action_node_t action)
        }
 }
 
-void list_foreach(list_t *list, list_action_t action)
-{
+void list_foreach(list_t *list, list_action_t action) {
        list_node_t *node, *next;
 
        for(node = list->head; node; node = next) {
diff --git a/lib/pidfile.c b/lib/pidfile.c
deleted file mode 100644 (file)
index dd6788a..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-    pidfile.c - interact with pidfiles
-    Copyright (c) 1995  Martin Schulze <Martin.Schulze@Linux.DE>
-
-    This file is part of the sysklogd package, a kernel and system log daemon.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA
-*/
-
-/* left unaltered for tinc -- Ivo Timmermans */
-/*
- * Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze
- *     First version (v0.2) released
- */
-
-#include "system.h"
-
-#ifndef HAVE_MINGW
-/* read_pid
- *
- * Reads the specified pidfile and returns the read pid.
- * 0 is returned if either there's no pidfile, it's empty
- * or no pid can be read.
- */
-pid_t read_pid (char *pidfile)
-{
-  FILE *f;
-  long pid;
-
-  if (!(f=fopen(pidfile,"r")))
-    return 0;
-  if(fscanf(f,"%ld", &pid) != 1)
-    pid = 0;
-  fclose(f);
-  return pid;
-}
-
-/* check_pid
- *
- * Reads the pid using read_pid and looks up the pid in the process
- * table (using /proc) to determine if the process already exists. If
- * so the pid is returned, otherwise 0.
- */
-pid_t check_pid (char *pidfile)
-{
-  pid_t pid = read_pid(pidfile);
-
-  /* Amazing ! _I_ am already holding the pid file... */
-  if ((!pid) || (pid == getpid ()))
-    return 0;
-
-  /*
-   * The 'standard' method of doing this is to try and do a 'fake' kill
-   * of the process.  If an ESRCH error is returned the process cannot
-   * be found -- GW
-   */
-  /* But... errno is usually changed only on error.. */
-  errno = 0;
-  if (kill(pid, 0) && errno == ESRCH)
-         return 0;
-
-  return pid;
-}
-
-/* write_pid
- *
- * Writes the pid to the specified file. If that fails 0 is
- * returned, otherwise the pid.
- */
-pid_t write_pid (char *pidfile)
-{
-  FILE *f;
-  int fd;
-  pid_t pid;
-
-  if ((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1) {
-      return 0;
-  }
-
-  if ((f = fdopen(fd, "r+")) == NULL) {
-      close(fd);
-      return 0;
-  }
-  
-#ifdef HAVE_FLOCK
-  if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
-      fclose(f);
-      return 0;
-  }
-#endif
-
-  pid = getpid();
-  if (!fprintf(f,"%ld\n", (long)pid)) {
-      fclose(f);
-      return 0;
-  }
-  fflush(f);
-
-#ifdef HAVE_FLOCK
-  if (flock(fd, LOCK_UN) == -1) {
-      fclose(f);
-      return 0;
-  }
-#endif
-  fclose(f);
-
-  return pid;
-}
-
-/* remove_pid
- *
- * Remove the the specified file. The result from unlink(2)
- * is returned
- */
-int remove_pid (char *pidfile)
-{
-  return unlink (pidfile);
-}
-#endif
diff --git a/lib/pidfile.h b/lib/pidfile.h
deleted file mode 100644 (file)
index 152ae2c..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-    pidfile.h - interact with pidfiles
-    Copyright (c) 1995  Martin Schulze <Martin.Schulze@Linux.DE>
-
-    This file is part of the sysklogd package, a kernel and system log daemon.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
-*/
-
-#ifndef HAVE_MINGW
-/* read_pid
- *
- * Reads the specified pidfile and returns the read pid.
- * 0 is returned if either there's no pidfile, it's empty
- * or no pid can be read.
- */
-pid_t read_pid (char *pidfile);
-
-/* check_pid
- *
- * Reads the pid using read_pid and looks up the pid in the process
- * table (using /proc) to determine if the process already exists. If
- * so 1 is returned, otherwise 0.
- */
-pid_t check_pid (char *pidfile);
-
-/* write_pid
- *
- * Writes the pid to the specified file. If that fails 0 is
- * returned, otherwise the pid.
- */
-pid_t write_pid (char *pidfile);
-
-/* remove_pid
- *
- * Remove the the specified file. The result from unlink(2)
- * is returned
- */
-int remove_pid (char *pidfile);
-#endif
index 02b7b3443e626c268bead9bff0bccd03f094b596..1d46630b0782be4c1e35ff805c7fc38539535977 100644 (file)
@@ -31,8 +31,7 @@ volatile int cp_index = 0;
 
 const char hexadecimals[] = "0123456789ABCDEF";
 
-int charhex2bin(char c)
-{
+int charhex2bin(char c) {
        if(isdigit(c))
                return c - '0';
        else
@@ -40,15 +39,13 @@ int charhex2bin(char c)
 }
 
 
-void hex2bin(char *src, char *dst, int length)
-{
+void hex2bin(char *src, char *dst, int length) {
        int i;
        for(i = 0; i < length; i++)
                dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]);
 }
 
-void bin2hex(char *src, char *dst, int length)
-{
+void bin2hex(char *src, char *dst, int length) {
        int i;
        for(i = length - 1; i >= 0; i--) {
                dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
@@ -57,8 +54,7 @@ void bin2hex(char *src, char *dst, int length)
 }
 
 #ifdef ENABLE_TRACING
-void cp_trace()
-{
+void cp_trace() {
        logger(LOG_DEBUG, "Checkpoint trace: %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d <- %s:%d...",
                   cp_file[(cp_index + 15) % 16], cp_line[(cp_index + 15) % 16],
                   cp_file[(cp_index + 14) % 16], cp_line[(cp_index + 14) % 16],
index e1df6e789d0c9e3a9de77dff54eabe7428f2bdbe..f063083ad6965a58b34c4087f4affe2c60b7fa2d 100644 (file)
@@ -3,33 +3,61 @@
 
 # Package source files
 
-lib/pidfile.c
+lib/dropin.c
 lib/utils.c
-src/conf.c
+lib/memcmp.c
+lib/getopt.c
+lib/avl_tree.c
+lib/list.c
+lib/getopt1.c
+lib/xmalloc.c
+lib/fake-getaddrinfo.c
+lib/alloca.c
+lib/splay_tree.c
+lib/fake-getnameinfo.c
+lib/malloc.c
+lib/realloc.c
+src/tincctl.c
+src/subnet.c
+src/logger.c
+src/edge.c
+src/device.c
+src/protocol_key.c
+src/protocol_edge.c
+src/control.c
 src/connection.c
-src/meta.c
-src/net.c
+src/openssl/rsa.c
+src/openssl/digest.c
+src/openssl/cipher.c
+src/openssl/crypto.c
+src/protocol_auth.c
 src/net_packet.c
+src/rsa.c
+src/bsd/device.c
+src/graph.c
+src/raw_socket/device.c
 src/net_setup.c
+src/digest.c
+src/conf.c
+src/gcrypt/rsa.c
+src/gcrypt/digest.c
+src/gcrypt/cipher.c
+src/gcrypt/crypto.c
+src/uml_socket/device.c
+src/mingw/device.c
 src/net_socket.c
+src/meta.c
 src/netutl.c
+src/cygwin/device.c
+src/node.c
 src/protocol.c
-src/protocol_auth.c
-src/protocol_edge.c
-src/protocol_key.c
-src/protocol_misc.c
-src/protocol_subnet.c
-src/subnet.c
-src/tincd.c
 src/process.c
-src/route.c
-src/node.c
-src/edge.c
-src/graph.c
+src/protocol_subnet.c
+src/cipher.c
+src/net.c
 src/linux/device.c
+src/tincd.c
+src/crypto.c
 src/solaris/device.c
-src/bsd/device.c
-src/cygwin/device.c
-src/mingw/device.c
-src/raw_socket/device.c
-src/uml_socket/device.c
+src/route.c
+src/protocol_misc.c
index 1c60b28e6c02e35f90667ef709e4d651107ddee3..d67f25ede8635d597c94853a2b79c2345f809102 100644 (file)
--- a/po/nl.po
+++ b/po/nl.po
@@ -1,13 +1,13 @@
 # Dutch messages for tinc
-# Copyright (C) 1999-2008 Ivo Timmermans, Guus Sliepen.
+# Copyright (C) 1999-2007 Ivo Timmermans, Guus Sliepen.
 # Ivo Timmermans <ivo@tinc-vpn.org>, 1999-2006.
-# Guus Sliepen <guus@tinc-vpn.org>, 2000-2008.
+# Guus Sliepen <guus@tinc-vpn.org>, 2000-2007.
 msgid ""
 msgstr ""
 "Project-Id-Version: tinc 1.0-svn\n"
 "Report-Msgid-Bugs-To: tinc-devel@tinc-vpn.org\n"
-"POT-Creation-Date: 2008-12-24 11:43+0100\n"
-"PO-Revision-Date: 2008-12-24 11:45+0100\n"
+"POT-Creation-Date: 2007-03-07 18:48+0100\n"
+"PO-Revision-Date: 2007-01-05 14:14+0100\n"
 "Last-Translator: Guus Sliepen <guus@tinc-vpn.org>\n"
 "Language-Team: Dutch\n"
 "MIME-Version: 1.0\n"
@@ -90,16 +90,16 @@ msgstr "iedereen"
 msgid "BROADCAST"
 msgstr "BROADCAST"
 
-#: src/connection.c:142
+#: src/connection.c:115
 msgid "Connections:"
 msgstr "Verbindingen:"
 
-#: src/connection.c:146
+#: src/connection.c:119
 #, c-format
 msgid " %s at %s options %lx socket %d status %04x outbuf %d/%d/%d"
 msgstr " %s op %s opties %lx socket %d status %04x outbuf %d/%d/%d"
 
-#: src/connection.c:151
+#: src/connection.c:124
 msgid "End of connections."
 msgstr "Einde van verbindingen."
 
@@ -161,52 +161,57 @@ msgstr "Verwijderen onbereikbare nodes"
 msgid "Purging node %s (%s)"
 msgstr "Verwijdering node %s (%s)"
 
-#: src/net.c:173
+#: src/net.c:159
 #, c-format
 msgid "Closing connection with %s (%s)"
 msgstr "Beëindigen verbinding met %s (%s)"
 
-#: src/net.c:244
+#: src/net.c:230
 #, c-format
 msgid "%s (%s) didn't respond to PING in %ld seconds"
 msgstr "%s (%s) antwoordde niet binnen %ld seconden op PING"
 
-#: src/net.c:253
+#: src/net.c:239
 #, c-format
 msgid "Old connection_t for %s (%s) status %04x still lingering, deleting..."
 msgstr ""
 "Oude connection_t voor %s (%s) status %04x nog steeds aanwezig, wordt "
 "verwijderd..."
 
-#: src/net.c:258
+#: src/net.c:244
 #, c-format
 msgid "Timeout from %s (%s) during authentication"
 msgstr "Timeout van %s (%s) tijdens authenticatie"
 
-#: src/net.c:273
+#: src/net.c:259
 #, c-format
 msgid "%s (%s) could not flush for %ld seconds (%d bytes remaining)"
 msgstr "%s (%s) kon niet binnen %ld seconden wegschrijven (%d bytes over)"
 
-#: src/net.c:318
+#: src/net.c:286
 #, c-format
 msgid "Error while connecting to %s (%s): %s"
 msgstr "Fout tijdens schrijven naar %s (%s): %s"
 
-#: src/net.c:383
+#: src/net.c:345
+#, fuzzy, c-format
+msgid "Error building fdset: %s"
+msgstr "Fout tijdens lezen van standaardinvoer: %s\n"
+
+#: src/net.c:354
 #, c-format
 msgid "Error while waiting for input: %s"
 msgstr "Fout tijdens wachten op invoer: %s"
 
-#: src/net.c:414
+#: src/net.c:383
 msgid "Regenerating symmetric key"
 msgstr "Hergenereren symmetrische sleutel"
 
-#: src/net.c:431
+#: src/net.c:400
 msgid "Flushing event queue"
 msgstr "Legen taakrij"
 
-#: src/net.c:450
+#: src/net.c:419
 msgid "Unable to reread configuration file, exitting."
 msgstr "Kan configuratiebestand niet herlezen, beëindigen."
 
@@ -287,13 +292,13 @@ msgstr "Fout tijdens versleutelen pakket naar %s (%s): %s"
 msgid "Setting outgoing packet priority to %d"
 msgstr "Instellen prioriteit uitgaand pakket op %d"
 
-#: src/net_packet.c:393 src/net_setup.c:478 src/net_socket.c:140
-#: src/net_socket.c:169 src/tincd.c:435 src/tincd.c:472 src/process.c:201
-#: src/process.c:234 src/process.c:433 src/bsd/device.c:93
+#: src/net_packet.c:393 src/net_setup.c:487 src/net_socket.c:129
+#: src/net_socket.c:158 src/tincd.c:435 src/tincd.c:477 src/process.c:198
+#: src/process.c:231 src/process.c:430 src/bsd/device.c:93
 #: src/bsd/device.c:112 src/cygwin/device.c:140 src/cygwin/device.c:171
-#: src/mingw/device.c:73 src/mingw/device.c:80 src/mingw/device.c:86
-#: src/mingw/device.c:258 src/mingw/device.c:265 src/mingw/device.c:270
-#: src/mingw/device.c:277 src/mingw/device.c:286 src/mingw/device.c:293
+#: src/mingw/device.c:73 src/mingw/device.c:82 src/mingw/device.c:87
+#: src/mingw/device.c:256 src/mingw/device.c:263 src/mingw/device.c:268
+#: src/mingw/device.c:275 src/mingw/device.c:284 src/mingw/device.c:291
 #: src/uml_socket/device.c:89 src/uml_socket/device.c:103
 #: src/uml_socket/device.c:130 src/uml_socket/device.c:194
 #, c-format
@@ -340,113 +345,118 @@ msgstr "Ontvangst pakket mislukt: %s"
 msgid "Received UDP packet from unknown source %s"
 msgstr "Ontvangst UDP pakket van onbekende oorsprong %s"
 
-#: src/net_setup.c:77 src/net_setup.c:94
+#: src/net_setup.c:78 src/net_setup.c:95
 #, c-format
 msgid "Error reading RSA public key file `%s': %s"
 msgstr "Fout tijdens lezen RSA publieke sleutel bestand `%s': %s"
 
-#: src/net_setup.c:109
+#: src/net_setup.c:110
 #, c-format
 msgid "Reading RSA public key file `%s' failed: %s"
 msgstr "Lezen RSA publieke sleutel bestand `%s' mislukt: %s"
 
-#: src/net_setup.c:145
+#: src/net_setup.c:146
 #, c-format
 msgid "No public key for %s specified!"
 msgstr "Geen publieke sleutel bekend voor %s gespecificeerd!"
 
-#: src/net_setup.c:160
+#: src/net_setup.c:161
 msgid "PrivateKey used but no PublicKey found!"
 msgstr "PrivateKey gebruikt maar geen PublicKey gevonden!"
 
-#: src/net_setup.c:179
+#: src/net_setup.c:180
 #, c-format
 msgid "Error reading RSA private key file `%s': %s"
 msgstr "Fout tijdens lezen RSA privé sleutel bestand `%s': %s"
 
-#: src/net_setup.c:187
+#: src/net_setup.c:188
 #, c-format
 msgid "Could not stat RSA private key file `%s': %s'"
 msgstr "Kon gegevens RSA privé sleutel bestand `%s' niet opvragen: %s"
 
-#: src/net_setup.c:194
+#: src/net_setup.c:195
 #, c-format
 msgid "Warning: insecure file permissions for RSA private key file `%s'!"
 msgstr ""
 "Waarschuwing: onveilige permissies voor RSA privé sleutel bestand `%s'!"
 
-#: src/net_setup.c:201
+#: src/net_setup.c:202
 #, c-format
 msgid "Reading RSA private key file `%s' failed: %s"
 msgstr "Fout tijdens lezen RSA privé sleutel bestand `%s': %s"
 
-#: src/net_setup.c:231 src/net_setup.c:232
+#: src/net_setup.c:232 src/net_setup.c:233
 msgid "MYSELF"
 msgstr "MIJZELF"
 
-#: src/net_setup.c:238
+#: src/net_setup.c:239
 msgid "Name for tinc daemon required!"
 msgstr "Naam voor tinc daemon verplicht!"
 
-#: src/net_setup.c:243
+#: src/net_setup.c:244
 msgid "Invalid name for myself!"
 msgstr "Ongeldige naam voor mijzelf!"
 
-#: src/net_setup.c:252
+#: src/net_setup.c:253
 msgid "Cannot open host configuration file for myself!"
 msgstr "Kan host configuratie bestand voor mijzelf niet openen!"
 
-#: src/net_setup.c:305
+#: src/net_setup.c:306
 msgid "Invalid routing mode!"
 msgstr "Ongeldige routing modus!"
 
-#: src/net_setup.c:316
+#: src/net_setup.c:317
 msgid "PriorityInheritance not supported on this platform"
 msgstr "PriorityInheritance wordt niet ondersteund op dit platform"
 
-#: src/net_setup.c:324
+#: src/net_setup.c:325
 msgid "Bogus maximum timeout!"
 msgstr "Onzinnige maximum timeout!"
 
-#: src/net_setup.c:338
+#: src/net_setup.c:339
 msgid "Invalid address family!"
 msgstr "Ongeldige adresfamilie!"
 
-#: src/net_setup.c:356
+#: src/net_setup.c:357
 msgid "Unrecognized cipher type!"
 msgstr "Onbekend cipher type!"
 
-#: src/net_setup.c:381 src/protocol_auth.c:194
+#: src/net_setup.c:382 src/protocol_auth.c:194
 #, c-format
 msgid "Error during initialisation of cipher for %s (%s): %s"
 msgstr "Fout tijdens initialisatie van cipher voor %s (%s): %s"
 
-#: src/net_setup.c:398
+#: src/net_setup.c:399
 msgid "Unrecognized digest type!"
 msgstr "Onbekend digest type!"
 
-#: src/net_setup.c:411
+#: src/net_setup.c:412
 msgid "MAC length exceeds size of digest!"
 msgstr "MAC lengte is groter dan dat van digest!"
 
-#: src/net_setup.c:414
+#: src/net_setup.c:415
 msgid "Bogus MAC length!"
 msgstr "Onzinnige MAC lengte!"
 
-#: src/net_setup.c:428
+#: src/net_setup.c:429
 msgid "Bogus compression level!"
 msgstr "Onzinnig compressieniveau!"
 
-#: src/net_setup.c:500
+#: src/net_setup.c:454 src/net_setup.c:514 src/net_setup.c:525
+#, fuzzy, c-format
+msgid "event_add failed: %s"
+msgstr "Ontvangst pakket mislukt: %s"
+
+#: src/net_setup.c:534
 #, c-format
 msgid "Listening on %s"
 msgstr "Luisterend op %s"
 
-#: src/net_setup.c:511
+#: src/net_setup.c:545
 msgid "Ready"
 msgstr "Gereed"
 
-#: src/net_setup.c:513
+#: src/net_setup.c:547
 msgid "Unable to create any listening socket!"
 msgstr "Kon geen enkele luistersocket aanmaken!"
 
@@ -455,96 +465,86 @@ msgstr "Kon geen enkele luistersocket aanmaken!"
 msgid "fcntl for %s: %s"
 msgstr "fcntl voor %s: %s"
 
-#: src/net_socket.c:69
-#, c-format
-msgid "ioctlsocket for %s: WSA error %d"
-msgstr "ioctlsocket voor %s: WSA fout %d"
-
-#: src/net_socket.c:96
+#: src/net_socket.c:90
 #, c-format
 msgid "Creating metasocket failed: %s"
 msgstr "Aanmaak van metasocket mislukt: %s"
 
-#: src/net_socket.c:120 src/net_socket.c:227
+#: src/net_socket.c:109 src/net_socket.c:201
 #, c-format
 msgid "Can't bind to interface %s: %s"
 msgstr "Kan niet aan interface %s binden: %s"
 
-#: src/net_socket.c:125
+#: src/net_socket.c:114
 msgid "BindToInterface not supported on this platform"
 msgstr "BindToInterface wordt niet ondersteund op dit platform"
 
-#: src/net_socket.c:132
+#: src/net_socket.c:121
 #, c-format
 msgid "Can't bind to %s/tcp: %s"
 msgstr "Kan niet aan %s/tcp binden: %s"
 
-#: src/net_socket.c:159
+#: src/net_socket.c:148
 #, c-format
 msgid "Creating UDP socket failed: %s"
 msgstr "Aanmaak UDP socket mislukte: %s"
 
-#: src/net_socket.c:179
-#, c-format
-msgid "Call to `%s' failed: WSA error %d"
-msgstr "Systeemaanroep `%s' mislukte: WSA fout %d"
-
-#: src/net_socket.c:238
+#: src/net_socket.c:212
 #, c-format
 msgid "Can't bind to %s/udp: %s"
 msgstr "Kan niet aan %s/udp binden: %s"
 
-#: src/net_socket.c:265
+#: src/net_socket.c:239
 #, c-format
 msgid "Trying to re-establish outgoing connection in %d seconds"
 msgstr "Poging tot herstellen van uitgaande verbinding over %d seconden"
 
-#: src/net_socket.c:273
+#: src/net_socket.c:247
 #, c-format
 msgid "Connected to %s (%s)"
 msgstr "Verbonden met %s (%s)"
 
-#: src/net_socket.c:292
+#: src/net_socket.c:266
 #, c-format
 msgid "Could not set up a meta connection to %s"
 msgstr "Kon geen metaverbinding aangaan met %s"
 
-#: src/net_socket.c:327
+#: src/net_socket.c:300
 #, c-format
 msgid "Trying to connect to %s (%s)"
 msgstr "Poging tot verbinden met %s (%s)"
 
-#: src/net_socket.c:333
+#: src/net_socket.c:306
 #, c-format
 msgid "Creating socket for %s failed: %s"
 msgstr "Aanmaken socket voor %s mislukt: %s"
 
-#: src/net_socket.c:365
+#: src/net_socket.c:328
 #, c-format
 msgid "%s: %s"
 msgstr "%s: %s"
 
-#: src/net_socket.c:386
+#: src/net_socket.c:349
 #, c-format
 msgid "Already connected to %s"
 msgstr "Reeds verbonden met %s"
 
-#: src/net_socket.c:405
+#: src/net_socket.c:368
 #, c-format
 msgid "No address specified for %s"
 msgstr "Geen adres gespecificeerd voor %s"
 
-#: src/net_socket.c:436
+#: src/net_socket.c:399
 #, c-format
 msgid "Accepting a new connection failed: %s"
 msgstr "Aanname van nieuwe verbinding is mislukt: %s"
 
-#: src/net_socket.c:455
+#: src/net_socket.c:417
 #, c-format
 msgid "Connection from %s"
 msgstr "Verbinding van %s"
 
-#: src/net_socket.c:480
+#: src/net_socket.c:440
 #, c-format
 msgid "Invalid name for outgoing connection in %s line %d"
 msgstr "Ongeldige naam voor uitgaande verbinding in %s regel %d"
@@ -647,7 +647,7 @@ msgstr "Veroudering vorige verzoeken: %d gewist, %d overgebleven"
 #: src/protocol_auth.c:58 src/protocol_auth.c:214 src/protocol_auth.c:345
 #: src/protocol_auth.c:412 src/protocol_auth.c:538 src/protocol_edge.c:73
 #: src/protocol_edge.c:188 src/protocol_key.c:62 src/protocol_key.c:105
-#: src/protocol_key.c:179 src/protocol_misc.c:56 src/protocol_misc.c:85
+#: src/protocol_key.c:173 src/protocol_misc.c:56 src/protocol_misc.c:85
 #: src/protocol_misc.c:176 src/protocol_subnet.c:58 src/protocol_subnet.c:170
 #, c-format
 msgid "Got bad %s from %s (%s)"
@@ -681,7 +681,7 @@ msgstr "Ander %s heeft onbekende identiteit (%s)"
 msgid "Generated random meta key (unencrypted): %s"
 msgstr "Willekeurige meta sleutel aangemaakt (niet versleuteld): %s"
 
-#: src/protocol_auth.c:170
+#: src/protocol_auth.c:170 src/protocol_auth.c:243
 #, c-format
 msgid "Error during encryption of meta key for %s (%s)"
 msgstr "Fout tijdens versleutelen van meta key voor %s (%s)"
@@ -692,11 +692,6 @@ msgstr "Fout tijdens versleutelen van meta key voor %s (%s)"
 msgid "Possible intruder %s (%s): %s"
 msgstr "Mogelijke indringer %s (%s): %s"
 
-#: src/protocol_auth.c:243
-#, c-format
-msgid "Error during decryption of meta key for %s (%s)"
-msgstr "Fout tijdens ontsleutelen van meta key voor %s (%s)"
-
 #: src/protocol_auth.c:251
 #, c-format
 msgid "Received random meta key (unencrypted): %s"
@@ -712,7 +707,7 @@ msgstr "%s (%s) gebruikt onbekende cipher!"
 msgid "Error during initialisation of cipher from %s (%s): %s"
 msgstr "Fout tijdens initalisatie van cipher van %s (%s): %s"
 
-#: src/protocol_auth.c:286 src/protocol_key.c:255
+#: src/protocol_auth.c:286 src/protocol_key.c:243
 #, c-format
 msgid "Node %s (%s) uses unknown digest!"
 msgstr "Node %s (%s) gebruikt onbekende digest!"
@@ -791,14 +786,14 @@ msgstr "Kreeg %s van %s (%s) voor onszelf"
 msgid "Got %s from %s (%s) origin %s which does not exist"
 msgstr "Kreeg %s van %s (%s) herkomst %s welke niet bestaat"
 
-#: src/protocol_key.c:113 src/protocol_key.c:187
+#: src/protocol_key.c:113 src/protocol_key.c:181
 #, c-format
 msgid ""
 "Got %s from %s (%s) origin %s which does not exist in our connection list"
 msgstr ""
 "Kreeg %s van %s (%s) herkomst %s welke niet voorkomt in de verbindingslijst"
 
-#: src/protocol_key.c:121 src/protocol_key.c:195
+#: src/protocol_key.c:121 src/protocol_key.c:189
 #, c-format
 msgid ""
 "Got %s from %s (%s) destination %s which does not exist in our connection "
@@ -806,32 +801,27 @@ msgid ""
 msgstr ""
 "Kreeg %s van %s (%s) doel %s welke niet voorkomt in de verbindingslijst"
 
-#: src/protocol_key.c:138 src/protocol_key.c:207
-#, c-format
-msgid "Got %s from %s (%s) destination %s which is not reachable"
-msgstr "Kreeg %s van %s (%s) doel %s welke niet bereikbaar is"
-
-#: src/protocol_key.c:235
+#: src/protocol_key.c:223
 #, c-format
 msgid "Node %s (%s) uses unknown cipher!"
 msgstr "Node %s (%s) gebruikt onbekende cipher!"
 
-#: src/protocol_key.c:241
+#: src/protocol_key.c:229
 #, c-format
 msgid "Node %s (%s) uses wrong keylength!"
 msgstr "Node %s (%s) gebruikt verkeerde lengte sleutel!"
 
-#: src/protocol_key.c:261
+#: src/protocol_key.c:249
 #, c-format
 msgid "Node %s (%s) uses bogus MAC length!"
 msgstr "Node %s (%s) gebruikt onzinnige MAC lengte!"
 
-#: src/protocol_key.c:270
+#: src/protocol_key.c:258
 #, c-format
 msgid "Node %s (%s) uses bogus compression level!"
 msgstr "Node %s (%s) gebruikt onzinnig compressieniveau!"
 
-#: src/protocol_key.c:278
+#: src/protocol_key.c:266
 #, c-format
 msgid "Error during initialisation of key from %s (%s): %s"
 msgstr "Fout tijdens initialisatie van sleutel van %s (%s): %s"
@@ -866,26 +856,26 @@ msgid "subnet_compare() was called with unknown subnet type %d, exitting!"
 msgstr ""
 "subnet_compare() werd aangeroepen met onbekend subnet type %d, beëindigen!"
 
-#: src/subnet.c:263
+#: src/subnet.c:251
 #, c-format
 msgid "net2str() was called with netstr=%p, subnet=%p!\n"
 msgstr "net2str() werd aangeroepen met netstr=%p, subnet=%p!\n"
 
-#: src/subnet.c:300
+#: src/subnet.c:288
 #, c-format
 msgid "net2str() was called with unknown subnet type %d, exiting!"
 msgstr "net2str() werd aangeroepen met onbekend subnet type %d, beëindigen!"
 
-#: src/subnet.c:465
+#: src/subnet.c:449
 msgid "Subnet list:"
 msgstr "Subnet lijst:"
 
-#: src/subnet.c:471
+#: src/subnet.c:455
 #, c-format
 msgid " %s owner %s"
 msgstr " %s eigenaar %s"
 
-#: src/subnet.c:474
+#: src/subnet.c:458
 msgid "End of subnet list."
 msgstr "Einde van subnet lijst."
 
@@ -1002,14 +992,14 @@ msgstr "%s versie %s (gemaakt %s %s, protocol %d)\n"
 #: src/tincd.c:411
 #, c-format
 msgid ""
-"Copyright (C) 1998-2008 Ivo Timmermans, Guus Sliepen and others.\n"
+"Copyright (C) 1998-2007 Ivo Timmermans, Guus Sliepen and others.\n"
 "See the AUTHORS file for a complete list.\n"
 "\n"
 "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
 "and you are welcome to redistribute it under certain conditions;\n"
 "see the file COPYING for details.\n"
 msgstr ""
-"Copyright (C) 1998-2008 Ivo Timmermans, Guus Sliepen en anderen.\n"
+"Copyright (C) 1998-2007 Ivo Timmermans, Guus Sliepen en anderen.\n"
 "Zie het bestand AUTHORS voor een volledige lijst.\n"
 "\n"
 "tinc wordt gedistribueerd ZONDER ENIGE GARANTIE.  Dit is vrije "
@@ -1022,10 +1012,15 @@ msgid "mlockall() not supported on this platform!"
 msgstr "mlockall() wordt niet ondersteund op dit platform!"
 
 #: src/tincd.c:466
+#, fuzzy
+msgid "Error initializing libevent!"
+msgstr "Fout tijdens initialiseren LZO compressor!"
+
+#: src/tincd.c:471
 msgid "Error initializing LZO compressor!"
 msgstr "Fout tijdens initialiseren LZO compressor!"
 
-#: src/tincd.c:507
+#: src/tincd.c:512
 msgid "Terminating"
 msgstr "Beëindigen"
 
@@ -1084,121 +1079,121 @@ msgstr "Kon %s service niet verwijderen: %s"
 msgid "%s service removed"
 msgstr "%s service verwijderd"
 
-#: src/process.c:161 src/process.c:164
+#: src/process.c:158 src/process.c:161
 #, c-format
 msgid "Got %s request"
 msgstr "Kreeg %s verzoek"
 
-#: src/process.c:167
+#: src/process.c:164
 #, c-format
 msgid "Got unexpected request %d"
 msgstr "Kreeg onverwacht verzoek %d"
 
-#: src/process.c:255
+#: src/process.c:252
 #, c-format
 msgid "A tincd is already running for net `%s' with pid %ld.\n"
 msgstr "Een tincd draait al voor net `%s' met pid %ld.\n"
 
-#: src/process.c:258
+#: src/process.c:255
 #, c-format
 msgid "A tincd is already running with pid %ld.\n"
 msgstr "Een tincd draait al met pid %ld.\n"
 
-#: src/process.c:264
+#: src/process.c:261
 #, c-format
 msgid "Could write pid file %s: %s\n"
 msgstr "Kon pid bestand %s niet openen: %s\n"
 
-#: src/process.c:286
+#: src/process.c:283
 #, c-format
 msgid "No other tincd is running for net `%s'.\n"
 msgstr "Geen andere tincd draait voor net `%s'.\n"
 
-#: src/process.c:289
+#: src/process.c:286
 #, c-format
 msgid "No other tincd is running.\n"
 msgstr "Geen andere tincd draait.\n"
 
-#: src/process.c:298
+#: src/process.c:295
 #, c-format
 msgid "The tincd for net `%s' is no longer running. "
 msgstr "De tincd voor net `%s' draait niet meer. "
 
-#: src/process.c:301
+#: src/process.c:298
 #, c-format
 msgid "The tincd is no longer running. "
 msgstr "De tincd draait niet meer. "
 
-#: src/process.c:303
+#: src/process.c:300
 #, c-format
 msgid "Removing stale lock file.\n"
 msgstr "Verwijdering oud vergrendelingsbestand.\n"
 
-#: src/process.c:336
+#: src/process.c:333
 #, c-format
 msgid "Couldn't detach from terminal: %s"
 msgstr "Kon niet ontkoppelen van terminal: %s"
 
-#: src/process.c:344
+#: src/process.c:341
 #, c-format
 msgid "Could not write pid file %s: %s\n"
 msgstr "Kon pid bestand %s niet schrijven: %s\n"
 
-#: src/process.c:355
+#: src/process.c:352
 #, c-format
 msgid "tincd %s (%s %s) starting, debug level %d"
 msgstr "tincd %s (%s %s) start, debug niveau %d"
 
-#: src/process.c:390
+#: src/process.c:387
 #, c-format
 msgid "Executing script %s"
 msgstr "Uitvoeren script %s"
 
-#: src/process.c:420
+#: src/process.c:417
 #, c-format
 msgid "Script %s exited with non-zero status %d"
 msgstr "Script %s beëindigde met status %d"
 
-#: src/process.c:425
+#: src/process.c:422
 #, c-format
 msgid "Script %s was killed by signal %d (%s)"
 msgstr "Script %s was gestopt door signaal %d (%s)"
 
-#: src/process.c:429
+#: src/process.c:426
 #, c-format
 msgid "Script %s terminated abnormally"
 msgstr "Script %s abnormaal beëindigd"
 
-#: src/process.c:449 src/process.c:458 src/process.c:499 src/process.c:505
-#: src/process.c:523
+#: src/process.c:446 src/process.c:455 src/process.c:496 src/process.c:502
+#: src/process.c:520
 #, c-format
 msgid "Got %s signal"
 msgstr "Kreeg %s signaal"
 
-#: src/process.c:467
+#: src/process.c:464
 #, c-format
 msgid "Got another fatal signal %d (%s): not restarting."
 msgstr "Kreeg nog een fataal signaal %d (%s): geen herstart."
 
-#: src/process.c:476
+#: src/process.c:473
 #, c-format
 msgid "Got fatal signal %d (%s)"
 msgstr "Kreeg fataal signaal %d (%s)"
 
-#: src/process.c:480
+#: src/process.c:477
 msgid "Trying to re-execute in 5 seconds..."
 msgstr "Poging tot herstarten over 5 seconden..."
 
-#: src/process.c:492
+#: src/process.c:489
 msgid "Not restarting."
 msgstr "Geen herstart."
 
-#: src/process.c:508
+#: src/process.c:505
 #, c-format
 msgid "Reverting to old debug level (%d)"
 msgstr "Herstellen van oud debug niveau (%d)"
 
-#: src/process.c:514
+#: src/process.c:511
 #, c-format
 msgid ""
 "Temporarily setting debug level to 5.  Kill me with SIGINT again to go back "
@@ -1207,17 +1202,17 @@ msgstr ""
 "Tijdelijk instellen debug niveau op 5. Zend nog een SIGINT signaal om niveau "
 "%d te herstellen."
 
-#: src/process.c:547
+#: src/process.c:544
 #, c-format
 msgid "Got unexpected signal %d (%s)"
 msgstr "Kreeg onverwacht signaal %d (%s)"
 
-#: src/process.c:553
+#: src/process.c:550
 #, c-format
 msgid "Ignored signal %d (%s)"
 msgstr "Signaal %d (%s) genegeerd"
 
-#: src/process.c:607
+#: src/process.c:604
 #, c-format
 msgid "Installing signal handler for signal %d (%s) failed: %s\n"
 msgstr "Installeren van signaal afhandelaar voor signaal %d (%s) faalde: %s\n"
@@ -1232,7 +1227,7 @@ msgstr "Nieuw MAC adres %hx:%hx:%hx:%hx:%hx:%hx geleerd"
 msgid "Subnet %s expired"
 msgstr "Subnet %s is verlopen"
 
-#: src/route.c:190 src/route.c:345 src/route.c:496
+#: src/route.c:190 src/route.c:345 src/route.c:489
 #, c-format
 msgid "Packet looping back to %s (%s)!"
 msgstr "Pakket komt terug naar %s (%s)!"
@@ -1256,12 +1251,12 @@ msgid ""
 msgstr ""
 "Kan pakket van %s (%s) niet routeren: onbekend IPv4 doeladres %d.%d.%d.%d"
 
-#: src/route.c:358 src/route.c:506
+#: src/route.c:358 src/route.c:499
 #, c-format
 msgid "Packet for %s (%s) length %d larger than MTU %d"
 msgstr "Packet voor %s (%s) lengte %d groter dan MTU %d"
 
-#: src/route.c:480
+#: src/route.c:473
 #, c-format
 msgid ""
 "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%"
@@ -1270,26 +1265,26 @@ msgstr ""
 "Kan pakket van %s (%s) niet routeren: onbekend IPv6 doeladres %hx:%hx:%hx:%"
 "hx:%hx:%hx:%hx:%hx"
 
-#: src/route.c:538
+#: src/route.c:531
 #, c-format
 msgid "Got neighbor solicitation request from %s (%s) while in router mode!"
 msgstr ""
 "Kreeg neighbor solicitation request van %s (%s) terwijl we in router mode "
 "werken!"
 
-#: src/route.c:557
+#: src/route.c:550
 msgid ""
 "Cannot route packet: received unknown type neighbor solicitation request"
 msgstr ""
 "Kan pakket niet routeren: ontvangst van onbekend type neighbor solicitation "
 "verzoek"
 
-#: src/route.c:576
+#: src/route.c:569
 msgid "Cannot route packet: checksum error for neighbor solicitation request"
 msgstr ""
 "Kan pakket niet routeren: checksum fout voor neighbor solicitation verzoek"
 
-#: src/route.c:585
+#: src/route.c:578
 #, c-format
 msgid ""
 "Cannot route packet: neighbor solicitation request for unknown address %hx:%"
@@ -1298,21 +1293,21 @@ msgstr ""
 "Kan pakket niet routeren: neighbor solicitation verzoek voor onbekend adres %"
 "hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"
 
-#: src/route.c:675
+#: src/route.c:665
 #, c-format
 msgid "Got ARP request from %s (%s) while in router mode!"
 msgstr "Kreeg ARP request van %s (%s) terwijl we in router mode werken!"
 
-#: src/route.c:692
+#: src/route.c:682
 msgid "Cannot route packet: received unknown type ARP request"
 msgstr "Kan pakket niet routeren: ontvangst van onbekend type ARP verzoek"
 
-#: src/route.c:701
+#: src/route.c:691
 #, c-format
 msgid "Cannot route packet: ARP request for unknown address %d.%d.%d.%d"
 msgstr "Kan pakket niet routeren: ARP verzoek voor onbekend adres %d.%d.%d.%d"
 
-#: src/route.c:757
+#: src/route.c:747
 #, c-format
 msgid "Cannot route packet from %s (%s): unknown type %hx"
 msgstr "Kan pakket van %s (%s) niet routeren: onbekend type %hx"
@@ -1388,22 +1383,22 @@ msgstr "%s is een %s"
 
 #: src/linux/device.c:133 src/linux/device.c:144 src/linux/device.c:155
 #: src/solaris/device.c:125 src/bsd/device.c:152 src/bsd/device.c:181
-#: src/bsd/device.c:210 src/cygwin/device.c:239 src/mingw/device.c:112
-#: src/mingw/device.c:325 src/raw_socket/device.c:102
+#: src/bsd/device.c:210 src/cygwin/device.c:239 src/mingw/device.c:110
+#: src/mingw/device.c:323 src/raw_socket/device.c:102
 #: src/uml_socket/device.c:239
 #, c-format
 msgid "Error while reading from %s %s: %s"
 msgstr "Fout tijdens lezen van %s %s: %s"
 
 #: src/linux/device.c:166 src/solaris/device.c:150 src/bsd/device.c:224
-#: src/cygwin/device.c:248 src/mingw/device.c:335 src/raw_socket/device.c:111
+#: src/cygwin/device.c:248 src/mingw/device.c:333 src/raw_socket/device.c:111
 #: src/uml_socket/device.c:249
 #, c-format
 msgid "Read packet of %d bytes from %s"
 msgstr "Pakket van %d bytes gelezen van %s"
 
 #: src/linux/device.c:176 src/solaris/device.c:160 src/bsd/device.c:234
-#: src/cygwin/device.c:260 src/mingw/device.c:348 src/raw_socket/device.c:121
+#: src/cygwin/device.c:260 src/mingw/device.c:346 src/raw_socket/device.c:121
 #: src/uml_socket/device.c:267
 #, c-format
 msgid "Writing packet of %d bytes to %s"
@@ -1417,21 +1412,21 @@ msgid "Can't write to %s %s: %s"
 msgstr "Kan niet schrijven naar %s %s: %s"
 
 #: src/linux/device.c:215 src/solaris/device.c:178 src/bsd/device.c:296
-#: src/cygwin/device.c:277 src/mingw/device.c:365 src/raw_socket/device.c:139
+#: src/cygwin/device.c:277 src/mingw/device.c:363 src/raw_socket/device.c:139
 #: src/uml_socket/device.c:288
 #, c-format
 msgid "Statistics for %s %s:"
 msgstr "Statistieken voor %s %s:"
 
 #: src/linux/device.c:216 src/solaris/device.c:179 src/bsd/device.c:297
-#: src/cygwin/device.c:278 src/mingw/device.c:366 src/raw_socket/device.c:140
+#: src/cygwin/device.c:278 src/mingw/device.c:364 src/raw_socket/device.c:140
 #: src/uml_socket/device.c:289
 #, c-format
 msgid " total bytes in:  %10d"
 msgstr " totaal aantal bytes in:  %10d"
 
 #: src/linux/device.c:217 src/solaris/device.c:180 src/bsd/device.c:298
-#: src/cygwin/device.c:279 src/mingw/device.c:367 src/raw_socket/device.c:141
+#: src/cygwin/device.c:279 src/mingw/device.c:365 src/raw_socket/device.c:141
 #: src/uml_socket/device.c:290
 #, c-format
 msgid " total bytes out: %10d"
@@ -1495,7 +1490,7 @@ msgid "Unknown address family %x while reading packet from %s %s"
 msgstr "Onbekende adresfamilie %x tijdens ontvangst pakket van %s %s"
 
 #: src/bsd/device.c:240 src/bsd/device.c:277 src/cygwin/device.c:264
-#: src/mingw/device.c:352
+#: src/mingw/device.c:350
 #, c-format
 msgid "Error while writing to %s %s: %s"
 msgstr "Fout tijdens schrijven naar %s %s: %s"
@@ -1505,12 +1500,12 @@ msgstr "Fout tijdens schrijven naar %s %s: %s"
 msgid "Unknown address family %x while writing packet to %s %s"
 msgstr "Onbekende adresfamiliy %x tijdens versturen pakket naar %s %s"
 
-#: src/cygwin/device.c:71 src/mingw/device.c:159
+#: src/cygwin/device.c:71 src/mingw/device.c:157
 #, c-format
 msgid "Unable to read registry: %s"
 msgstr "Kon registry niet lezen: %s"
 
-#: src/cygwin/device.c:123 src/mingw/device.c:210
+#: src/cygwin/device.c:123 src/mingw/device.c:208
 msgid "No Windows tap device found!"
 msgstr "Geen Windows tap apparaat gevonden!"
 
@@ -1519,7 +1514,7 @@ msgstr "Geen Windows tap apparaat gevonden!"
 msgid "Could not open Windows tap device %s (%s) for writing: %s"
 msgstr "Kon Windows tap apparaat %s (%s) niet openen om te schrijven: %s"
 
-#: src/cygwin/device.c:158 src/mingw/device.c:235
+#: src/cygwin/device.c:158 src/mingw/device.c:233
 #, c-format
 msgid "Could not get MAC address from Windows tap device %s (%s): %s"
 msgstr "Kon MAC adres niet achterhalen van Windows tap apparaat %s (%s): %s"
@@ -1537,20 +1532,20 @@ msgstr "Taplezer is geforked en draait."
 msgid "Tap reader failed!"
 msgstr "Taplezer faalde!"
 
-#: src/cygwin/device.c:214 src/mingw/device.c:304
+#: src/cygwin/device.c:214 src/mingw/device.c:302
 msgid "Windows tap device"
 msgstr "Windows tap apparaat"
 
-#: src/cygwin/device.c:216 src/mingw/device.c:306
+#: src/cygwin/device.c:216 src/mingw/device.c:304
 #, c-format
 msgid "%s (%s) is a %s"
 msgstr "%s (%s) is een %s"
 
-#: src/mingw/device.c:93
+#: src/mingw/device.c:91
 msgid "Tap reader running"
 msgstr "Taplezer draait"
 
-#: src/mingw/device.c:228
+#: src/mingw/device.c:226
 #, c-format
 msgid "%s (%s) is not a usable Windows tap device: %s"
 msgstr "%s (%s) is geen bruikbaar Windows tap apparaat: %s"
index 501fdf66953875873d88289e60dc36ea26308961..db90897ff60d1d01c71d20cf8f15d176880a1a20 100644 (file)
@@ -1,13 +1,15 @@
 ## Produce this file with automake to get Makefile.in
 # $Id: Makefile.am,v 1.4.4.33 2003/08/02 15:13:08 guus Exp $
 
-sbin_PROGRAMS = tincd
+sbin_PROGRAMS = tincd tincctl
 
 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
 
-tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c      \
+tincd_SOURCES = cipher.c conf.c connection.c control.c crypto.c digest.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 rsa.c subnet.c tincd.c
+
+tincctl_SOURCES = tincctl.c rsagen.c
 
 if TUNEMU
 tincd_SOURCES += bsd/tunemu.c
@@ -19,10 +21,10 @@ DEFAULT_INCLUDES =
 
 INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
 
-noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h meta.h net.h netutl.h node.h process.h   \
-       protocol.h route.h subnet.h bsd/tunemu.h
+noinst_HEADERS = cipher.h conf.h connection.h control.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h      \
+       protocol.h route.h rsa.h rsagen.h subnet.h bsd/tunemu.h
 
-LIBS = @LIBS@ @LIBINTL@
+LIBS = @LIBS@ @LIBGCRYPT_LIBS@ @LIBINTL@
 
 if TUNEMU
 LIBS += -lpcap
@@ -31,9 +33,12 @@ endif
 tincd_LDADD = \
        $(top_builddir)/lib/libvpn.a
 
+tincctl_LDADD = \
+       $(top_builddir)/lib/libvpn.a
+
 localedir = $(datadir)/locale
 
-AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\"
+AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
 
 dist-hook:
        rm -f `find . -type l`
index fe85d10fc534a166244457dbd01e0512b81c8afb..872ad92f818a6e26f69a5672d7d715d92bc409d6 100644 (file)
@@ -184,7 +184,7 @@ void close_device(void) {
 }
 
 bool read_packet(vpn_packet_t *packet) {
-       int lenin;
+       int inlen;
 
        cp();
 
@@ -193,13 +193,13 @@ bool read_packet(vpn_packet_t *packet) {
 #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
 #else
-                               lenin = read(device_fd, packet->data + 14, MTU - 14);
+                               inlen = read(device_fd, packet->data + 14, MTU - 14);
 #endif
 
-                       if(lenin <= 0) {
+                       if(inlen <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                                           device, strerror(errno));
                                return false;
@@ -221,14 +221,14 @@ bool read_packet(vpn_packet_t *packet) {
                                        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) {
+                       if((inlen = readv(device_fd, vector, 2)) <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                                           device, strerror(errno));
                                return false;
@@ -252,18 +252,18 @@ bool read_packet(vpn_packet_t *packet) {
                                        return false;
                        }
 
-                       packet->len = lenin + 10;
+                       packet->len = inlen + 10;
                        break;
                }
 
                case DEVICE_TYPE_TAP:
-                       if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
+                       if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                                           device, strerror(errno));
                                return false;
                        }
 
-                       packet->len = lenin;
+                       packet->len = inlen;
                        break;
 
                default:
@@ -279,8 +279,7 @@ bool read_packet(vpn_packet_t *packet) {
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
+bool write_packet(vpn_packet_t *packet) {
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
@@ -297,7 +296,7 @@ bool write_packet(vpn_packet_t *packet)
 
                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];
@@ -351,8 +350,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index d8a8d83214304e079d78f4324bc6685e153e1186..827da68181bfc2bbc8eb5d8083878b6a4dcbaf36 100644 (file)
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "conf.h"
 #include "logger.h"
 #include "netutl.h"                            /* for str2address */
 #include "utils.h"                             /* for cp */
 #include "xalloc.h"
 
-avl_tree_t *config_tree;
+splay_tree_t *config_tree;
 
 int pinginterval = 0;                  /* seconds between pings */
 int pingtimeout = 0;                   /* seconds to wait for response */
 char *confbase = NULL;                 /* directory in which all config files are */
 char *netname = NULL;                  /* name of the vpn network */
 
-static int config_compare(const config_t *a, const config_t *b)
-{
+static int config_compare(const config_t *a, const config_t *b) {
        int result;
 
        result = strcasecmp(a->variable, b->variable);
@@ -55,30 +54,26 @@ static int config_compare(const config_t *a, const config_t *b)
                return strcmp(a->file, b->file);
 }
 
-void init_configuration(avl_tree_t ** config_tree)
-{
+void init_configuration(splay_tree_t ** config_tree) {
        cp();
 
-       *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
+       *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
 }
 
-void exit_configuration(avl_tree_t ** config_tree)
-{
+void exit_configuration(splay_tree_t ** config_tree) {
        cp();
 
-       avl_delete_tree(*config_tree);
+       splay_delete_tree(*config_tree);
        *config_tree = NULL;
 }
 
-config_t *new_config(void)
-{
+config_t *new_config(void) {
        cp();
 
        return xmalloc_and_zero(sizeof(config_t));
 }
 
-void free_config(config_t *cfg)
-{
+void free_config(config_t *cfg) {
        cp();
 
        if(cfg->variable)
@@ -93,15 +88,13 @@ void free_config(config_t *cfg)
        free(cfg);
 }
 
-void config_add(avl_tree_t *config_tree, config_t *cfg)
-{
+void config_add(splay_tree_t *config_tree, config_t *cfg) {
        cp();
 
-       avl_insert(config_tree, cfg);
+       splay_insert(config_tree, cfg);
 }
 
-config_t *lookup_config(avl_tree_t *config_tree, char *variable)
-{
+config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
        config_t cfg, *found;
 
        cp();
@@ -110,7 +103,7 @@ config_t *lookup_config(avl_tree_t *config_tree, char *variable)
        cfg.file = "";
        cfg.line = 0;
 
-       found = avl_search_closest_greater(config_tree, &cfg);
+       found = splay_search_closest_greater(config_tree, &cfg);
 
        if(!found)
                return NULL;
@@ -121,14 +114,13 @@ config_t *lookup_config(avl_tree_t *config_tree, char *variable)
        return found;
 }
 
-config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
-{
-       avl_node_t *node;
+config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
+       splay_node_t *node;
        config_t *found;
 
        cp();
 
-       node = avl_search_node(config_tree, cfg);
+       node = splay_search_node(config_tree, cfg);
 
        if(node) {
                if(node->next) {
@@ -142,8 +134,7 @@ config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
        return NULL;
 }
 
-bool get_config_bool(const config_t *cfg, bool *result)
-{
+bool get_config_bool(const config_t *cfg, bool *result) {
        cp();
 
        if(!cfg)
@@ -163,8 +154,7 @@ bool get_config_bool(const config_t *cfg, bool *result)
        return false;
 }
 
-bool get_config_int(const config_t *cfg, int *result)
-{
+bool get_config_int(const config_t *cfg, int *result) {
        cp();
 
        if(!cfg)
@@ -179,8 +169,7 @@ bool get_config_int(const config_t *cfg, int *result)
        return false;
 }
 
-bool get_config_string(const config_t *cfg, char **result)
-{
+bool get_config_string(const config_t *cfg, char **result) {
        cp();
 
        if(!cfg)
@@ -191,8 +180,7 @@ bool get_config_string(const config_t *cfg, char **result)
        return true;
 }
 
-bool get_config_address(const config_t *cfg, struct addrinfo **result)
-{
+bool get_config_address(const config_t *cfg, struct addrinfo **result) {
        struct addrinfo *ai;
 
        cp();
@@ -213,8 +201,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result)
        return false;
 }
 
-bool get_config_subnet(const config_t *cfg, subnet_t ** result)
-{
+bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
        subnet_t subnet = {0};
 
        cp();
@@ -231,9 +218,9 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result)
        /* Teach newbies what subnets are... */
 
        if(((subnet.type == SUBNET_IPV4)
-               && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
+               && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
                || ((subnet.type == SUBNET_IPV6)
-               && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
+               && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) {
                logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
                           cfg->variable, cfg->file, cfg->line);
                return false;
@@ -254,8 +241,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result)
   given, and buf needs to be expanded, the var pointed to by buflen
   will be increased.
 */
-static char *readline(FILE * fp, char **buf, size_t *buflen)
-{
+static char *readline(FILE * fp, char **buf, size_t *buflen) {
        char *newline = NULL;
        char *p;
        char *line;                                     /* The array that contains everything that has been read so far */
@@ -319,8 +305,7 @@ static char *readline(FILE * fp, char **buf, size_t *buflen)
   Parse a configuration file and put the results in the configuration tree
   starting at *base.
 */
-int read_config_file(avl_tree_t *config_tree, const char *fname)
-{
+int read_config_file(splay_tree_t *config_tree, const char *fname) {
        int err = -2;                           /* Parse error */
        FILE *fp;
        char *buffer, *line;
@@ -410,8 +395,7 @@ int read_config_file(avl_tree_t *config_tree, const char *fname)
        return err;
 }
 
-bool read_server_config()
-{
+bool read_server_config() {
        char *fname;
        int x;
 
@@ -428,98 +412,3 @@ bool read_server_config()
 
        return x == 0;
 }
-
-FILE *ask_and_open(const char *filename, const char *what)
-{
-       FILE *r;
-       char *directory;
-       char *fn;
-
-       /* Check stdin and stdout */
-       if(!isatty(0) || !isatty(1)) {
-               /* Argh, they are running us from a script or something.  Write
-                  the files to the current directory and let them burn in hell
-                  for ever. */
-               fn = xstrdup(filename);
-       } else {
-               /* Ask for a file and/or directory name. */
-               fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
-                               what, filename);
-               fflush(stdout);
-
-               fn = readline(stdin, NULL, NULL);
-
-               if(!fn) {
-                       fprintf(stderr, _("Error while reading stdin: %s\n"),
-                                       strerror(errno));
-                       return NULL;
-               }
-
-               if(!strlen(fn))
-                       /* User just pressed enter. */
-                       fn = xstrdup(filename);
-       }
-
-#ifdef HAVE_MINGW
-       if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
-#else
-       if(fn[0] != '/') {
-#endif
-               /* The directory is a relative path or a filename. */
-               char *p;
-
-               directory = get_current_dir_name();
-               xasprintf(&p, "%s/%s", directory, fn);
-               free(fn);
-               free(directory);
-               fn = p;
-       }
-
-       umask(0077);                            /* Disallow everything for group and other */
-
-       /* Open it first to keep the inode busy */
-
-       r = fopen(fn, "r+") ?: fopen(fn, "w+");
-
-       if(!r) {
-               fprintf(stderr, _("Error opening file `%s': %s\n"),
-                               fn, strerror(errno));
-               free(fn);
-               return NULL;
-       }
-
-       free(fn);
-
-       return r;
-}
-
-bool disable_old_keys(FILE *f) {
-       char buf[100];
-       long pos;
-       bool disabled = false;
-
-       rewind(f);
-       pos = ftell(f);
-
-       while(fgets(buf, sizeof buf, f)) {
-               if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
-                       buf[11] = 'O';
-                       buf[12] = 'L';
-                       buf[13] = 'D';
-                       fseek(f, pos, SEEK_SET);
-                       fputs(buf, f);
-                       disabled = true;
-               }
-               else if(!strncmp(buf, "-----END RSA", 12)) {    
-                       buf[ 9] = 'O';
-                       buf[10] = 'L';
-                       buf[11] = 'D';
-                       fseek(f, pos, SEEK_SET);
-                       fputs(buf, f);
-                       disabled = true;
-               }
-               pos = ftell(f);
-       }
-
-       return disabled;
-}
index d1eae978e2ae0c155f02745356a10f83cb1c46f2..dfa1123100142dad2b2416e7afc55a5b26383577 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __TINC_CONF_H__
 #define __TINC_CONF_H__
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 
 typedef struct config_t {
        char *variable;
@@ -34,7 +34,7 @@ typedef struct config_t {
 
 #include "subnet.h"
 
-extern avl_tree_t *config_tree;
+extern splay_tree_t *config_tree;
 
 extern int pinginterval;
 extern int pingtimeout;
@@ -43,22 +43,22 @@ extern bool bypass_security;
 extern char *confbase;
 extern char *netname;
 
-extern void init_configuration(avl_tree_t **);
-extern void exit_configuration(avl_tree_t **);
+extern void init_configuration(splay_tree_t **);
+extern void exit_configuration(splay_tree_t **);
 extern config_t *new_config(void) __attribute__ ((__malloc__));
 extern void free_config(config_t *);
-extern void config_add(avl_tree_t *, config_t *);
-extern config_t *lookup_config(avl_tree_t *, char *);
-extern config_t *lookup_config_next(avl_tree_t *, const config_t *);
+extern void config_add(splay_tree_t *, config_t *);
+extern config_t *lookup_config(splay_tree_t *, char *);
+extern config_t *lookup_config_next(splay_tree_t *, const config_t *);
 extern bool get_config_bool(const config_t *, bool *);
 extern bool get_config_int(const config_t *, int *);
 extern bool get_config_string(const config_t *, char **);
 extern bool get_config_address(const config_t *, struct addrinfo **);
 extern bool get_config_subnet(const config_t *, struct subnet_t **);
 
-extern int read_config_file(avl_tree_t *, const char *);
+extern int read_config_file(splay_tree_t *, const char *);
 extern bool read_server_config(void);
-extern FILE *ask_and_open(const char *, const char *);
+extern FILE *ask_and_open(const char *, const char *, const char *);
 extern bool is_safe_path(const char *);
 extern bool disable_old_keys(FILE *);
 
index 283ebd7127d2462a8cc3ff3b3ddedf3347f659b6..4a2ba4c09110394e8654f4ecc3728484878ddf3f 100644 (file)
@@ -22,7 +22,8 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
+#include "cipher.h"
 #include "conf.h"
 #include "list.h"
 #include "logger.h"
 #include "utils.h"
 #include "xalloc.h"
 
-avl_tree_t *connection_tree;   /* Meta connections */
+splay_tree_t *connection_tree; /* Meta connections */
 connection_t *broadcast;
 
-static int connection_compare(const connection_t *a, const connection_t *b)
-{
+static int connection_compare(const connection_t *a, const connection_t *b) {
        return a < b ? -1 : a == b ? 0 : 1;
 }
 
-void init_connections(void)
-{
+void init_connections(void) {
        cp();
 
-       connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
+       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"));
 }
 
-void exit_connections(void)
-{
+void exit_connections(void) {
        cp();
 
-       avl_delete_tree(connection_tree);
+       splay_delete_tree(connection_tree);
        free_connection(broadcast);
 }
 
-connection_t *new_connection(void)
-{
-       connection_t *c;
-
+connection_t *new_connection(void) {
        cp();
 
-       c = xmalloc_and_zero(sizeof(connection_t));
-
-       if(!c)
-               return NULL;
-
-       gettimeofday(&c->start, NULL);
-
-       return c;
+       return xmalloc_and_zero(sizeof(connection_t));
 }
 
-void free_connection(connection_t *c)
-{
+void free_connection(connection_t *c) {
        cp();
 
+       if(!c)
+               return;
+
        if(c->name)
                free(c->name);
 
        if(c->hostname)
                free(c->hostname);
 
-       if(c->inkey)
-               free(c->inkey);
-
-       if(c->outkey)
-               free(c->outkey);
-
-       if(c->inctx) {
-               EVP_CIPHER_CTX_cleanup(c->inctx);
-               free(c->inctx);
-       }
-
-       if(c->outctx) {
-               EVP_CIPHER_CTX_cleanup(c->outctx);
-               free(c->outctx);
-       }
-
-       if(c->mychallenge)
-               free(c->mychallenge);
+       cipher_close(&c->incipher);
+       cipher_close(&c->outcipher);
 
        if(c->hischallenge)
                free(c->hischallenge);
@@ -109,50 +83,46 @@ void free_connection(connection_t *c)
        if(c->config_tree)
                exit_configuration(&c->config_tree);
 
-       if(c->outbuf)
-               free(c->outbuf);
-
-       if(c->rsa_key)
-               RSA_free(c->rsa_key);
+       if(c->buffer)
+               bufferevent_free(c->buffer);
+       
+       if(event_initialized(&c->inevent))
+               event_del(&c->inevent);
 
        free(c);
 }
 
-void connection_add(connection_t *c)
-{
+void connection_add(connection_t *c) {
        cp();
 
-       avl_insert(connection_tree, c);
+       splay_insert(connection_tree, c);
 }
 
-void connection_del(connection_t *c)
-{
+void connection_del(connection_t *c) {
        cp();
 
-       avl_delete(connection_tree, c);
+       splay_delete(connection_tree, c);
 }
 
-void dump_connections(void)
-{
-       avl_node_t *node;
+int dump_connections(struct evbuffer *out) {
+       splay_node_t *node;
        connection_t *c;
 
        cp();
 
-       logger(LOG_DEBUG, _("Connections:"));
-
        for(node = connection_tree->head; node; node = node->next) {
                c = node->data;
-               logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x outbuf %d/%d/%d"),
-                          c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status),
-                          c->outbufsize, c->outbufstart, c->outbuflen);
+               if(evbuffer_add_printf(out,
+                                  _(" %s at %s options %lx socket %d status %04x\n"),
+                                  c->name, c->hostname, c->options, c->socket,
+                                  bitfield_to_int(&c->status, sizeof c->status)) == -1)
+                       return errno;
        }
 
-       logger(LOG_DEBUG, _("End of connections."));
+       return 0;
 }
 
-bool read_connection_config(connection_t *c)
-{
+bool read_connection_config(connection_t *c) {
        char *fname;
        int x;
 
index 8948d4fae885589205c74c7c2348a79f071a8f05..e44af0b06a2412c9c021114dac35985404b48c40 100644 (file)
 #ifndef __TINC_CONNECTION_H__
 #define __TINC_CONNECTION_H__
 
-#include <openssl/rsa.h>
-#include <openssl/evp.h>
-
-#include "avl_tree.h"
+#include "cipher.h"
+#include "digest.h"
+#include "rsa.h"
+#include "splay_tree.h"
 
 #define OPTION_INDIRECT                0x0001
 #define OPTION_TCPONLY         0x0002
 #define OPTION_PMTU_DISCOVERY  0x0004
 
 typedef struct connection_status_t {
-       int pinged:1;                           /* sent ping */
-       int active:1;                           /* 1 if active.. */
-       int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
-       int termreq:1;                          /* the termination of this connection was requested */
-       int remove:1;                           /* Set to 1 if you want this connection removed */
-       int timeout:1;                          /* 1 if gotten timeout */
-       int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
-       int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
-       int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
-       int unused:23;
+               int pinged:1;                           /* sent ping */
+               int active:1;                           /* 1 if active.. */
+               int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
+               int termreq:1;                          /* the termination of this connection was requested */
+               int remove_unused:1;                            /* Set to 1 if you want this connection removed */
+               int timeout_unused:1;                           /* 1 if gotten timeout */
+               int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
+               int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
+               int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
+               int unused:23;
 } connection_status_t;
 
 #include "edge.h"
@@ -67,42 +67,30 @@ typedef struct connection_t {
        struct node_t *node;            /* node associated with the other end */
        struct edge_t *edge;            /* edge associated with this connection */
 
-       RSA *rsa_key;                           /* his public/private key */
-       const EVP_CIPHER *incipher;     /* Cipher he will use to send data to us */
-       const EVP_CIPHER *outcipher;    /* Cipher we will use to send data to him */
-       EVP_CIPHER_CTX *inctx;          /* Context of encrypted meta data that will come from him to us */
-       EVP_CIPHER_CTX *outctx;         /* Context of encrypted meta data that will be sent from us to him */
-       char *inkey;                            /* His symmetric meta key + iv */
-       char *outkey;                           /* Our symmetric meta key + iv */
-       int inkeylength;                        /* Length of his key + iv */
-       int outkeylength;                       /* Length of our key + iv */
-       const EVP_MD *indigest;
-       const EVP_MD *outdigest;
+       rsa_t rsa;                      /* his public/private key */
+       cipher_t incipher;              /* Cipher he will use to send data to us */
+       cipher_t outcipher;             /* Cipher we will use to send data to him */
+       digest_t indigest;
+       digest_t outdigest;
+
        int inmaclength;
        int outmaclength;
        int incompression;
        int outcompression;
-       char *mychallenge;                      /* challenge we received from him */
-       char *hischallenge;                     /* challenge we sent to him */
 
-       char buffer[MAXBUFSIZE];        /* metadata input buffer */
-       int buflen;                                     /* bytes read into buffer */
-       int reqlen;                                     /* length of incoming request */
+       char *hischallenge;             /* The challenge we sent to him */
+
+       struct bufferevent *buffer;                     /* buffer events on this metadata connection */
+       struct event inevent;                           /* input event on this metadata connection */
        int tcplen;                                     /* length of incoming TCPpacket */
        int allow_request;                      /* defined if there's only one request possible */
 
-       char *outbuf;                           /* metadata output buffer */
-       int outbufstart;                        /* index of first meaningful byte in output buffer */
-       int outbuflen;                          /* number of meaningful bytes in output buffer */
-       int outbufsize;                         /* number of bytes allocated to output buffer */
-
        time_t last_ping_time;          /* last time we saw some activity from the other end or pinged them */
-       time_t last_flushed_time;       /* last time buffer was empty. Only meaningful if outbuflen > 0 */
 
-       avl_tree_t *config_tree;        /* Pointer to configuration tree belonging to him */
+       splay_tree_t *config_tree;      /* Pointer to configuration tree belonging to him */
 } connection_t;
 
-extern avl_tree_t *connection_tree;
+extern splay_tree_t *connection_tree;
 extern connection_t *broadcast;
 
 extern void init_connections(void);
@@ -111,7 +99,7 @@ extern connection_t *new_connection(void) __attribute__ ((__malloc__));
 extern void free_connection(connection_t *);
 extern void connection_add(connection_t *);
 extern void connection_del(connection_t *);
-extern void dump_connections(void);
+extern int dump_connections(struct evbuffer *);
 extern bool read_connection_config(connection_t *);
 
 #endif                                                 /* __TINC_CONNECTION_H__ */
diff --git a/src/control.c b/src/control.c
new file mode 100644 (file)
index 0000000..19f074a
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+    control.c -- Control socket handling.
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include <sys/un.h>
+
+#include "system.h"
+#include "conf.h"
+#include "control.h"
+#include "control_common.h"
+#include "graph.h"
+#include "logger.h"
+#include "xalloc.h"
+
+static int control_socket = -1;
+static struct event control_event;
+static splay_tree_t *control_socket_tree;
+extern char *controlsocketname;
+
+static void handle_control_data(struct bufferevent *event, void *data) {
+       tinc_ctl_request_t req;
+       tinc_ctl_request_t res;
+       struct evbuffer *res_data = NULL;
+       void *req_data;
+
+       if(EVBUFFER_LENGTH(event->input) < sizeof req)
+               return;
+
+       /* Copy the structure to ensure alignment */
+       memcpy(&req, EVBUFFER_DATA(event->input), sizeof req);
+
+       if(EVBUFFER_LENGTH(event->input) < req.length)
+               return;
+       req_data = EVBUFFER_DATA(event->input) + sizeof req;
+
+       if(req.length < sizeof req)
+               goto failure;
+
+       memset(&res, 0, sizeof res);
+       res.type = req.type;
+       res.id = req.id;
+
+       res_data = evbuffer_new();
+       if(res_data == NULL) {
+               res.res_errno = ENOMEM;
+               goto respond;
+       }
+
+       if(req.type == REQ_STOP) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "stop");
+               event_loopexit(NULL);
+               goto respond;
+       }
+
+       if(req.type == REQ_DUMP_NODES) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "dump nodes");
+               res.res_errno = dump_nodes(res_data);
+               goto respond;
+       }
+
+       if(req.type == REQ_DUMP_EDGES) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "dump edges");
+               res.res_errno = dump_edges(res_data);
+               goto respond;
+       }
+
+       if(req.type == REQ_DUMP_SUBNETS) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "dump subnets");
+               res.res_errno = dump_subnets(res_data);
+               goto respond;
+       }
+
+       if(req.type == REQ_DUMP_CONNECTIONS) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "dump connections");
+               res.res_errno = dump_connections(res_data);
+               goto respond;
+       }
+
+       if(req.type == REQ_DUMP_GRAPH) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "dump graph");
+               res.res_errno = dump_graph(res_data);
+               goto respond;
+       }
+
+       if(req.type == REQ_PURGE) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "purge");
+               purge();
+               goto respond;
+       }
+
+       if(req.type == REQ_SET_DEBUG) {
+               debug_t new_debug_level;
+
+               logger(LOG_NOTICE, _("Got '%s' command"), "debug");
+               if(req.length != sizeof req + sizeof debug_level)
+                       res.res_errno = EINVAL;
+               else {
+                       memcpy(&new_debug_level, req_data, sizeof new_debug_level);
+                       logger(LOG_NOTICE, _("Changing debug level from %d to %d"),
+                                  debug_level, new_debug_level);
+                       if(evbuffer_add_printf(res_data,
+                                                                  _("Changing debug level from %d to %d\n"),
+                                                                  debug_level, new_debug_level) == -1)
+                               res.res_errno = errno;
+                       debug_level = new_debug_level;
+               }
+               goto respond;
+       }
+
+       if(req.type == REQ_RETRY) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "retry");
+               retry();
+               goto respond;
+       }
+
+       if(req.type == REQ_RELOAD) {
+               logger(LOG_NOTICE, _("Got '%s' command"), "reload");
+               res.res_errno = reload_configuration();
+               goto respond;
+       }
+
+       logger(LOG_DEBUG, _("Malformed control command received"));
+       res.res_errno = EINVAL;
+
+respond:
+       res.length = (sizeof res)
+                                + ((res_data == NULL) ? 0 : EVBUFFER_LENGTH(res_data));
+       evbuffer_drain(event->input, req.length);
+       if(bufferevent_write(event, &res, sizeof res) == -1)
+               goto failure;
+       if(res_data != NULL) {
+               if(bufferevent_write_buffer(event, res_data) == -1)
+                       goto failure;
+               evbuffer_free(res_data);
+       }
+       return;
+
+failure:
+       logger(LOG_INFO, _("Closing control socket on error"));
+       evbuffer_free(res_data);
+       close(event->ev_read.ev_fd);
+       splay_delete(control_socket_tree, event);
+}
+
+static void handle_control_error(struct bufferevent *event, short what, void *data) {
+       if(what & EVBUFFER_EOF)
+               logger(LOG_DEBUG, _("Control socket connection closed by peer"));
+       else
+               logger(LOG_DEBUG, _("Error while reading from control socket: %s"), strerror(errno));
+
+       close(event->ev_read.ev_fd);
+       splay_delete(control_socket_tree, event);
+}
+
+static void handle_new_control_socket(int fd, short events, void *data) {
+       int newfd;
+       struct bufferevent *ev;
+       tinc_ctl_greeting_t greeting;
+
+       newfd = accept(fd, NULL, NULL);
+
+       if(newfd < 0) {
+               logger(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno));
+               event_del(&control_event);
+               return;
+       }
+
+       ev = bufferevent_new(newfd, handle_control_data, NULL, handle_control_error, NULL);
+       if(!ev) {
+               logger(LOG_ERR, _("Could not create bufferevent for new control connection: %s"), strerror(errno));
+               close(newfd);
+               return;
+       }
+
+       memset(&greeting, 0, sizeof greeting);
+       greeting.version = TINC_CTL_VERSION_CURRENT;
+       greeting.pid = getpid();
+       if(bufferevent_write(ev, &greeting, sizeof greeting) == -1) {
+               logger(LOG_ERR,
+                          _("Cannot send greeting for new control connection: %s"),
+                          strerror(errno));
+               bufferevent_free(ev);
+               close(newfd);
+               return;
+       }
+
+       bufferevent_enable(ev, EV_READ);
+       splay_insert(control_socket_tree, ev);
+
+       logger(LOG_DEBUG, _("Control socket connection accepted"));
+}
+
+static int control_compare(const struct event *a, const struct event *b) {
+       return a < b ? -1 : a > b ? 1 : 0;
+}
+
+bool init_control() {
+       int result;
+       struct sockaddr_un addr;
+       char *lastslash;
+
+       if(strlen(controlsocketname) >= sizeof addr.sun_path) {
+               logger(LOG_ERR, _("Control socket filename too long!"));
+               goto bail;
+       }
+
+       memset(&addr, 0, sizeof addr);
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, controlsocketname, sizeof addr.sun_path - 1);
+
+       control_socket = socket(PF_UNIX, SOCK_STREAM, 0);
+
+       if(control_socket < 0) {
+               logger(LOG_ERR, _("Creating UNIX socket failed: %s"), strerror(errno));
+               goto bail;
+       }
+
+       /*
+        * Restrict connections to our control socket by ensuring the parent
+        * directory can be traversed only by root. Note this is not totally
+        * race-free unless all ancestors are writable only by trusted users,
+        * which we don't verify.
+        */
+
+       struct stat statbuf;
+       lastslash = strrchr(controlsocketname, '/');
+       if(lastslash != NULL) {
+               *lastslash = 0; /* temporarily change controlsocketname to be dir */
+               if(mkdir(controlsocketname, 0700) < 0 && errno != EEXIST) {
+                       logger(LOG_ERR, _("Unable to create control socket directory %s: %s"), controlsocketname, strerror(errno));
+                       *lastslash = '/';
+                       goto bail;
+               }
+
+               result = stat(controlsocketname, &statbuf);
+               *lastslash = '/';
+       } else
+               result = stat(".", &statbuf);
+
+       if(result < 0) {
+               logger(LOG_ERR, _("Examining control socket directory failed: %s"), strerror(errno));
+               goto bail;
+       }
+
+       if(statbuf.st_uid != 0 || (statbuf.st_mode & S_IXOTH) != 0 || (statbuf.st_gid != 0 && (statbuf.st_mode & S_IXGRP)) != 0) {
+               logger(LOG_ERR, _("Control socket directory ownership/permissions insecure."));
+               goto bail;
+       }
+
+       result = bind(control_socket, (struct sockaddr *)&addr, sizeof addr);
+
+       if(result < 0 && errno == EADDRINUSE) {
+               result = connect(control_socket, (struct sockaddr *)&addr, sizeof addr);
+               if(result < 0) {
+                       logger(LOG_WARNING, _("Removing old control socket."));
+                       unlink(controlsocketname);
+                       result = bind(control_socket, (struct sockaddr *)&addr, sizeof addr);
+               } else {
+                       if(netname)
+                               logger(LOG_ERR, _("Another tincd is already running for net `%s'."), netname);
+                       else
+                               logger(LOG_ERR, _("Another tincd is already running."));
+                       goto bail;
+               }
+       }
+
+       if(result < 0) {
+               logger(LOG_ERR, _("Can't bind to %s: %s"), controlsocketname, strerror(errno));
+               goto bail;
+       }
+
+       if(listen(control_socket, 3) < 0) {
+               logger(LOG_ERR, _("Can't listen on %s: %s"), controlsocketname, strerror(errno));
+               goto bail;
+       }
+
+       control_socket_tree = splay_alloc_tree((splay_compare_t)control_compare, (splay_action_t)bufferevent_free);
+
+       event_set(&control_event, control_socket, EV_READ | EV_PERSIST, handle_new_control_socket, NULL);
+       event_add(&control_event, NULL);
+       return true;
+
+bail:
+       if(control_socket != -1) {
+               close(control_socket);
+               control_socket = -1;
+       }
+       return false;
+}
+
+void exit_control() {
+       event_del(&control_event);
+       close(control_socket);
+       unlink(controlsocketname);
+}
diff --git a/src/control.h b/src/control.h
new file mode 100644 (file)
index 0000000..e2020a8
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+    control.h -- header for control.c.
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CONTROL_H__
+#define __TINC_CONTROL_H__
+
+extern bool init_control();
+extern void exit_control();
+
+#endif
diff --git a/src/control_common.h b/src/control_common.h
new file mode 100644 (file)
index 0000000..6384651
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    control_protocol.h -- control socket protocol.
+    Copyright (C) 2007 Scott Lamb <slamb@slamb.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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CONTROL_PROTOCOL_H__
+#define __TINC_CONTROL_PROTOCOL_H__
+
+enum request_type {
+       REQ_STOP,
+       REQ_RELOAD,
+       REQ_RESTART,
+       REQ_DUMP_NODES,
+       REQ_DUMP_EDGES,
+       REQ_DUMP_SUBNETS,
+       REQ_DUMP_CONNECTIONS,
+       REQ_DUMP_GRAPH,
+       REQ_PURGE,
+       REQ_SET_DEBUG,
+       REQ_RETRY,
+};
+
+#define TINC_CTL_VERSION_CURRENT 0
+
+/* This greeting is sent by the server on socket open. */
+typedef struct tinc_ctl_greeting_t {
+       int version;
+       pid_t pid;
+} tinc_ctl_greeting_t;
+
+/* A single request or response header. */
+typedef struct tinc_ctl_request_t {
+       size_t length; /* total length, including the header */
+       enum request_type type;
+       int id;
+       int res_errno; /* used only for responses */
+} tinc_ctl_request_t;
+
+#endif
index c6e6f35392a4f0e76704f75d1991255bafe20977..97b2a38d0c60ef327317efec5359d032c9e3bd58 100644 (file)
@@ -46,8 +46,7 @@ static int device_total_out = 0;
 static pid_t reader_pid;
 static int sp[2];
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        HKEY key, key2;
        int i, err;
 
@@ -73,18 +72,18 @@ bool setup_device(void)
        }
 
        for (i = 0; ; i++) {
-               len = sizeof(adapterid);
+               len = sizeof adapterid;
                if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
                        break;
 
                /* Find out more about this adapter */
 
-               snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
+               snprintf(regpath, sizeof regpath, "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
 
                 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
                        continue;
 
-               len = sizeof(adaptername);
+               len = sizeof adaptername;
                err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
 
                RegCloseKey(key2);
@@ -108,7 +107,7 @@ bool setup_device(void)
                                continue;
                }
 
-               snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
+               snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
                if(device_handle != INVALID_HANDLE_VALUE) {
                        CloseHandle(device_handle);
@@ -130,7 +129,7 @@ bool setup_device(void)
        if(!iface)
                iface = xstrdup(adaptername);
 
-       snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
+       snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
        
        /* Now we are going to open this device twice: once for reading and once for writing.
           We do this because apparently it isn't possible to check for activity in the select() loop.
@@ -154,7 +153,7 @@ bool setup_device(void)
 
        /* Get MAC address from tap device */
 
-       if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
+       if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
                logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
                return false;
        }
@@ -177,7 +176,7 @@ bool setup_device(void)
                   It passes everything it reads to the socket. */
        
                char buf[MTU];
-               long lenin;
+               long inlen;
 
                CloseHandle(device_handle);
 
@@ -200,8 +199,8 @@ bool setup_device(void)
                /* Pass packets */
 
                for(;;) {
-                       ReadFile(device_handle, buf, MTU, &lenin, NULL);
-                       write(sp[1], buf, lenin);
+                       ReadFile(device_handle, buf, MTU, &inlen, NULL);
+                       write(sp[1], buf, inlen);
                }
        }
 
@@ -218,8 +217,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
 
        close(sp[0]);
@@ -232,19 +230,18 @@ void close_device(void)
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
-       int lenin;
+bool read_packet(vpn_packet_t *packet) {
+       int inlen;
 
        cp();
 
-       if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
+       if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                           device, strerror(errno));
                return false;
        }
        
-       packet->len = lenin;
+       packet->len = inlen;
 
        device_total_in += packet->len;
 
@@ -254,16 +251,15 @@ bool read_packet(vpn_packet_t *packet)
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
-       long lenout;
+bool write_packet(vpn_packet_t *packet) {
+       long outlen;
 
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
                           packet->len, device_info);
 
-       if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) {
+       if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
                logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
                return false;
        }
@@ -273,8 +269,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index 99ec1415e83a1080911d86b387b08d2d3774acad..3b584f3928e0584296234e875a8c3ce137d4bf93 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "edge.h"
 #include "logger.h"
 #include "netutl.h"
 #include "utils.h"
 #include "xalloc.h"
 
-avl_tree_t *edge_weight_tree;  /* Tree with all edges, sorted on weight */
+splay_tree_t *edge_weight_tree;        /* Tree with all edges, sorted on weight */
 
-static int edge_compare(const edge_t *a, const edge_t *b)
-{
+static int edge_compare(const edge_t *a, const edge_t *b) {
        return strcmp(a->to->name, b->to->name);
 }
 
-static int edge_weight_compare(const edge_t *a, const edge_t *b)
-{
+static int edge_weight_compare(const edge_t *a, const edge_t *b) {
        int result;
 
        result = a->weight - b->weight;
@@ -54,45 +52,39 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b)
        return strcmp(a->to->name, b->to->name);
 }
 
-void init_edges(void)
-{
+void init_edges(void) {
        cp();
 
-       edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
+       edge_weight_tree = splay_alloc_tree((splay_compare_t) edge_weight_compare, NULL);
 }
 
-avl_tree_t *new_edge_tree(void)
-{
+splay_tree_t *new_edge_tree(void) {
        cp();
 
-       return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
+       return splay_alloc_tree((splay_compare_t) edge_compare, (splay_action_t) free_edge);
 }
 
-void free_edge_tree(avl_tree_t *edge_tree)
-{
+void free_edge_tree(splay_tree_t *edge_tree) {
        cp();
 
-       avl_delete_tree(edge_tree);
+       splay_delete_tree(edge_tree);
 }
 
-void exit_edges(void)
-{
+void exit_edges(void) {
        cp();
 
-       avl_delete_tree(edge_weight_tree);
+       splay_delete_tree(edge_weight_tree);
 }
 
 /* Creation and deletion of connection elements */
 
-edge_t *new_edge(void)
-{
+edge_t *new_edge(void) {
        cp();
 
        return xmalloc_and_zero(sizeof(edge_t));
 }
 
-void free_edge(edge_t *e)
-{
+void free_edge(edge_t *e) {
        cp();
        
        sockaddrfree(&e->address);
@@ -100,12 +92,11 @@ void free_edge(edge_t *e)
        free(e);
 }
 
-void edge_add(edge_t *e)
-{
+void edge_add(edge_t *e) {
        cp();
 
-       avl_insert(edge_weight_tree, e);
-       avl_insert(e->from->edge_tree, e);
+       splay_insert(edge_weight_tree, e);
+       splay_insert(e->from->edge_tree, e);
 
        e->reverse = lookup_edge(e->to, e->from);
 
@@ -113,19 +104,17 @@ void edge_add(edge_t *e)
                e->reverse->reverse = e;
 }
 
-void edge_del(edge_t *e)
-{
+void edge_del(edge_t *e) {
        cp();
 
        if(e->reverse)
                e->reverse->reverse = NULL;
 
-       avl_delete(edge_weight_tree, e);
-       avl_delete(e->from->edge_tree, e);
+       splay_delete(edge_weight_tree, e);
+       splay_delete(e->from->edge_tree, e);
 }
 
-edge_t *lookup_edge(node_t *from, node_t *to)
-{
+edge_t *lookup_edge(node_t *from, node_t *to) {
        edge_t v;
        
        cp();
@@ -133,30 +122,32 @@ edge_t *lookup_edge(node_t *from, node_t *to)
        v.from = from;
        v.to = to;
 
-       return avl_search(from->edge_tree, &v);
+       return splay_search(from->edge_tree, &v);
 }
 
-void dump_edges(void)
-{
-       avl_node_t *node, *node2;
+int dump_edges(struct evbuffer *out) {
+       splay_node_t *node, *node2;
        node_t *n;
        edge_t *e;
        char *address;
 
        cp();
 
-       logger(LOG_DEBUG, _("Edges:"));
-
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
                for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
                        e = node2->data;
                        address = sockaddr2hostname(&e->address);
-                       logger(LOG_DEBUG, _(" %s to %s at %s options %lx weight %d"),
-                                  e->from->name, e->to->name, address, e->options, e->weight);
+                       if(evbuffer_add_printf(out,
+                                                                  _(" %s to %s at %s options %lx weight %d\n"),
+                                                                  e->from->name, e->to->name, address,
+                                                                  e->options, e->weight) == -1) {
+                               free(address);
+                               return errno;
+                       }
                        free(address);
                }
        }
 
-       logger(LOG_DEBUG, _("End of edges."));
+       return 0;
 }
index 83759203b8d10a5f1081cc5c32384d2778bc4854..dd3d6704cc6846c557aa16b802140eb4eca1af5f 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef __TINC_EDGE_H__
 #define __TINC_EDGE_H__
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "connection.h"
 #include "net.h"
 #include "node.h"
@@ -40,17 +40,17 @@ typedef struct edge_t {
        struct edge_t *reverse;         /* edge in the opposite direction, if available */
 } edge_t;
 
-extern avl_tree_t *edge_weight_tree;   /* Tree with all known edges sorted on weight */
+extern splay_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
 
 extern void init_edges(void);
 extern void exit_edges(void);
 extern edge_t *new_edge(void) __attribute__ ((__malloc__));
 extern void free_edge(edge_t *);
-extern avl_tree_t *new_edge_tree(void) __attribute__ ((__malloc__));
-extern void free_edge_tree(avl_tree_t *);
+extern splay_tree_t *new_edge_tree(void) __attribute__ ((__malloc__));
+extern void free_edge_tree(splay_tree_t *);
 extern void edge_add(edge_t *);
 extern void edge_del(edge_t *);
 extern edge_t *lookup_edge(struct node_t *, struct node_t *);
-extern void dump_edges(void);
+extern int dump_edges(struct evbuffer *);
 
 #endif                                                 /* __TINC_EDGE_H__ */
diff --git a/src/event.c b/src/event.c
deleted file mode 100644 (file)
index 5fee783..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-    event.c -- event queue
-    Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
-                  2002-2005 Ivo Timmermans
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#include "system.h"
-
-#include "avl_tree.h"
-#include "event.h"
-#include "utils.h"
-#include "xalloc.h"
-
-avl_tree_t *event_tree;
-extern time_t now;
-
-int id;
-
-static int event_compare(const event_t *a, const event_t *b)
-{
-       if(a->time > b->time)
-               return 1;
-
-       if(a->time < b->time)
-               return -1;
-
-       return a->id - b->id;
-}
-
-void init_events(void)
-{
-       cp();
-
-       event_tree = avl_alloc_tree((avl_compare_t) event_compare, (avl_action_t) free_event);
-}
-
-void exit_events(void)
-{
-       cp();
-
-       avl_delete_tree(event_tree);
-}
-
-void expire_events(void)
-{
-       avl_node_t *node;
-       event_t *event;
-       time_t diff;
-
-       /*
-        * Make all events appear expired by substracting the difference between
-         * the expiration time of the last event and the current time.
-        */
-
-       cp();
-
-       if(!event_tree->tail)
-               return;
-
-       event = event_tree->tail->data;
-       if(event->time < now)
-               return;
-
-       diff = 1 + event->time - now;
-       
-       for(node = event_tree->head; node; node = node->next) {
-               event = node->data;
-               event->time -= diff;
-       }
-}
-
-event_t *new_event(void)
-{
-       cp();
-
-       return xmalloc_and_zero(sizeof(event_t));
-}
-
-void free_event(event_t *event)
-{
-       cp();
-
-       free(event);
-}
-
-void event_add(event_t *event)
-{
-       cp();
-
-       event->id = ++id;
-       avl_insert(event_tree, event);
-}
-
-void event_del(event_t *event)
-{
-       cp();
-
-       avl_delete(event_tree, event);
-}
-
-event_t *get_expired_event(void)
-{
-       event_t *event;
-
-       cp();
-
-       if(event_tree->head) {
-               event = event_tree->head->data;
-
-               if(event->time < now) {
-                       avl_node_t *node = event_tree->head;
-                       avl_unlink_node(event_tree, node);
-                       free(node);
-                       return event;
-               }
-       }
-
-       return NULL;
-}
diff --git a/src/event.h b/src/event.h
deleted file mode 100644 (file)
index 7c1873d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-    event.h -- header for event.c
-    Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
-                  2002-2005 Ivo Timmermans
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
-*/
-
-#ifndef __TINC_EVENT_H__
-#define __TINC_EVENT_H__
-
-#include "avl_tree.h"
-
-extern avl_tree_t *event_tree;
-
-typedef void (*event_handler_t)(void *);
-
-typedef struct {
-       time_t time;
-       int id;
-       event_handler_t handler;
-       void *data;
-} event_t;
-
-extern void init_events(void);
-extern void exit_events(void);
-extern void expire_events(void);
-extern event_t *new_event(void) __attribute__ ((__malloc__));
-extern void free_event(event_t *);
-extern void event_add(event_t *);
-extern void event_del(event_t *);
-extern event_t *get_expired_event(void);
-
-#endif                                                 /* __TINC_EVENT_H__ */
diff --git a/src/gcrypt/cipher.c b/src/gcrypt/cipher.c
new file mode 100644 (file)
index 0000000..77add6c
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+    cipher.c -- Symmetric block cipher handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "cipher.h"
+#include "logger.h"
+#include "xalloc.h"
+
+static struct {
+       const char *name;
+       int algo;
+       int mode;
+       int nid;
+} ciphertable[] = {
+       {"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
+
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
+       {"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
+       {NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
+
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
+       {"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
+       {NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
+
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
+       {"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
+       {NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
+
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
+       {"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
+       {NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
+};
+
+static bool nametocipher(const char *name, int *algo, int *mode) {
+       size_t i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
+                       *algo = ciphertable[i].algo;
+                       *mode = ciphertable[i].mode;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool nidtocipher(int nid, int *algo, int *mode) {
+       size_t i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(nid == ciphertable[i].nid) {
+                       *algo = ciphertable[i].algo;
+                       *mode = ciphertable[i].mode;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool ciphertonid(int algo, int mode, int *nid) {
+       size_t i;
+
+       for(i = 0; i < sizeof ciphertable / sizeof *ciphertable; i++) {
+               if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
+                       *nid = ciphertable[i].nid;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool cipher_open(cipher_t *cipher, int algo, int mode) {
+       gcry_error_t err;
+
+       if(!ciphertonid(algo, mode, &cipher->nid)) {
+               logger(LOG_DEBUG, _("Cipher %d mode %d has no corresponding nid!"), algo, mode);
+               return false;
+       }
+
+       if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
+               logger(LOG_DEBUG, _("Unable to intialise cipher %d mode %d: %s"), algo, mode, gcry_strerror(err));
+               return false;
+       }
+
+       cipher->keylen = gcry_cipher_get_algo_keylen(algo);
+       if(mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC)
+               cipher->blklen = gcry_cipher_get_algo_blklen(algo);
+       else
+               cipher->blklen = 0;
+       cipher->key = xmalloc(cipher->keylen + cipher->blklen);
+
+       return true;
+}
+
+bool cipher_open_by_name(cipher_t *cipher, const char *name) {
+       int algo, mode;
+
+       if(!nametocipher(name, &algo, &mode)) {
+               logger(LOG_DEBUG, _("Unknown cipher name '%s'!"), name);
+               return false;
+       }
+
+       return cipher_open(cipher, algo, mode);
+}
+
+bool cipher_open_by_nid(cipher_t *cipher, int nid) {
+       int algo, mode;
+
+       if(!nidtocipher(nid, &algo, &mode)) {
+               logger(LOG_DEBUG, _("Unknown cipher ID %d!"), nid);
+               return false;
+       }
+
+       return cipher_open(cipher, algo, mode);
+}
+
+bool cipher_open_blowfish_ofb(cipher_t *cipher) {
+       return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
+}
+
+void cipher_close(cipher_t *cipher) {
+       if(cipher->handle) {
+               gcry_cipher_close(cipher->handle);
+               cipher->handle = NULL;
+       }
+
+       if(cipher->key) {
+               free(cipher->key);
+               cipher->key = NULL;
+       }
+}
+
+size_t cipher_keylength(const cipher_t *cipher) {
+       return cipher->keylen + cipher->blklen;
+}
+
+void cipher_get_key(const cipher_t *cipher, void *key) {
+       memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
+}
+
+bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
+       memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
+
+       gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
+       gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
+
+       return true;
+}
+
+bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
+       memcpy(cipher->key, key + len - cipher->keylen, cipher->keylen + cipher->blklen);
+       memcpy(cipher->key + cipher->keylen, key + len - cipher->keylen - cipher->blklen, cipher->blklen);
+
+       gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
+       gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
+
+       return true;
+}
+
+bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
+       gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
+
+       gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
+       gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
+
+       return true;
+}
+
+static bool cipher_add_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
+       size_t reqlen;
+
+       if(cipher->blklen == 1) {
+               *outlen = inlen;
+               return true;
+       }
+
+       reqlen = ((inlen + 1) / cipher->blklen) * cipher->blklen;
+       if(reqlen > *outlen)
+               return false;
+
+       // add padding
+
+       *outlen = reqlen;
+       return true;
+}
+
+static bool cipher_remove_padding(cipher_t *cipher, void *indata, size_t inlen, size_t *outlen) {
+       size_t origlen;
+
+       if(cipher->blklen == 1) {
+               *outlen = inlen;
+               return true;
+       }
+
+       if(inlen % cipher->blklen)
+               return false;
+
+       // check and remove padding
+
+       *outlen = origlen;
+       return true;
+}
+
+bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
+       gcry_error_t err;
+
+       // To be fixed
+
+       if((err = gcry_cipher_encrypt(cipher->handle, outdata, inlen, indata, inlen))) {
+               logger(LOG_ERR, _("Error while encrypting: %s"), gcry_strerror(err));
+               return false;
+       }
+
+       return true;
+}
+
+bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
+       gcry_error_t err;
+
+       // To be fixed
+
+       if((err = gcry_cipher_decrypt(cipher->handle, outdata, inlen, indata, inlen))) {
+               logger(LOG_ERR, _("Error while decrypting: %s"), gcry_strerror(err));
+               return false;
+       }
+
+       return true;
+}
+
+int cipher_get_nid(const cipher_t *cipher) {
+       return cipher->nid;
+}
+
+bool cipher_active(const cipher_t *cipher) {
+       return cipher->nid != 0;
+}
diff --git a/src/gcrypt/cipher.h b/src/gcrypt/cipher.h
new file mode 100644 (file)
index 0000000..4d1e096
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    cipher.h -- header file cipher.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CIPHER_H__
+#define __TINC_CIPHER_H__
+
+#include <gcrypt.h>
+
+#define CIPHER_MAX_BLOCK_SIZE 32
+#define CIPHER_MAX_IV_SIZE 16
+#define CIPHER_MAX_KEY_SIZE 32
+
+typedef struct cipher {
+       gcry_cipher_hd_t handle;
+       char *key;
+       int nid;
+       uint16_t keylen;
+       uint16_t blklen;
+} cipher_t;
+
+extern bool cipher_open_by_name(struct cipher *, const char *);
+extern bool cipher_open_by_nid(struct cipher *, int);
+extern bool cipher_open_blowfish_ofb(struct cipher *);
+extern void cipher_close(struct cipher *);
+extern size_t cipher_keylength(const struct cipher *);
+extern void cipher_get_key(const struct cipher *, void *);
+extern bool cipher_set_key(struct cipher *, void *, bool);
+extern bool cipher_set_key_from_rsa(struct cipher *, void *, size_t, bool);
+extern bool cipher_regenerate_key(struct cipher *, bool);
+extern bool cipher_encrypt(struct cipher *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
+extern bool cipher_decrypt(struct cipher *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot);
+extern int cipher_get_nid(const struct cipher *);
+extern bool cipher_active(const struct cipher *);
+
+#endif
diff --git a/src/gcrypt/crypto.c b/src/gcrypt/crypto.c
new file mode 100644 (file)
index 0000000..9465606
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    crypto.c -- Cryptographic miscellaneous functions and initialisation
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <gcrypt.h>
+
+#include "crypto.h"
+
+void crypto_init() {
+}
+
+void crypto_exit() {
+}
+
+void randomize(void *out, size_t outlen) {
+       gcry_create_nonce(out, outlen);
+}
diff --git a/src/gcrypt/crypto.h b/src/gcrypt/crypto.h
new file mode 100644 (file)
index 0000000..3999251
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+    crypto.h -- header for crypto.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CRYPTO_H__
+#define __TINC_CRYPTO_H__
+
+extern void crypto_init();
+extern void crypto_exit();
+extern void randomize(void *, size_t);
+
+#endif
diff --git a/src/gcrypt/digest.c b/src/gcrypt/digest.c
new file mode 100644 (file)
index 0000000..639fa67
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+    digest.c -- Digest handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include "digest.h"
+#include "logger.h"
+
+static struct {
+       const char *name;
+       int algo;
+       int nid;
+} digesttable[] = {
+       {"none", GCRY_MD_NONE, 0},
+       {"sha1", GCRY_MD_SHA1, 64},
+       {"sha256", GCRY_MD_SHA256, 672},
+       {"sha384", GCRY_MD_SHA384, 673},
+       {"sha512", GCRY_MD_SHA512, 674},
+};
+
+static bool nametodigest(const char *name, int *algo) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
+                       *algo = digesttable[i].algo;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool nidtodigest(int nid, int *algo) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(nid == digesttable[i].nid) {
+                       *algo = digesttable[i].algo;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool digesttonid(int algo, int *nid) {
+       int i;
+
+       for(i = 0; i < sizeof digesttable / sizeof *digesttable; i++) {
+               if(algo == digesttable[i].algo) {
+                       *nid = digesttable[i].nid;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool digest_open(digest_t *digest, int algo) {
+       if(!digesttonid(algo, &digest->nid)) {
+               logger(LOG_DEBUG, _("Digest %d has no corresponding nid!"), algo);
+               return false;
+       }
+
+       digest->len = gcry_md_get_algo_dlen(algo);
+
+       return true;
+}
+
+bool digest_open_by_name(digest_t *digest, const char *name) {
+       int algo;
+
+       if(!nametodigest(name, &algo)) {
+               logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
+               return false;
+       }
+
+       return digest_open(digest, algo);
+}
+
+bool digest_open_by_nid(digest_t *digest, int nid) {
+       int algo;
+
+       if(!nidtodigest(nid, &algo)) {
+               logger(LOG_DEBUG, _("Unknown digest ID %d!"), nid);
+               return false;
+       }
+
+       return digest_open(digest, algo);
+}
+
+bool digest_open_sha1(digest_t *digest) {
+       return digest_open(digest, GCRY_MD_SHA1);
+}
+
+void digest_close(digest_t *digest) {
+}
+
+bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
+       gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
+       return true;
+}
+
+bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
+       char outdata[digest->len];
+
+       gcry_md_hash_buffer(digest->algo, outdata, indata, inlen);
+       return !memcmp(cmpdata, outdata, digest->len);
+}
+
+int digest_get_nid(const digest_t *digest) {
+       return digest->nid;
+}
+
+size_t digest_length(const digest_t *digest) {
+       return digest->len;
+}
+
+bool digest_active(const digest_t *digest) {
+       return digest->algo != GCRY_MD_NONE;
+}
diff --git a/src/gcrypt/digest.h b/src/gcrypt/digest.h
new file mode 100644 (file)
index 0000000..18e4910
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    digest.h -- header file digest.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_DIGEST_H__
+#define __TINC_DIGEST_H__
+
+#include <gcrypt.h>
+
+#define DIGEST_MAX_SIZE 64
+
+typedef struct digest {
+       int algo;
+       int nid;
+       uint16_t len;
+} digest_t;
+
+extern bool digest_open_by_name(struct digest *, const char *);
+extern bool digest_open_by_nid(struct digest *, int);
+extern bool digest_open_sha1(struct digest *);
+extern void digest_close(struct digest *);
+extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
+extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
+extern int digest_get_nid(const struct digest *);
+extern size_t digest_length(const struct digest *);
+extern bool digest_active(const struct digest *);
+
+#endif
diff --git a/src/gcrypt/rsa.c b/src/gcrypt/rsa.c
new file mode 100644 (file)
index 0000000..6530162
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+    rsa.c -- RSA key handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <gcrypt.h>
+
+#include "logger.h"
+#include "rsa.h"
+
+// Base64 decoding table
+
+static const uint8_t b64d[128] = {
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+  0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+  0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+  0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+  0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+  0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+  0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+  0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+  0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
+  0xff, 0xff
+};
+
+// PEM encoding/decoding functions
+
+static bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
+       bool decode = false;
+       char line[1024];
+       uint16_t word = 0;
+       int shift = 10;
+       size_t i, j = 0;
+
+       while(!feof(fp)) {
+               if(!fgets(line, sizeof line, fp))
+                       return false;
+
+               if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
+                       if(!strncmp(line + 11, header, strlen(header)))
+                               decode = true;
+                       continue;
+               }
+
+               if(decode && !strncmp(line, "-----END", 8)) {
+                       break;
+               }
+
+               if(!decode)
+                       continue;
+
+               for(i = 0; line[i] >= ' '; i++) {
+                       if((signed char)line[i] < 0 || b64d[(int)line[i]] == 0xff)
+                               break;
+                       word |= b64d[(int)line[i]] << shift;
+                       shift -= 6;
+                       if(shift <= 2) {
+                               if(j > size) {
+                                       errno = ENOMEM;
+                                       return false;
+                               }
+
+                               buf[j++] = word >> 8;
+                               word <<= 8;
+                               shift += 8;
+                       }
+               }
+       }
+
+       if(outsize)
+               *outsize = j;
+       return true;
+}
+
+
+// BER decoding functions
+
+static int ber_read_id(unsigned char **p, size_t *buflen) {
+       if(*buflen <= 0)
+               return -1;
+
+       if((**p & 0x1f) == 0x1f) {
+               int id = 0;
+               bool more;
+               while(*buflen > 0) {
+                       id <<= 7;
+                       id |= **p & 0x7f;
+                       more = *(*p)++ & 0x80;
+                       (*buflen)--;
+                       if(!more)
+                               break;
+               }
+               return id;
+       } else {
+               (*buflen)--;
+               return *(*p)++ & 0x1f;
+       }
+}
+
+static size_t ber_read_len(unsigned char **p, size_t *buflen) {
+       if(*buflen <= 0)
+               return -1;
+
+       if(**p & 0x80) {
+               size_t result = 0;
+               int len = *(*p)++ & 0x7f;
+               (*buflen)--;
+               if(len > *buflen)
+                       return 0;
+
+               while(len--) {
+                       result <<= 8;
+                       result |= *(*p)++;
+                       (*buflen)--;
+               }
+
+               return result;
+       } else {
+               (*buflen)--;
+               return *(*p)++;
+       }
+}
+       
+
+static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
+       int tag = ber_read_id(p, buflen);
+       size_t len = ber_read_len(p, buflen);
+
+       if(tag == 0x10) {
+               if(result)
+                       *result = len;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
+       int tag = ber_read_id(p, buflen);
+       size_t len = ber_read_len(p, buflen);
+       gcry_error_t err = 0;
+
+       if(tag != 0x02 || len > *buflen)
+               return false;
+
+       if(mpi)
+               err = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, *p, len, NULL);
+       
+       *p += len;
+       *buflen -= len;
+
+       return mpi ? !err : true;
+}
+
+bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
+       gcry_error_t err = 0;
+
+       err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
+               ?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, n, 0, NULL);
+
+       if(err) {
+               logger(LOG_ERR, _("Error while reading RSA public key: %s"), gcry_strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+
+bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
+       gcry_error_t err = 0;
+
+       err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
+               ?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, n, 0, NULL)
+               ?: gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, n, 0, NULL);
+
+       if(err) {
+               logger(LOG_ERR, _("Error while reading RSA public key: %s"), gcry_strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+
+// Read PEM RSA keys
+
+bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf[8096], *derp = derbuf;
+       size_t derlen;
+
+       if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
+               logger(LOG_ERR, _("Unable to read RSA public key: %s"), strerror(errno));
+               return NULL;
+       }
+
+       if(!ber_read_sequence(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, &rsa->n)
+                       || !ber_read_mpi(&derp, &derlen, &rsa->e)
+                       || derlen) {
+               logger(LOG_ERR, _("Error while decoding RSA public key"));
+               return NULL;
+       }
+
+       return true;
+}
+
+bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf[8096], *derp = derbuf;
+       size_t derlen;
+
+       if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
+               logger(LOG_ERR, _("Unable to read RSA private key: %s"), strerror(errno));
+               return NULL;
+       }
+
+       if(!ber_read_sequence(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, &rsa->n)
+                       || !ber_read_mpi(&derp, &derlen, &rsa->e)
+                       || !ber_read_mpi(&derp, &derlen, &rsa->d)
+                       || !ber_read_mpi(&derp, &derlen, NULL) // p
+                       || !ber_read_mpi(&derp, &derlen, NULL) // q
+                       || !ber_read_mpi(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, NULL)
+                       || !ber_read_mpi(&derp, &derlen, NULL) // u
+                       || derlen) {
+               logger(LOG_ERR, _("Error while decoding RSA private key"));
+               return NULL;
+       }
+
+       return true;
+}
+
+size_t rsa_size(rsa_t *rsa) {
+       return (gcry_mpi_get_nbits(rsa->n) + 7) / 8;
+}
+
+/* Well, libgcrypt has functions to handle RSA keys, but they suck.
+ * So we just use libgcrypt's mpi functions, and do the math ourselves.
+ */
+
+// TODO: get rid of this macro, properly clean up gcry_ structures after use
+#define check(foo) { gcry_error_t err = (foo); if(err) {logger(LOG_ERR, "gcrypt error %s/%s at %s:%d\n", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
+
+bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+       gcry_mpi_t inmpi;
+       check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
+
+       gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
+       gcry_mpi_powm(outmpi, inmpi, rsa->e, rsa->n);
+
+       check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
+
+       return true;
+}
+
+bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+       gcry_mpi_t inmpi;
+       check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
+
+       gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
+       gcry_mpi_powm(outmpi, inmpi, rsa->d, rsa->n);
+
+       check(gcry_mpi_print(GCRYMPI_FMT_USG, out,len, NULL, outmpi));
+
+       return true;
+}
diff --git a/src/gcrypt/rsa.h b/src/gcrypt/rsa.h
new file mode 100644 (file)
index 0000000..0b3937a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    rsa.h -- RSA key handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_RSA_H__
+#define __TINC_RSA_H__
+
+#include <gcrypt.h>
+
+typedef struct rsa {
+       gcry_mpi_t n;
+       gcry_mpi_t e;
+       gcry_mpi_t d;
+} rsa_t;
+
+extern bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e);
+extern bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d);
+extern bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp);
+extern bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp);
+extern size_t rsa_size(rsa_t *rsa);
+extern bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out);
+extern bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out);
+
+#endif
diff --git a/src/gcrypt/rsagen.c b/src/gcrypt/rsagen.c
new file mode 100644 (file)
index 0000000..d9f42b7
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+    rsagen.c -- RSA key generation and export
+    Copyright (C) 2008 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <gcrypt.h>
+
+#include "rsagen.h"
+
+#if 0
+// Base64 encoding table
+
+static const char b64e[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// PEM encoding
+
+static bool pem_encode(FILE *fp, const char *header, uint8_t *buf, size_t size) {
+       bool decode = false;
+       char line[1024];
+       uint32_t word = 0;
+       int shift = 0;
+       size_t i, j = 0;
+
+       fprintf(fp, "-----BEGIN %s-----\n", header);
+
+       for(i = 0; i < size; i += 3) {
+               if(i <= size - 3) {
+                       word = buf[i] << 16 | buf[i + 1] << 8 | buf[i + 2];
+               } else {
+                       word = buf[i] << 16;
+                       if(i == size - 2)
+                               word |= buf[i + 1] << 8;
+               }
+
+               line[j++] = b64e[(word >> 18)       ];
+               line[j++] = b64e[(word >> 12) & 0x3f];
+               line[j++] = b64e[(word >>  6) & 0x3f];
+               line[j++] = b64e[(word      ) & 0x3f];
+
+               if(j >= 64) {
+                       line[j++] = '\n';
+                       line[j] = 0;
+                       fputs(line, fp);
+                       j = 0;
+               }
+       }
+
+       if(size % 3 > 0) {
+               if(size % 3 > 1)
+                       line[j++] = '=';
+               line[j++] = '=';
+       }
+
+       if(j) {
+               line[j++] = '\n';
+               line[j] = 0;
+               fputs(line, fp);
+       }
+
+       fprintf(fp, "-----END %s-----\n", header);
+
+       return true;
+}
+
+
+// BER encoding functions
+
+static bool ber_write_id(uint8_t **p, size_t *buflen, int id) {
+       if(*buflen <= 0)
+               return false;
+
+       if(id >= 0x1f) {
+               while(id) {
+                       if(*buflen <= 0)
+                               return false;
+
+                       (*buflen)--;
+                       **p = id & 0x7f;
+                       id >>= 7;
+                       if(id)
+                               **p |= 0x80;
+                       (*p)++;
+               }
+       } else {
+               (*buflen)--;
+               *(*p)++ = id;
+       }
+
+       return true;
+}
+
+static bool ber_write_len(uint8_t **p, size_t *buflen, size_t len) {
+       do {
+               if(*buflen <= 0)
+                       return false;
+
+               (*buflen)--;
+               **p = len & 0x7f;
+               len >>= 7;
+               if(len)
+                       **p |= 0x80;
+               (*p)++;
+       } while(len);
+
+       return true;
+}
+
+static bool ber_write_sequence(uint8_t **p, size_t *buflen, uint8_t *seqbuf, size_t seqlen) {
+       if(!ber_write_id(p, buflen, 0x10) || !ber_write_len(p, buflen, seqlen) || *buflen < seqlen)
+               return false;
+
+       memcpy(*p, seqbuf, seqlen);
+       *p += seqlen;
+       *buflen -= seqlen;
+
+       return true;
+}
+
+static bool ber_write_mpi(uint8_t **p, size_t *buflen, gcry_mpi_t mpi) {
+       uint8_t tmpbuf[1024];
+       size_t tmplen = sizeof tmpbuf;
+       gcry_error_t err;
+
+       err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &tmpbuf, &tmplen, mpi);
+       if(err)
+               return false;
+
+       if(!ber_write_id(p, buflen, 0x02) || !ber_write_len(p, buflen, tmplen) || *buflen < tmplen)
+               return false;
+
+       memcpy(*p, tmpbuf, tmplen);
+       *p += tmplen;
+       *buflen -= tmplen;
+
+       return true;
+}
+
+// Write PEM RSA keys
+
+bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf1[8096];
+       uint8_t derbuf2[8096];
+       uint8_t *derp1 = derbuf1;
+       uint8_t *derp2 = derbuf2;
+       size_t derlen1 = sizeof derbuf1;
+       size_t derlen2 = sizeof derbuf2;
+
+       if(!ber_write_mpi(&derp1, &derlen1, &rsa->n)
+                       || !ber_write_mpi(&derp1, &derlen1, &rsa->e)
+                       || !ber_write_sequence(&derp2, &derlen2, derbuf1, derlen1)) {
+               logger(LOG_ERR, _("Error while encoding RSA public key"));
+               return false;
+       }
+
+       if(!pem_encode(fp, "RSA PUBLIC KEY", derbuf2, derlen2)) {
+               logger(LOG_ERR, _("Unable to write RSA public key: %s"), strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+
+bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
+       uint8_t derbuf1[8096];
+       uint8_t derbuf2[8096];
+       uint8_t *derp1 = derbuf1;
+       uint8_t *derp2 = derbuf2;
+       size_t derlen1 = sizeof derbuf1;
+       size_t derlen2 = sizeof derbuf2;
+
+       if(!ber_write_mpi(&derp1, &derlen1, &bits)
+                       || ber_write_mpi(&derp1, &derlen1, &rsa->n) // modulus
+                       || ber_write_mpi(&derp1, &derlen1, &rsa->e) // public exponent
+                       || ber_write_mpi(&derp1, &derlen1, &rsa->d) // private exponent
+                       || ber_write_mpi(&derp1, &derlen1, &p)
+                       || ber_write_mpi(&derp1, &derlen1, &q)
+                       || ber_write_mpi(&derp1, &derlen1, &exp1)
+                       || ber_write_mpi(&derp1, &derlen1, &exp2)
+                       || ber_write_mpi(&derp1, &derlen1, &coeff))
+               logger(LOG_ERR, _("Error while encoding RSA private key"));
+               return false;
+       }
+
+       if(!pem_encode(fp, "RSA PRIVATE KEY", derbuf2, derlen2)) {
+               logger(LOG_ERR, _("Unable to write RSA private key: %s"), strerror(errno));
+               return false;
+       }
+
+       return true;
+}
+#endif
+
+bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
+       return false;
+}
+
+bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
+       return false;
+}
+
+bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent) {
+       fprintf(stderr, _("Generating RSA keys with libgcrypt not implemented yet\n"));
+       return false;
+}
diff --git a/src/gcrypt/rsagen.h b/src/gcrypt/rsagen.h
new file mode 100644 (file)
index 0000000..e5aff63
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    rsagen.h -- RSA key generation and export
+    Copyright (C) 2008 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_RSAGEN_H__
+#define __TINC_RSAGEN_H__
+
+#include "rsa.h"
+
+extern bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent);
+extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp);
+extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp);
+
+#endif
index a267f052a196df31c1d797ca1e5cf0dc965d11d9..f2e546ee9b4e1463f4490f713a3bb90d316dc06e 100644 (file)
@@ -46,7 +46,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "config.h"
 #include "connection.h"
 #include "device.h"
 #include "utils.h"
 #include "xalloc.h"
 
-static bool graph_changed = true;
-
 /* Implementation of Kruskal's algorithm.
-   Running time: O(EN)
+   Running time: O(E)
    Please note that sorting on weight is already done by add_edge().
 */
 
-void mst_kruskal(void)
-{
-       avl_node_t *node, *next;
+void mst_kruskal(void) {
+       splay_node_t *node, *next;
        edge_t *e;
        node_t *n;
        connection_t *c;
-       int nodes = 0;
-       int safe_edges = 0;
-       bool skipped;
 
        cp();
        
@@ -85,11 +79,6 @@ void mst_kruskal(void)
                c->status.mst = false;
        }
 
-       /* Do we have something to do at all? */
-
-       if(!edge_weight_tree->head)
-               return;
-
        ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
 
        /* Clear visited status on nodes */
@@ -97,29 +86,16 @@ void mst_kruskal(void)
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
                n->status.visited = false;
-               nodes++;
-       }
-
-       /* Starting point */
-
-       for(node = edge_weight_tree->head; node; node = node->next) {
-               e = node->data;
-               if(e->from->status.reachable) {
-                       e->from->status.visited = true;
-                       break;
-               }
        }
 
        /* Add safe edges */
 
-       for(skipped = false, node = edge_weight_tree->head; node; node = next) {
+       for(node = edge_weight_tree->head; node; node = next) {
                next = node->next;
                e = node->data;
 
-               if(!e->reverse || e->from->status.visited == e->to->status.visited) {
-                       skipped = true;
+               if(!e->reverse || (e->from->status.visited && e->to->status.visited))
                        continue;
-               }
 
                e->from->status.visited = true;
                e->to->status.visited = true;
@@ -130,38 +106,148 @@ void mst_kruskal(void)
                if(e->reverse->connection)
                        e->reverse->connection->status.mst = true;
 
-               safe_edges++;
-
                ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
                                   e->to->name, e->weight);
+       }
+}
 
-               if(skipped) {
-                       skipped = false;
-                       next = edge_weight_tree->head;
-                       continue;
+/* Implementation of Dijkstra's algorithm.
+   Running time: O(N^2)
+*/
+
+void sssp_dijkstra(void) {
+       splay_node_t *node, *to;
+       edge_t *e;
+       node_t *n, *m;
+       list_t *todo_list;
+       list_node_t *lnode, *nnode;
+       bool indirect;
+
+       cp();
+
+       todo_list = list_alloc(NULL);
+
+       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:");
+
+       /* Clear visited status on nodes */
+
+       for(node = node_tree->head; node; node = node->next) {
+               n = node->data;
+               n->status.visited = false;
+               n->status.indirect = true;
+               n->distance = -1;
+       }
+
+       /* Begin with myself */
+
+       myself->status.indirect = false;
+       myself->nexthop = myself;
+       myself->via = myself;
+       myself->distance = 0;
+       list_insert_head(todo_list, myself);
+
+       /* Loop while todo_list is filled */
+
+       while(todo_list->head) {
+               n = NULL;
+               nnode = NULL;
+
+               /* Select node from todo_list with smallest distance */
+
+               for(lnode = todo_list->head; lnode; lnode = lnode->next) {
+                       m = lnode->data;
+                       if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) {
+                               n = m;
+                               nnode = lnode;
+                       }
+               }
+
+               /* Mark this node as visited and remove it from the todo_list */
+
+               n->status.visited = true;
+               list_unlink_node(todo_list, nnode);
+
+               /* Update distance of neighbours and add them to the todo_list */
+
+               for(to = n->edge_tree->head; to; to = to->next) {       /* "to" is the edge connected to "from" */
+                       e = to->data;
+
+                       if(e->to->status.visited || !e->reverse)
+                               continue;
+
+                       /* Situation:
+
+                                  /
+                                 /
+                          ----->(n)---e-->(e->to)
+                                 \
+                                  \
+
+                          Where e is an edge, (n) and (e->to) are nodes.
+                          n->address is set to the e->address of the edge left of n to n.
+                          We are currently examining the edge e right of n from n:
+
+                          - If e->reverse->address != n->address, then e->to is probably
+                            not reachable for the nodes left of n. We do as if the indirectdata
+                            flag is set on edge e.
+                          - If edge e provides for better reachability of e->to, update e->to.
+                        */
+
+                       if(e->to->distance < 0)
+                               list_insert_tail(todo_list, e->to);
+
+                       indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address));
+
+                       if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight)
+                               continue;
+
+                       e->to->distance = n->distance + e->weight;
+                       e->to->status.indirect = indirect;
+                       e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
+                       e->to->via = indirect ? n->via : e->to;
+                       e->to->options = e->options;
+
+                       if(sockaddrcmp(&e->to->address, &e->address)) {
+                               node = splay_unlink(node_udp_tree, e->to);
+                               sockaddrfree(&e->to->address);
+                               sockaddrcpy(&e->to->address, &e->address);
+
+                               if(e->to->hostname)
+                                       free(e->to->hostname);
+
+                               e->to->hostname = sockaddr2hostname(&e->to->address);
+
+                               if(node)
+                                       splay_insert_node(node_udp_tree, node);
+
+                               if(e->to->options & OPTION_PMTU_DISCOVERY) {
+                                       e->to->mtuprobes = 0;
+                                       e->to->minmtu = 0;
+                                       e->to->maxmtu = MTU;
+                                       if(e->to->status.validkey)
+                                               send_mtu_probe(e->to);
+                               }
+                       }
+
+                       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name,
+                                          e->to->name, e->weight, e->to->distance);
                }
        }
 
-       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
-                          safe_edges);
+       list_free(todo_list);
 }
 
 /* Implementation of a simple breadth-first search algorithm.
    Running time: O(E)
 */
 
-void sssp_bfs(void)
-{
-       avl_node_t *node, *next, *to;
+void sssp_bfs(void) {
+       splay_node_t *node, *to;
        edge_t *e;
        node_t *n;
        list_t *todo_list;
        list_node_t *from, *todonext;
        bool indirect;
-       char *name;
-       char *address, *port;
-       char *envp[7];
-       int i;
 
        cp();
 
@@ -238,6 +324,15 @@ void sssp_bfs(void)
        }
 
        list_free(todo_list);
+}
+
+void check_reachability() {
+       splay_node_t *node, *next;
+       node_t *n;
+       char *name;
+       char *address, *port;
+       char *envp[7];
+       int i;
 
        /* Check reachability status. */
 
@@ -265,10 +360,7 @@ void sssp_bfs(void)
                        n->minmtu = 0;
                        n->mtuprobes = 0;
 
-                       if(n->mtuevent) {
-                               event_del(n->mtuevent);
-                               n->mtuevent = NULL;
-                       }
+                       event_del(&n->mtuevent);
 
                        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
                        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
@@ -298,74 +390,45 @@ void sssp_bfs(void)
        }
 }
 
-void graph(void)
-{
-       subnet_cache_flush();
-       sssp_bfs();
-       mst_kruskal();
-       graph_changed = true;
-}
-
-
-
 /* Dump nodes and edges to a graphviz file.
           
    The file can be converted to an image with
    dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
 */
 
-void dump_graph(void)
-{
-       avl_node_t *node;
+int dump_graph(struct evbuffer *out) {
+       splay_node_t *node;
        node_t *n;
        edge_t *e;
-       char *filename = NULL, *tmpname = NULL;
-       FILE *file;
-       
-       if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename))
-               return;
-
-       graph_changed = false;
-
-       ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
-       
-       if(filename[0] == '|') {
-               file = popen(filename + 1, "w");
-       } else {
-               xasprintf(&tmpname, "%s.new", filename);
-               file = fopen(tmpname, "w");
-       }
-
-       if(!file) {
-               logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
-               free(tmpname);
-               return;
-       }
 
-       fprintf(file, "digraph {\n");
+       if(evbuffer_add_printf(out, "digraph {\n") == -1)
+               return errno;
        
        /* dump all nodes first */
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
-               fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name);
+               if(evbuffer_add_printf(out, "   %s [label = \"%s\"];\n",
+                                                          n->name, n->name) == -1)
+                       return errno;
        }
 
        /* now dump all edges */
        for(node = edge_weight_tree->head; node; node = node->next) {
                e = node->data;
-               fprintf(file, " %s -> %s;\n", e->from->name, e->to->name);
+               if(evbuffer_add_printf(out, "   %s -> %s;\n",
+                                                          e->from->name, e->to->name) == -1)
+                       return errno;
        }
 
-       fprintf(file, "}\n");   
-       
-       if(filename[0] == '|') {
-               pclose(file);
-       } else {
-               fclose(file);
-#ifdef HAVE_MINGW
-               unlink(filename);
-#endif
-               rename(tmpname, filename);
-               free(tmpname);
-       }
+       if(evbuffer_add_printf(out, "}\n") == -1)
+               return errno;
+
+       return 0;
+}
+
+void graph(void) {
+    subnet_cache_flush();
+       sssp_dijkstra();
+       check_reachability();
+       mst_kruskal();
 }
index 0d5be20c1ca6262391a0deb28c22daf41ce09f82..88de9f6a83c8d565258c12225d61b99e9328d349 100644 (file)
@@ -26,6 +26,6 @@
 extern void graph(void);
 extern void mst_kruskal(void);
 extern void sssp_bfs(void);
-extern void dump_graph(void);
+extern int dump_graph(struct evbuffer *);
 
 #endif /* __TINC_GRAPH_H__ */
index 4e9591c21c1f8f2a8ae48e5e8eda8cfd16806f54..e692ca9ff8c5082b8195c24b7de2fe3b8bf7bf84 100644 (file)
@@ -52,8 +52,7 @@ static char *device_info;
 static int device_total_in = 0;
 static int device_total_out = 0;
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        struct ifreq ifr;
 
        cp();
@@ -78,7 +77,7 @@ bool setup_device(void)
 #ifdef HAVE_LINUX_IF_TUN_H
        /* Ok now check if this is an old ethertap or a new tun/tap thingie */
 
-       memset(&ifr, 0, sizeof(ifr));
+       memset(&ifr, 0, sizeof ifr);
        if(routing_mode == RMODE_ROUTER) {
                ifr.ifr_flags = IFF_TUN;
                device_type = DEVICE_TYPE_TUN;
@@ -118,8 +117,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
        
        close(device_fd);
@@ -128,45 +126,44 @@ void close_device(void)
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
-       int lenin;
+bool read_packet(vpn_packet_t *packet) {
+       int inlen;
        
        cp();
 
        switch(device_type) {
                case DEVICE_TYPE_TUN:
-                       lenin = read(device_fd, packet->data + 10, MTU - 10);
+                       inlen = read(device_fd, packet->data + 10, MTU - 10);
 
-                       if(lenin <= 0) {
+                       if(inlen <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"),
                                           device_info, device, strerror(errno));
                                return false;
                        }
 
-                       packet->len = lenin + 10;
+                       packet->len = inlen + 10;
                        break;
                case DEVICE_TYPE_TAP:
-                       lenin = read(device_fd, packet->data, MTU);
+                       inlen = read(device_fd, packet->data, MTU);
 
-                       if(lenin <= 0) {
+                       if(inlen <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"),
                                           device_info, device, strerror(errno));
                                return false;
                        }
 
-                       packet->len = lenin;
+                       packet->len = inlen;
                        break;
                case DEVICE_TYPE_ETHERTAP:
-                       lenin = read(device_fd, packet->data - 2, MTU + 2);
+                       inlen = read(device_fd, packet->data - 2, MTU + 2);
 
-                       if(lenin <= 0) {
+                       if(inlen <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"),
                                           device_info, device, strerror(errno));
                                return false;
                        }
 
-                       packet->len = lenin - 2;
+                       packet->len = inlen - 2;
                        break;
        }
 
@@ -178,8 +175,7 @@ bool read_packet(vpn_packet_t *packet)
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
+bool write_packet(vpn_packet_t *packet) {
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
@@ -217,8 +213,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index 8e73a6d3759376eccc2ff0301ae99152c8b8f673..effcb7887b883f6259eddf4e72ef3161aa2e1e70 100644 (file)
@@ -88,7 +88,7 @@ void logger(int priority, const char *format, ...) {
                        {
                                char message[4096];
                                char *messages[] = {message};
-                               vsnprintf(message, sizeof(message), format, ap);
+                               vsnprintf(message, sizeof message, format, ap);
                                ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
                        }
 #else
@@ -98,7 +98,7 @@ void logger(int priority, const char *format, ...) {
 #else
                        {
                                char message[4096];
-                               vsnprintf(message, sizeof(message), format, ap);
+                               vsnprintf(message, sizeof message, format, ap);
                                syslog(priority, "%s", message);
                        }
 #endif
index b59f15b09443f47596d8e60454686e262c5298b7..6054427ce62b0d64b8a283f109afc7dfe7a3c3c7 100644 (file)
 
 #include "system.h"
 
-#include <openssl/err.h>
-#include <openssl/evp.h>
-
-#include "avl_tree.h"
+#include "splay_tree.h"
+#include "cipher.h"
 #include "connection.h"
 #include "logger.h"
 #include "meta.h"
 #include "utils.h"
 #include "xalloc.h"
 
-bool send_meta(connection_t *c, const char *buffer, int length)
-{
-       int outlen;
-       int result;
-
+bool send_meta(connection_t *c, const char *buffer, int length) {
        cp();
 
        if(!c) {
@@ -49,81 +43,31 @@ bool send_meta(connection_t *c, const char *buffer, int length)
        ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
                           c->name, c->hostname);
 
-       if(!c->outbuflen)
-               c->last_flushed_time = now;
-
-       /* Find room in connection's buffer */
-       if(length + c->outbuflen > c->outbufsize) {
-               c->outbufsize = length + c->outbuflen;
-               c->outbuf = xrealloc(c->outbuf, c->outbufsize);
-       }
-
-       if(length + c->outbuflen + c->outbufstart > c->outbufsize) {
-               memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen);
-               c->outbufstart = 0;
-       }
-
        /* Add our data to buffer */
        if(c->status.encryptout) {
-               result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
-                               &outlen, (unsigned char *)buffer, length);
-               if(!result || outlen < length) {
-                       logger(LOG_ERR, _("Error while encrypting metadata to %s (%s): %s"),
-                                       c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
-                       return false;
-               } else if(outlen > length) {
-                       logger(LOG_EMERG, _("Encrypted data too long! Heap corrupted!"));
-                       abort();
-               }
-               c->outbuflen += outlen;
-       } else {
-               memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
-               c->outbuflen += length;
-       }
-
-       return true;
-}
-
-bool flush_meta(connection_t *c)
-{
-       int result;
-       
-       ifdebug(META) logger(LOG_DEBUG, _("Flushing %d bytes to %s (%s)"),
-                        c->outbuflen, c->name, c->hostname);
-
-       while(c->outbuflen) {
-               result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
-               if(result <= 0) {
-                       if(!errno || errno == EPIPE) {
-                               ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection closed by %s (%s)"),
-                                                  c->name, c->hostname);
-                       } else if(errno == EINTR) {
-                               continue;
-#ifdef EWOULDBLOCK
-                       } else if(errno == EWOULDBLOCK) {
-                               ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Flushing %d bytes to %s (%s) would block"),
-                                               c->outbuflen, c->name, c->hostname);
-                               return true;
-#endif
-                       } else {
-                               logger(LOG_ERR, _("Flushing meta data to %s (%s) failed: %s"), c->name,
-                                          c->hostname, strerror(errno));
-                       }
+               char outbuf[length];
+               size_t outlen = length;
 
+               if(!cipher_encrypt(&c->outcipher, buffer, length, outbuf, &outlen, false) || outlen != length) {
+                       logger(LOG_ERR, _("Error while encrypting metadata to %s (%s)"),
+                                       c->name, c->hostname);
                        return false;
                }
-
-               c->outbufstart += result;
-               c->outbuflen -= result;
+               
+               ifdebug(META) logger(LOG_DEBUG, _("Encrypted write %p %p %p %d"), c, c->buffer, outbuf, length);
+               bufferevent_write(c->buffer, (void *)outbuf, length);
+               ifdebug(META) logger(LOG_DEBUG, _("Done."));
+       } else {
+               ifdebug(META) logger(LOG_DEBUG, _("Unencrypted write %p %p %p %d"), c, c->buffer, buffer, length);
+               bufferevent_write(c->buffer, (void *)buffer, length);
+               ifdebug(META) logger(LOG_DEBUG, _("Done."));
        }
 
-       c->outbufstart = 0; /* avoid unnecessary memmoves */
        return true;
 }
 
-void broadcast_meta(connection_t *from, const char *buffer, int length)
-{
-       avl_node_t *node;
+void broadcast_meta(connection_t *from, const char *buffer, int length) {
+       splay_node_t *node;
        connection_t *c;
 
        cp();
@@ -136,12 +80,10 @@ void broadcast_meta(connection_t *from, const char *buffer, int length)
        }
 }
 
-bool receive_meta(connection_t *c)
-{
-       int oldlen, i, result;
-       int lenin, lenout, reqlen;
-       bool decrypted = false;
+bool receive_meta(connection_t *c) {
+       size_t inlen;
        char inbuf[MAXBUFSIZE];
+       char *bufp = inbuf, *endp;
 
        cp();
 
@@ -154,89 +96,70 @@ bool receive_meta(connection_t *c)
           - If not, keep stuff in buffer and exit.
         */
 
-       lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0);
-
-       if(lenin <= 0) {
-               if(!lenin || !errno) {
-                       ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection closed by %s (%s)"),
-                                          c->name, c->hostname);
-               } else if(errno == EINTR)
-                       return true;
-               else
-                       logger(LOG_ERR, _("Metadata socket read error for %s (%s): %s"),
-                                  c->name, c->hostname, strerror(errno));
+       inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
 
+       if(inlen <= 0) {
+               logger(LOG_ERR, _("Receive callback called for %s (%s) but no data to receive: %s"), c->name, c->hostname, strerror(errno));
                return false;
        }
 
-       oldlen = c->buflen;
-       c->buflen += lenin;
+       do {
+               if(!c->status.decryptin) {
+                       endp = memchr(bufp, '\n', inlen);
+                       if(endp)
+                               endp++;
+                       else
+                               endp = bufp + inlen;
 
-       while(lenin > 0) {
-               /* Decrypt */
+                       evbuffer_add(c->buffer->input, bufp, endp - bufp);
 
-               if(c->status.decryptin && !decrypted) {
-                       result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
-                       if(!result || lenout != lenin) {
-                               logger(LOG_ERR, _("Error while decrypting metadata from %s (%s): %s"),
-                                               c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
+                       inlen -= endp - bufp;
+                       bufp = endp;
+               } else {
+                       size_t outlen = inlen;
+                       ifdebug(META) logger(LOG_DEBUG, _("Received encrypted %zu bytes"), inlen);
+                       evbuffer_expand(c->buffer->input, c->buffer->input->off + inlen);
+
+                       if(!cipher_decrypt(&c->incipher, bufp, inlen, c->buffer->input->buffer + c->buffer->input->off, &outlen, false) || inlen != outlen) {
+                               logger(LOG_ERR, _("Error while decrypting metadata from %s (%s)"),
+                                          c->name, c->hostname);
                                return false;
                        }
-                       memcpy(c->buffer + oldlen, inbuf, lenin);
-                       decrypted = true;
+                       c->buffer->input->off += inlen;
+
+                       inlen = 0;
                }
 
-               /* Are we receiving a TCPpacket? */
+               while(c->buffer->input->off) {
+                       /* Are we receiving a TCPpacket? */
+
+                       if(c->tcplen) {
+                               if(c->tcplen <= c->buffer->input->off) {
+                                       receive_tcppacket(c, (char *)c->buffer->input->buffer, c->tcplen);
+                                       evbuffer_drain(c->buffer->input, c->tcplen);
+                                       c->tcplen = 0;
+                                       continue;
+                               } else {
+                                       break;
+                               }
+                       }
 
-               if(c->tcplen) {
-                       if(c->tcplen <= c->buflen) {
-                               receive_tcppacket(c, c->buffer, c->tcplen);
+                       /* Otherwise we are waiting for a request */
 
-                               c->buflen -= c->tcplen;
-                               lenin -= c->tcplen - oldlen;
-                               memmove(c->buffer, c->buffer + c->tcplen, c->buflen);
-                               oldlen = 0;
-                               c->tcplen = 0;
+                       char *request = evbuffer_readline(c->buffer->input);
+                       if(request) {
+                               bool result = receive_request(c, request);
+                               free(request);
+                               if(!result)
+                                       return false;
                                continue;
                        } else {
                                break;
                        }
                }
+       } while(inlen);
 
-               /* Otherwise we are waiting for a request */
-
-               reqlen = 0;
-
-               for(i = oldlen; i < c->buflen; i++) {
-                       if(c->buffer[i] == '\n') {
-                               c->buffer[i] = '\0';    /* replace end-of-line by end-of-string so we can use sscanf */
-                               reqlen = i + 1;
-                               break;
-                       }
-               }
-
-               if(reqlen) {
-                       c->reqlen = reqlen;
-                       if(!receive_request(c))
-                               return false;
-
-                       c->buflen -= reqlen;
-                       lenin -= reqlen - oldlen;
-                       memmove(c->buffer, c->buffer + reqlen, c->buflen);
-                       oldlen = 0;
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       if(c->buflen >= MAXBUFSIZE) {
-               logger(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"),
-                          c->name, c->hostname);
-               return false;
-       }
-
-       c->last_ping_time = now;
+       c->last_ping_time = time(NULL);
 
        return true;
 }
index 192bf24c6d9148408170ab11922374696bf0970b..f67caf4001b248827a79b50067cbfce00b34e362 100644 (file)
@@ -27,7 +27,7 @@
 
 extern bool send_meta(struct connection_t *, const char *, int);
 extern void broadcast_meta(struct connection_t *, const char *, int);
-extern bool flush_meta(struct connection_t *);
+extern void flush_meta(int fd, short events, void *data);
 extern bool receive_meta(struct connection_t *);
 
 #endif                                                 /* __TINC_META_H__ */
index fa13433230fb2e1c66e7ccd15829ede8c8e9be2f..2334af3913c49a5a71248a3045008c1bd7fb185b 100644 (file)
@@ -84,8 +84,7 @@ static DWORD WINAPI tapreader(void *bla) {
        }
 }
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        HKEY key, key2;
        int i;
 
@@ -122,18 +121,18 @@ bool setup_device(void)
        }
 
        for (i = 0; ; i++) {
-               len = sizeof(adapterid);
+               len = sizeof adapterid;
                if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
                        break;
 
                /* Find out more about this adapter */
 
-               snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
+               snprintf(regpath, sizeof regpath, "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
 
                 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
                        continue;
 
-               len = sizeof(adaptername);
+               len = sizeof adaptername;
                err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
 
                RegCloseKey(key2);
@@ -157,7 +156,7 @@ bool setup_device(void)
                                continue;
                }
 
-               snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
+               snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
                if(device_handle != INVALID_HANDLE_VALUE) {
                        found = true;
@@ -181,7 +180,7 @@ bool setup_device(void)
        /* Try to open the corresponding tap device */
 
        if(device_handle == INVALID_HANDLE_VALUE) {
-               snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
+               snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
        }
        
@@ -192,7 +191,7 @@ bool setup_device(void)
 
        /* Get MAC address from tap device */
 
-       if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
+       if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
                logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
                return false;
        }
@@ -213,7 +212,7 @@ bool setup_device(void)
        /* Set media status for newer TAP-Win32 devices */
 
        status = true;
-       DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
+       DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
 
        device_info = _("Windows tap device");
 
@@ -222,8 +221,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
 
        CloseHandle(device_handle);
@@ -232,14 +230,12 @@ void close_device(void)
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
+bool read_packet(vpn_packet_t *packet) {
        return false;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
-       long lenout;
+bool write_packet(vpn_packet_t *packet) {
+       long outlen;
        OVERLAPPED overlapped = {0};
 
        cp();
@@ -247,7 +243,7 @@ bool write_packet(vpn_packet_t *packet)
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
                           packet->len, device_info);
 
-       if(!WriteFile(device_handle, packet->data, packet->len, &lenout, &overlapped)) {
+       if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
                logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
                return false;
        }
@@ -257,8 +253,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index 82b0ede18ba84e8d0e362856481ff4fe688f26dc..8ee782145cbd9b28a5d12734b50022db2dffd7ce 100644 (file)
--- a/src/net.c
+++ b/src/net.c
 #include <openssl/rand.h>
 
 #include "utils.h"
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "conf.h"
 #include "connection.h"
 #include "device.h"
-#include "event.h"
 #include "graph.h"
 #include "logger.h"
 #include "meta.h"
 #include "netutl.h"
 #include "process.h"
 #include "protocol.h"
-#include "route.h"
 #include "subnet.h"
 #include "xalloc.h"
 
-bool do_purge = false;
-volatile bool running = false;
-
-time_t now = 0;
-
 /* Purge edges and subnets of unreachable nodes. Use carefully. */
 
-static void purge(void)
-{
-       avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
+void purge(void) {
+       splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
        node_t *n;
        edge_t *e;
        subnet_t *s;
@@ -108,55 +100,6 @@ static void purge(void)
        }
 }
 
-/*
-  put all file descriptors in an fd_set array
-  While we're at it, purge stuff that needs to be removed.
-*/
-static int build_fdset(fd_set *readset, fd_set *writeset)
-{
-       avl_node_t *node, *next;
-       connection_t *c;
-       int i, max = 0;
-
-       cp();
-
-       FD_ZERO(readset);
-       FD_ZERO(writeset);
-
-       for(node = connection_tree->head; node; node = next) {
-               next = node->next;
-               c = node->data;
-
-               if(c->status.remove) {
-                       connection_del(c);
-                       if(!connection_tree->head)
-                               purge();
-               } else {
-                       FD_SET(c->socket, readset);
-                       if(c->outbuflen > 0)
-                               FD_SET(c->socket, writeset);
-                       if(c->socket > max)
-                               max = c->socket;
-               }
-       }
-
-       for(i = 0; i < listen_sockets; i++) {
-               FD_SET(listen_socket[i].tcp, readset);
-               if(listen_socket[i].tcp > max)
-                       max = listen_socket[i].tcp;
-               FD_SET(listen_socket[i].udp, readset);
-               if(listen_socket[i].udp > max)
-                       max = listen_socket[i].udp;
-       }
-
-       if(device_fd >= 0)
-               FD_SET(device_fd, readset);
-       if(device_fd > max)
-               max = device_fd;
-       
-       return max;
-}
-
 /*
   Terminate a connection:
   - Close the socket
@@ -164,17 +107,12 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
   - Check if we need to retry making an outgoing connection
   - Deactivate the host
 */
-void terminate_connection(connection_t *c, bool report)
-{
+void terminate_connection(connection_t *c, bool report) {
        cp();
 
-       if(c->status.remove)
-               return;
-
        ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Closing connection with %s (%s)"),
                           c->name, c->hostname);
 
-       c->status.remove = true;
        c->status.active = false;
 
        if(c->node)
@@ -208,16 +146,10 @@ void terminate_connection(connection_t *c, bool report)
 
        /* Check if this was our outgoing connection */
 
-       if(c->outgoing) {
+       if(c->outgoing)
                retry_outgoing(c->outgoing);
-               c->outgoing = NULL;
-       }
 
-       free(c->outbuf);
-       c->outbuf = NULL;
-       c->outbuflen = 0;
-       c->outbufsize = 0;
-       c->outbufstart = 0;
+       connection_del(c);
 }
 
 /*
@@ -228,10 +160,10 @@ void terminate_connection(connection_t *c, bool report)
   end does not reply in time, we consider them dead
   and close the connection.
 */
-static void check_dead_connections(void)
-{
-       avl_node_t *node, *next;
+static void timeout_handler(int fd, short events, void *event) {
+       splay_node_t *node, *next;
        connection_t *c;
+       time_t now = time(NULL);
 
        cp();
 
@@ -244,254 +176,162 @@ static void check_dead_connections(void)
                                if(c->status.pinged) {
                                        ifdebug(CONNECTIONS) logger(LOG_INFO, _("%s (%s) didn't respond to PING in %ld seconds"),
                                                           c->name, c->hostname, now - c->last_ping_time);
-                                       c->status.timeout = true;
                                        terminate_connection(c, true);
+                                       continue;
                                } else if(c->last_ping_time + pinginterval < now) {
                                        send_ping(c);
                                }
                        } else {
-                               if(c->status.remove) {
-                                       logger(LOG_WARNING, _("Old connection_t for %s (%s) status %04x still lingering, deleting..."),
-                                                  c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status));
-                                       connection_del(c);
-                                       continue;
-                               }
-                               ifdebug(CONNECTIONS) logger(LOG_WARNING, _("Timeout from %s (%s) during authentication"),
-                                                  c->name, c->hostname);
                                if(c->status.connecting) {
+                                       ifdebug(CONNECTIONS)
+                                               logger(LOG_WARNING, _("Timeout while connecting to %s (%s)"), c->name, c->hostname);
                                        c->status.connecting = false;
                                        closesocket(c->socket);
                                        do_outgoing_connection(c);
                                } else {
+                                       ifdebug(CONNECTIONS) logger(LOG_WARNING, _("Timeout from %s (%s) during authentication"), c->name, c->hostname);
                                        terminate_connection(c, false);
+                                       continue;
                                }
                        }
                }
+       }
 
-               if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) {
-                       if(c->status.active) {
-                               ifdebug(CONNECTIONS) logger(LOG_INFO,
-                                               _("%s (%s) could not flush for %ld seconds (%d bytes remaining)"),
-                                               c->name, c->hostname, now - c->last_flushed_time, c->outbuflen);
-                               c->status.timeout = true;
-                               terminate_connection(c, true);
-                       }
+       event_add(event, &(struct timeval){pingtimeout, 0});
+}
+
+void handle_meta_connection_data(int fd, short events, void *data) {
+       connection_t *c = data;
+       int result;
+       socklen_t len = sizeof result;
+
+       if(c->status.connecting) {
+               c->status.connecting = false;
+
+               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
+
+               if(!result)
+                       finish_connecting(c);
+               else {
+                       ifdebug(CONNECTIONS) logger(LOG_DEBUG,
+                                          _("Error while connecting to %s (%s): %s"),
+                                          c->name, c->hostname, strerror(result));
+                       closesocket(c->socket);
+                       do_outgoing_connection(c);
+                       return;
                }
        }
+
+       if (!receive_meta(c)) {
+               terminate_connection(c, c->status.active);
+               return;
+       }
 }
 
-/*
-  check all connections to see if anything
-  happened on their sockets
-*/
-static void check_network_activity(fd_set * readset, fd_set * writeset)
-{
+static void sigterm_handler(int signal, short events, void *data) {
+       logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
+       event_loopexit(NULL);
+}
+
+static void sighup_handler(int signal, short events, void *data) {
+       logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
+       reload_configuration();
+}
+
+int reload_configuration(void) {
        connection_t *c;
-       avl_node_t *node;
-       int result, i;
-       socklen_t len = sizeof(result);
-       vpn_packet_t packet;
+       splay_node_t *node, *next;
+       char *fname;
+       struct stat s;
+       static time_t last_config_check = 0;
 
-       cp();
+       /* Reread our own configuration file */
 
-       /* check input from kernel */
-       if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
-               if(read_packet(&packet)) {
-                       packet.priority = 0;
-                       route(myself, &packet);
-               }
+       exit_configuration(&config_tree);
+       init_configuration(&config_tree);
+
+       if(!read_server_config()) {
+               logger(LOG_ERR, _("Unable to reread configuration file, exitting."));
+               event_loopexit(NULL);
+               return EINVAL;
        }
 
-       /* check meta connections */
-       for(node = connection_tree->head; node; node = node->next) {
+       /* Close connections to hosts that have a changed or deleted host config file */
+       
+       for(node = connection_tree->head; node; node = next) {
                c = node->data;
+               next = node->next;
+               
+               if(c->outgoing) {
+                       free(c->outgoing->name);
+                       if(c->outgoing->ai)
+                               freeaddrinfo(c->outgoing->ai);
+                       free(c->outgoing);
+                       c->outgoing = NULL;
+               }
+               
+               asprintf(&fname, "%s/hosts/%s", confbase, c->name);
+               if(stat(fname, &s) || s.st_mtime > last_config_check)
+                       terminate_connection(c, c->status.active);
+               free(fname);
+       }
 
-               if(c->status.remove)
-                       continue;
+       last_config_check = time(NULL);
 
-               if(FD_ISSET(c->socket, readset)) {
-                       if(c->status.connecting) {
-                               c->status.connecting = false;
-                               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
+       /* Try to make outgoing connections */
+       
+       try_outgoing_connections();
 
-                               if(!result)
-                                       finish_connecting(c);
-                               else {
-                                       ifdebug(CONNECTIONS) logger(LOG_DEBUG,
-                                                          _("Error while connecting to %s (%s): %s"),
-                                                          c->name, c->hostname, strerror(result));
-                                       closesocket(c->socket);
-                                       do_outgoing_connection(c);
-                                       continue;
-                               }
-                       }
+       return 0;
+}
 
-                       if(!receive_meta(c)) {
-                               terminate_connection(c, c->status.active);
-                               continue;
-                       }
-               }
+void retry(void) {
+       connection_t *c;
+       splay_node_t *node;
 
-               if(FD_ISSET(c->socket, writeset)) {
-                       if(!flush_meta(c)) {
-                               terminate_connection(c, c->status.active);
-                               continue;
-                       }
+       for(node = connection_tree->head; node; node = node->next) {
+               c = node->data;
+               
+               if(c->outgoing && !c->node) {
+                       if(timeout_initialized(&c->outgoing->ev))
+                               event_del(&c->outgoing->ev);
+                       if(c->status.connecting)
+                               close(c->socket);
+                       c->outgoing->timeout = 0;
+                       do_outgoing_connection(c);
                }
        }
-
-       for(i = 0; i < listen_sockets; i++) {
-               if(FD_ISSET(listen_socket[i].udp, readset))
-                       handle_incoming_vpn_data(listen_socket[i].udp);
-
-               if(FD_ISSET(listen_socket[i].tcp, readset))
-                       handle_new_meta_connection(listen_socket[i].tcp);
-       }
 }
 
 /*
   this is where it all happens...
 */
-int main_loop(void)
-{
-       fd_set readset, writeset;
-       struct timeval tv;
-       int r, maxfd;
-       time_t last_ping_check, last_config_check, last_graph_dump;
-       event_t *event;
+int main_loop(void) {
+       struct event timeout_event;
+       struct event sighup_event;
+       struct event sigterm_event;
+       struct event sigquit_event;
 
        cp();
 
-       last_ping_check = now;
-       last_config_check = now;
-       last_graph_dump = now;
-       
-       srand(now);
-
-       running = true;
-
-       while(running) {
-               now = time(NULL);
-
-       //      tv.tv_sec = 1 + (rand() & 7);   /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
-               tv.tv_sec = 1;
-               tv.tv_usec = 0;
-
-               maxfd = build_fdset(&readset, &writeset);
-
-#ifdef HAVE_MINGW
-               LeaveCriticalSection(&mutex);
-#endif
-               r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
-#ifdef HAVE_MINGW
-               EnterCriticalSection(&mutex);
-#endif
-
-               if(r < 0) {
-                       if(errno != EINTR && errno != EAGAIN) {
-                               logger(LOG_ERR, _("Error while waiting for input: %s"),
-                                          strerror(errno));
-                               cp_trace();
-                               dump_connections();
-                               return 1;
-                       }
-
-                       continue;
-               }
-
-               check_network_activity(&readset, &writeset);
-
-               if(do_purge) {
-                       purge();
-                       do_purge = false;
-               }
-
-               /* Let's check if everybody is still alive */
-
-               if(last_ping_check + pingtimeout < now) {
-                       check_dead_connections();
-                       last_ping_check = now;
-
-                       if(routing_mode == RMODE_SWITCH)
-                               age_subnets();
-
-                       age_past_requests();
-
-                       /* Should we regenerate our key? */
-
-                       if(keyexpires < now) {
-                               avl_node_t *node;
-                               node_t *n;
-
-                               ifdebug(STATUS) logger(LOG_INFO, _("Expiring symmetric keys"));
-
-                               for(node = node_tree->head; node; node = node->next) {
-                                       n = node->data;
-                                       if(n->inkey) {
-                                               free(n->inkey);
-                                               n->inkey = NULL;
-                                       }
-                               }
-
-                               send_key_changed(broadcast, myself);
-                               keyexpires = now + keylifetime;
-                       }
-               }
-
-               if(sigalrm) {
-                       logger(LOG_INFO, _("Flushing event queue"));
-                       expire_events();
-                       sigalrm = false;
-               }
-
-               while((event = get_expired_event())) {
-                       event->handler(event->data);
-                       free_event(event);
-               }
-
-               if(sighup) {
-                       connection_t *c;
-                       avl_node_t *node;
-                       char *fname;
-                       struct stat s;
-                       
-                       sighup = false;
-                       
-                       /* Reread our own configuration file */
-
-                       exit_configuration(&config_tree);
-                       init_configuration(&config_tree);
-
-                       if(!read_server_config()) {
-                               logger(LOG_ERR, _("Unable to reread configuration file, exitting."));
-                               return 1;
-                       }
-
-                       /* Close connections to hosts that have a changed or deleted host config file */
-                       
-                       for(node = connection_tree->head; node; node = node->next) {
-                               c = node->data;
-                               
-                               xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
-                               if(stat(fname, &s) || s.st_mtime > last_config_check)
-                                       terminate_connection(c, c->status.active);
-                               free(fname);
-                       }
-
-                       last_config_check = now;
-
-                       /* Try to make outgoing connections */
-                       
-                       try_outgoing_connections();
-               }
-               
-               /* Dump graph if wanted every 60 seconds*/
-
-               if(last_graph_dump + 60 < now) {
-                       dump_graph();
-                       last_graph_dump = now;
-               }
+       timeout_set(&timeout_event, timeout_handler, &timeout_event);
+       event_add(&timeout_event, &(struct timeval){pingtimeout, 0});
+       signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
+       signal_add(&sighup_event, NULL);
+       signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
+       signal_add(&sigterm_event, NULL);
+       signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
+       signal_add(&sigquit_event, NULL);
+
+       if(event_loop(0) < 0) {
+               logger(LOG_ERR, _("Error while waiting for input: %s"), strerror(errno));
+               return 1;
        }
 
+       signal_del(&sighup_event);
+       signal_del(&sigterm_event);
+       signal_del(&sigquit_event);
+       event_del(&timeout_event);
+
        return 0;
 }
index ff32b73c9181e6746240dcc982782800d99fa313..57e9d8db3a0c7ddb05a915e6c7a4f970c49406a1 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -23,9 +23,9 @@
 #ifndef __TINC_NET_H__
 #define __TINC_NET_H__
 
-#include <openssl/evp.h>
-
 #include "ipv6.h"
+#include "cipher.h"
+#include "digest.h"
 
 #ifdef ENABLE_JUMBOGRAMS
 #define MTU 9018                               /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
 #define MTU 1518                               /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
 #endif
 
-#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20)       /* MTU + seqno + padding + HMAC + compressor overhead */
+#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)      /* MTU + seqno + padding + HMAC + compressor overhead */
 #define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)   /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
 
-#define MAXSOCKETS 128                 /* Overkill... */
+#define MAXSOCKETS 8                   /* Probably overkill... */
 
 typedef struct mac_t {
        uint8_t x[6];
@@ -86,6 +86,8 @@ typedef struct vpn_packet_t {
 } vpn_packet_t;
 
 typedef struct listen_socket_t {
+       struct event ev_tcp;
+       struct event ev_udp;
        int tcp;
        int udp;
        sockaddr_t sa;
@@ -100,6 +102,7 @@ typedef struct outgoing_t {
        struct config_t *cfg;
        struct addrinfo *ai;
        struct addrinfo *aip;
+       struct event ev;
 } outgoing_t;
 
 extern list_t *outgoing_list;
@@ -110,22 +113,19 @@ extern int addressfamily;
 
 extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
-extern int keyexpires;
 extern int keylifetime;
 extern bool do_prune;
-extern bool do_purge;
 extern char *myport;
-extern time_t now;
 
 /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
 #include "connection.h"
 #include "node.h"
 
 extern void retry_outgoing(outgoing_t *);
-extern void handle_incoming_vpn_data(int);
+extern void handle_incoming_vpn_data(int, short, void *);
 extern void finish_connecting(struct connection_t *);
 extern void do_outgoing_connection(struct connection_t *);
-extern bool handle_new_meta_connection(int);
+extern void handle_new_meta_connection(int, short, void *);
 extern int setup_listen_socket(const sockaddr_t *);
 extern int setup_vpn_in_socket(const sockaddr_t *);
 extern void send_packet(const struct node_t *, vpn_packet_t *);
@@ -140,6 +140,12 @@ extern void terminate_connection(struct connection_t *, bool);
 extern void flush_queue(struct node_t *);
 extern bool read_rsa_public_key(struct connection_t *);
 extern void send_mtu_probe(struct node_t *);
+extern void handle_device_data(int, short, void *);
+extern void handle_meta_connection_data(int, short, void *);
+extern void regenerate_key();
+extern void purge(void);
+extern void retry(void);
+extern int reload_configuration(void);
 
 #ifndef HAVE_MINGW
 #define closesocket(s) close(s)
index aca84683e5aaa5a500758803bdcaf90ba435ac8e..77e29c0a9deeda77080d1208ec7edbadc4324c2c 100644 (file)
 
 #include "system.h"
 
-#include <openssl/rand.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/hmac.h>
-
 #include <zlib.h>
 #include LZO1X_H
 
-#include "avl_tree.h"
+#include "splay_tree.h"
+#include "cipher.h"
 #include "conf.h"
 #include "connection.h"
+#include "crypto.h"
+#include "digest.h"
 #include "device.h"
 #include "ethernet.h"
-#include "event.h"
 #include "graph.h"
 #include "list.h"
 #include "logger.h"
@@ -60,15 +56,14 @@ static void send_udppacket(node_t *, vpn_packet_t *);
 
 #define MAX_SEQNO 1073741824
 
-void send_mtu_probe(node_t *n)
-{
+static void send_mtu_probe_handler(int fd, short events, void *data) {
+       node_t *n = data;
        vpn_packet_t packet;
        int len, i;
        
        cp();
 
        n->mtuprobes++;
-       n->mtuevent = NULL;
 
        if(!n->status.reachable) {
                logger(LOG_DEBUG, _("Trying to send MTU probe to unreachable node %s (%s)"), n->name, n->hostname);
@@ -92,7 +87,7 @@ void send_mtu_probe(node_t *n)
                        len = 64;
                
                memset(packet.data, 0, 14);
-               RAND_pseudo_bytes(packet.data + 14, len - 14);
+               randomize(packet.data + 14, len - 14);
                packet.len = len;
                packet.priority = 0;
 
@@ -101,11 +96,13 @@ void send_mtu_probe(node_t *n)
                send_udppacket(n, &packet);
        }
 
-       n->mtuevent = new_event();
-       n->mtuevent->handler = (event_handler_t)send_mtu_probe;
-       n->mtuevent->data = n;
-       n->mtuevent->time = now + 1;
-       event_add(n->mtuevent);
+       event_add(&n->mtuevent, &(struct timeval){1, 0});
+}
+
+void send_mtu_probe(node_t *n) {
+       if(!timeout_initialized(&n->mtuevent))
+               timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
+       send_mtu_probe_handler(0, 0, n);
 }
 
 void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
@@ -120,8 +117,7 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        }
 }
 
-static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
-{
+static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
        if(level == 10) {
                lzo_uint lzolen = MAXSIZE;
                lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
@@ -141,8 +137,7 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l
        return -1;
 }
 
-static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
-{
+static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
        if(level > 9) {
                lzo_uint lzolen = MAXSIZE;
                if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK)
@@ -162,8 +157,7 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
 
 /* VPN packet I/O */
 
-static void receive_packet(node_t *n, vpn_packet_t *packet)
-{
+static void receive_packet(node_t *n, vpn_packet_t *packet) {
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"),
@@ -172,16 +166,12 @@ static void receive_packet(node_t *n, vpn_packet_t *packet)
        route(n, packet);
 }
 
-static bool try_mac(const node_t *n, const vpn_packet_t *inpkt)
+static bool try_mac(node_t *n, const vpn_packet_t *inpkt)
 {
-       unsigned char hmac[EVP_MAX_MD_SIZE];
-
-       if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
+       if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
                return false;
 
-       HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
-
-       return !memcmp(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
+       return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len);
 }
 
 static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
@@ -190,13 +180,12 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
        vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
        int nextpkt = 0;
        vpn_packet_t *outpkt = pkt[0];
-       int outlen, outpad;
-       unsigned char hmac[EVP_MAX_MD_SIZE];
+       size_t outlen;
        int i;
 
        cp();
 
-       if(!n->inkey) {
+       if(!cipher_active(&n->incipher)) {
                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got packet from %s (%s) but he hasn't got our key yet"),
                                        n->name, n->hostname);
                return;
@@ -204,7 +193,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        /* Check packet length */
 
-       if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
+       if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
                                        n->name, n->hostname);
                return;
@@ -212,66 +201,56 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        /* Check the message authentication code */
 
-       if(n->indigest && n->inmaclength) {
-               inpkt->len -= n->inmaclength;
-               HMAC(n->indigest, n->inkey, n->inkeylength,
-                        (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
-
-               if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
-                       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
-                                          n->name, n->hostname);
-                       return;
-               }
+       if(digest_active(&n->indigest) && !digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname);
+               return;
        }
 
        /* Decrypt the packet */
 
-       if(n->incipher) {
+       if(cipher_active(&n->incipher)) {
                outpkt = pkt[nextpkt++];
+               outlen = MAXSIZE;
 
-               if(!EVP_DecryptInit_ex(&n->inctx, NULL, NULL, NULL, NULL)
-                               || !EVP_DecryptUpdate(&n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
-                                       (unsigned char *) &inpkt->seqno, inpkt->len)
-                               || !EVP_DecryptFinal_ex(&n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
-                       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s): %s"),
-                                               n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
+               if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+                       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s)"), n->name, n->hostname);
                        return;
                }
                
-               outpkt->len = outlen + outpad;
+               outpkt->len = outlen;
                inpkt = outpkt;
        }
 
        /* Check the sequence number */
 
-       inpkt->len -= sizeof(inpkt->seqno);
+       inpkt->len -= sizeof inpkt->seqno;
        inpkt->seqno = ntohl(inpkt->seqno);
 
        if(inpkt->seqno != n->received_seqno + 1) {
-               if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) {
+               if(inpkt->seqno >= n->received_seqno + sizeof n->late * 8) {
                        logger(LOG_WARNING, _("Lost %d packets from %s (%s)"),
                                           inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
                        
-                       memset(n->late, 0, sizeof(n->late));
+                       memset(n->late, 0, sizeof n->late);
                } else if (inpkt->seqno <= n->received_seqno) {
-                       if((n->received_seqno >= sizeof(n->late) * 8 && inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8) || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) {
+                       if((n->received_seqno >= sizeof n->late * 8 && inpkt->seqno <= n->received_seqno - sizeof n->late * 8) || !(n->late[(inpkt->seqno / 8) % sizeof n->late] & (1 << inpkt->seqno % 8))) {
                                logger(LOG_WARNING, _("Got late or replayed packet from %s (%s), seqno %d, last received %d"),
                                           n->name, n->hostname, inpkt->seqno, n->received_seqno);
                                return;
                        }
                } else {
                        for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
-                               n->late[(i / 8) % sizeof(n->late)] |= 1 << i % 8;
+                               n->late[(i / 8) % sizeof n->late] |= 1 << i % 8;
                }
        }
        
-       n->late[(inpkt->seqno / 8) % sizeof(n->late)] &= ~(1 << inpkt->seqno % 8);
+       n->late[(inpkt->seqno / 8) % sizeof n->late] &= ~(1 << inpkt->seqno % 8);
 
        if(inpkt->seqno > n->received_seqno)
                n->received_seqno = inpkt->seqno;
                        
        if(n->received_seqno > MAX_SEQNO)
-               keyexpires = 0;
+               regenerate_key();
 
        /* Decompress the packet */
 
@@ -293,17 +272,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        inpkt->priority = 0;
 
-       if(n->connection)
-               n->connection->last_ping_time = now;
-
        if(!inpkt->data[12] && !inpkt->data[13])
                mtu_probe_h(n, inpkt, origlen);
        else
                receive_packet(n, inpkt);
 }
 
-void receive_tcppacket(connection_t *c, char *buffer, int len)
-{
+void receive_tcppacket(connection_t *c, char *buffer, int len) {
        vpn_packet_t outpkt;
 
        cp();
@@ -318,15 +293,14 @@ void receive_tcppacket(connection_t *c, char *buffer, int len)
        receive_packet(c->node, &outpkt);
 }
 
-static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
-{
+static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
        vpn_packet_t pkt1, pkt2;
        vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
        vpn_packet_t *inpkt = origpkt;
        int nextpkt = 0;
        vpn_packet_t *outpkt;
        int origlen;
-       int outlen, outpad;
+       size_t outlen;
        static int priority = 0;
        int origpriority;
        int sock;
@@ -385,32 +359,28 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
        /* Add sequence number */
 
        inpkt->seqno = htonl(++(n->sent_seqno));
-       inpkt->len += sizeof(inpkt->seqno);
+       inpkt->len += sizeof inpkt->seqno;
 
        /* Encrypt the packet */
 
-       if(n->outcipher) {
+       if(cipher_active(&n->outcipher)) {
                outpkt = pkt[nextpkt++];
+               outlen = MAXSIZE;
 
-               if(!EVP_EncryptInit_ex(&n->outctx, NULL, NULL, NULL, NULL)
-                               || !EVP_EncryptUpdate(&n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
-                                       (unsigned char *) &inpkt->seqno, inpkt->len)
-                               || !EVP_EncryptFinal_ex(&n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
-                       ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s): %s"),
-                                               n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
+               if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+                       ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s)"), n->name, n->hostname);
                        goto end;
                }
 
-               outpkt->len = outlen + outpad;
+               outpkt->len = outlen;
                inpkt = outpkt;
        }
 
        /* Add the message authentication code */
 
-       if(n->outdigest && n->outmaclength) {
-               HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
-                        inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
-               inpkt->len += n->outmaclength;
+       if(digest_active(&n->outdigest)) {
+               digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len);
+               inpkt->len += digest_length(&n->outdigest);
        }
 
        /* Determine which socket we have to use */
@@ -429,7 +399,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
           && listen_socket[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[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
@@ -451,8 +421,7 @@ end:
 /*
   send a packet to the given vpn ip.
 */
-void send_packet(const node_t *n, vpn_packet_t *packet)
-{
+void send_packet(const node_t *n, vpn_packet_t *packet) {
        node_t *via;
 
        cp();
@@ -488,9 +457,8 @@ void send_packet(const node_t *n, vpn_packet_t *packet)
 
 /* Broadcast a packet using the minimum spanning tree */
 
-void broadcast_packet(const node_t *from, vpn_packet_t *packet)
-{
-       avl_node_t *node;
+void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
+       splay_node_t *node;
        connection_t *c;
 
        cp();
@@ -516,7 +484,7 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet)
 }
 
 static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
-       avl_node_t *node;
+       splay_node_t *node;
        edge_t *e;
        node_t *n = NULL;
 
@@ -539,12 +507,12 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        return n;
 }
 
-void handle_incoming_vpn_data(int sock)
+void handle_incoming_vpn_data(int sock, short events, void *data)
 {
        vpn_packet_t pkt;
        char *hostname;
        sockaddr_t from;
-       socklen_t fromlen = sizeof(from);
+       socklen_t fromlen = sizeof from;
        node_t *n;
 
        cp();
@@ -577,3 +545,10 @@ void handle_incoming_vpn_data(int sock)
 
        receive_udppacket(n, &pkt);
 }
+
+void handle_device_data(int sock, short events, void *data) {
+       vpn_packet_t packet;
+
+       if(read_packet(&packet))
+               route(myself, &packet);
+}
index 3c4bf48c71607795b8c5f4bedbc44436ef2e1991..623eb1856692507628971263529110e5ff244cc4 100644 (file)
 
 #include "system.h"
 
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-#include <openssl/rand.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-
-#include "avl_tree.h"
+#include "splay_tree.h"
+#include "cipher.h"
 #include "conf.h"
 #include "connection.h"
+#include "control.h"
 #include "device.h"
-#include "event.h"
+#include "digest.h"
 #include "graph.h"
 #include "logger.h"
 #include "net.h"
 #include "process.h"
 #include "protocol.h"
 #include "route.h"
+#include "rsa.h"
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
 
 char *myport;
+static struct event device_ev;
 
-bool read_rsa_public_key(connection_t *c)
-{
+bool read_rsa_public_key(connection_t *c) {
        FILE *fp;
        char *fname;
-       char *key;
+       char *n;
+       bool result;
 
        cp();
 
-       if(!c->rsa_key) {
-               c->rsa_key = RSA_new();
-//             RSA_blinding_on(c->rsa_key, NULL);
-       }
-
        /* First, check for simple PublicKey statement */
 
-       if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) {
-               BN_hex2bn(&c->rsa_key->n, key);
-               BN_hex2bn(&c->rsa_key->e, "FFFF");
-               free(key);
-               return true;
+       if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) {
+               result = rsa_set_hex_public_key(&c->rsa, n, "FFFF");
+               free(n);
+               return result;
        }
 
        /* Else, check for PublicKeyFile statement and read it */
 
-       if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) {
-               fp = fopen(fname, "r");
-
-               if(!fp) {
-                       logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
-                                  fname, strerror(errno));
-                       free(fname);
-                       return false;
-               }
-
-               free(fname);
-               c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
-               fclose(fp);
-
-               if(c->rsa_key)
-                       return true;            /* Woohoo. */
+       if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
+               asprintf(&fname, "%s/hosts/%s", confbase, c->name);
 
-               /* If it fails, try PEM_read_RSA_PUBKEY. */
-               fp = fopen(fname, "r");
-
-               if(!fp) {
-                       logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
-                                  fname, strerror(errno));
-                       free(fname);
-                       return false;
-               }
-
-               free(fname);
-               c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
-               fclose(fp);
-
-               if(c->rsa_key) {
-//                             RSA_blinding_on(c->rsa_key, NULL);
-                       return true;
-               }
+       fp = fopen(fname, "r");
 
-               logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"),
+       if(!fp) {
+               logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
                           fname, strerror(errno));
+               free(fname);
                return false;
        }
 
-       /* Else, check if a harnessed public key is in the config file */
-
-       xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
-       fp = fopen(fname, "r");
-
-       if(fp) {
-               c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
-               fclose(fp);
-       }
-
-       free(fname);
-
-       if(c->rsa_key)
-               return true;
-
-       /* Try again with PEM_read_RSA_PUBKEY. */
-
-       xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
-       fp = fopen(fname, "r");
-
-       if(fp) {
-               c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
-//             RSA_blinding_on(c->rsa_key, NULL);
-               fclose(fp);
-       }
+       result = rsa_read_pem_public_key(&c->rsa, fp);
+       fclose(fp);
 
+       if(!result) 
+               logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), fname, strerror(errno));
        free(fname);
-
-       if(c->rsa_key)
-               return true;
-
-       logger(LOG_ERR, _("No public key for %s specified!"), c->name);
-
-       return false;
+       return result;
 }
 
-bool read_rsa_private_key(void)
-{
+bool read_rsa_private_key() {
        FILE *fp;
-       char *fname, *key, *pubkey;
-       struct stat s;
+       char *fname;
+       char *n, *d;
+       bool result;
 
        cp();
 
-       if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
-               if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) {
+       /* First, check for simple PrivateKey statement */
+
+       if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
+               if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) {
                        logger(LOG_ERR, _("PrivateKey used but no PublicKey found!"));
+                       free(d);
                        return false;
                }
-               myself->connection->rsa_key = RSA_new();
-//             RSA_blinding_on(myself->connection->rsa_key, NULL);
-               BN_hex2bn(&myself->connection->rsa_key->d, key);
-               BN_hex2bn(&myself->connection->rsa_key->n, pubkey);
-               BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
-               free(key);
-               free(pubkey);
+               result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
+               free(n);
+               free(d);
                return true;
        }
 
+       /* Else, check for PrivateKeyFile statement and read it */
+
        if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
                xasprintf(&fname, "%s/rsa_key.priv", confbase);
 
@@ -183,9 +120,10 @@ bool read_rsa_private_key(void)
        }
 
 #if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
+       struct stat s;
+
        if(fstat(fileno(fp), &s)) {
-               logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"),
-                               fname, strerror(errno));
+               logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"), fname, strerror(errno));
                free(fname);
                return false;
        }
@@ -194,25 +132,37 @@ bool read_rsa_private_key(void)
                logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
 #endif
 
-       myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+       result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
        fclose(fp);
 
-       if(!myself->connection->rsa_key) {
-               logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"),
-                          fname, strerror(errno));
-               free(fname);
-               return false;
+       if(!result) 
+               logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"), fname, strerror(errno));
+       free(fname);
+       return result;
+}
+
+static struct event keyexpire_event;
+
+static void keyexpire_handler(int fd, short events, void *data) {
+       regenerate_key();
+}
+
+void regenerate_key() {
+       if(timeout_initialized(&keyexpire_event)) {
+               ifdebug(STATUS) logger(LOG_INFO, _("Expiring symmetric keys"));
+               event_del(&keyexpire_event);
+               send_key_changed(broadcast, myself);
+       } else {
+               timeout_set(&keyexpire_event, keyexpire_handler, NULL);
        }
 
-       free(fname);
-       return true;
+       event_add(&keyexpire_event, &(struct timeval){keylifetime, 0});
 }
 
 /*
   Configure node_t myself and set up the local sockets (listen only)
 */
-bool setup_myself(void)
-{
+bool setup_myself(void) {
        config_t *cfg;
        subnet_t *subnet;
        char *name, *hostname, *mode, *afname, *cipher, *digest;
@@ -349,65 +299,36 @@ bool setup_myself(void)
 
        /* Generate packet encryption key */
 
-       if(get_config_string
-          (lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
-               if(!strcasecmp(cipher, "none")) {
-                       myself->incipher = NULL;
-               } else {
-                       myself->incipher = EVP_get_cipherbyname(cipher);
-
-                       if(!myself->incipher) {
-                               logger(LOG_ERR, _("Unrecognized cipher type!"));
-                               return false;
-                       }
-               }
-       } else
-               myself->incipher = EVP_aes_256_cbc();
+       if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
+               cipher = xstrdup("aes256");
 
-       if(myself->incipher)
-               myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
-       else
-               myself->inkeylength = 1;
-
-       myself->connection->outcipher = EVP_aes_256_ofb();
+       if(!cipher_open_by_name(&myself->incipher, cipher)) {
+               logger(LOG_ERR, _("Unrecognized cipher type!"));
+               return false;
+       }
 
        if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
                keylifetime = 3600;
 
-       keyexpires = now + keylifetime;
-       
+       regenerate_key();
+
        /* Check if we want to use message authentication codes... */
 
-       if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
-               if(!strcasecmp(digest, "none")) {
-                       myself->indigest = NULL;
-               } else {
-                       myself->indigest = EVP_get_digestbyname(digest);
+       if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
+               digest = xstrdup("sha256");
 
-                       if(!myself->indigest) {
-                               logger(LOG_ERR, _("Unrecognized digest type!"));
-                               return false;
-                       }
-               }
-       } else
-               myself->indigest = EVP_sha256();
-
-       myself->connection->outdigest = EVP_sha256();
-
-       if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength)) {
-               if(myself->indigest) {
-                       if(myself->inmaclength > myself->indigest->md_size) {
-                               logger(LOG_ERR, _("MAC length exceeds size of digest!"));
-                               return false;
-                       } else if(myself->inmaclength < 0) {
-                               logger(LOG_ERR, _("Bogus MAC length!"));
-                               return false;
-                       }
-               }
-       } else
-               myself->inmaclength = 4;
+       int maclength = 4;
+       get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength);
 
-       myself->connection->outmaclength = 0;
+       if(maclength < 0) {
+               logger(LOG_ERR, _("Bogus MAC length!"));
+               return false;
+       }
+
+       if(!digest_open_by_name(&myself->indigest, digest, maclength)) {
+               logger(LOG_ERR, _("Unrecognized digest type!"));
+               return false;
+       }
 
        /* Compression */
 
@@ -435,6 +356,14 @@ bool setup_myself(void)
        if(!setup_device())
                return false;
 
+       event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
+
+       if (event_add(&device_ev, NULL) < 0) {
+               logger(LOG_ERR, _("event_add failed: %s"), strerror(errno));
+               close_device();
+               return false;
+       }
+
        /* Run tinc-up script to further initialize the tap interface */
        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
@@ -480,8 +409,28 @@ bool setup_myself(void)
                listen_socket[listen_sockets].udp =
                        setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
 
-               if(listen_socket[listen_sockets].udp < 0)
+               if(listen_socket[listen_sockets].udp < 0) {
+                       close(listen_socket[listen_sockets].tcp);
                        continue;
+               }
+
+               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_EMERG, _("event_add failed: %s"), strerror(errno));
+                       abort();
+               }
+
+               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_EMERG, _("event_add failed: %s"), strerror(errno));
+                       abort();
+               }
 
                ifdebug(CONNECTIONS) {
                        hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
@@ -491,6 +440,11 @@ bool setup_myself(void)
 
                memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
                listen_sockets++;
+
+               if(listen_sockets >= MAXSOCKETS) {
+                       logger(LOG_WARNING, _("Maximum of %d listening sockets reached"), MAXSOCKETS);
+                       break;
+               }
        }
 
        freeaddrinfo(ai);
@@ -512,9 +466,6 @@ bool setup_network(void)
 {
        cp();
 
-       now = time(NULL);
-
-       init_events();
        init_connections();
        init_subnets();
        init_nodes();
@@ -545,9 +496,8 @@ bool setup_network(void)
 /*
   close all open network connections
 */
-void close_network_connections(void)
-{
-       avl_node_t *node, *next;
+void close_network_connections(void) {
+       splay_node_t *node, *next;
        connection_t *c;
        char *envp[5];
        int i;
@@ -570,6 +520,8 @@ void close_network_connections(void)
        }
 
        for(i = 0; i < listen_sockets; i++) {
+               event_del(&listen_socket[i].ev_tcp);
+               event_del(&listen_socket[i].ev_udp);
                close(listen_socket[i].tcp);
                close(listen_socket[i].udp);
        }
@@ -585,7 +537,6 @@ void close_network_connections(void)
        exit_subnets();
        exit_nodes();
        exit_connections();
-       exit_events();
 
        execute_script("tinc-down", envp);
 
index 8df9f38075356632ab778336e9966689bbfa027f..47a41684a7f93008871b88a6cd43616326137756 100644 (file)
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "conf.h"
 #include "connection.h"
-#include "event.h"
 #include "logger.h"
 #include "meta.h"
 #include "net.h"
@@ -55,8 +54,7 @@ list_t *outgoing_list = NULL;
 
 /* Setup sockets */
 
-static void configure_tcp(connection_t *c)
-{
+static void configure_tcp(connection_t *c) {
        int option;
 
 #ifdef O_NONBLOCK
@@ -75,12 +73,12 @@ static void configure_tcp(connection_t *c)
 
 #if defined(SOL_TCP) && defined(TCP_NODELAY)
        option = 1;
-       setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
+       setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof option);
 #endif
 
 #if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
        option = IPTOS_LOWDELAY;
-       setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
+       setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof option);
 #endif
 }
 
@@ -190,7 +188,7 @@ int setup_listen_socket(const sockaddr_t *sa)
        /* Optimize TCP settings */
 
        option = 1;
-       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
+       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
 
 #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
@@ -202,10 +200,10 @@ int setup_listen_socket(const sockaddr_t *sa)
 #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
                struct ifreq ifr;
 
-               memset(&ifr, 0, sizeof(ifr));
+               memset(&ifr, 0, sizeof ifr);
                strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
 
-               if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
+               if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) {
                        closesocket(nfd);
                        logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
                                   strerror(errno));
@@ -235,8 +233,7 @@ int setup_listen_socket(const sockaddr_t *sa)
        return nfd;
 }
 
-int setup_vpn_in_socket(const sockaddr_t *sa)
-{
+int setup_vpn_in_socket(const sockaddr_t *sa) {
        int nfd;
        char *addrstr;
        int option;
@@ -274,7 +271,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
 #endif
 
        option = 1;
-       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
+       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
 
 #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
@@ -312,10 +309,11 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
        return nfd;
 } /* int setup_vpn_in_socket */
 
-void retry_outgoing(outgoing_t *outgoing)
-{
-       event_t *event;
+static void retry_outgoing_handler(int fd, short events, void *data) {
+       setup_outgoing_connection(data);
+}
 
+void retry_outgoing(outgoing_t *outgoing) {
        cp();
 
        outgoing->timeout += 5;
@@ -323,32 +321,28 @@ void retry_outgoing(outgoing_t *outgoing)
        if(outgoing->timeout > maxtimeout)
                outgoing->timeout = maxtimeout;
 
-       event = new_event();
-       event->handler = (event_handler_t) setup_outgoing_connection;
-       event->time = now + outgoing->timeout;
-       event->data = outgoing;
-       event_add(event);
+       timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
+       event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0});
 
        ifdebug(CONNECTIONS) logger(LOG_NOTICE,
                           _("Trying to re-establish outgoing connection in %d seconds"),
                           outgoing->timeout);
 }
 
-void finish_connecting(connection_t *c)
-{
+void finish_connecting(connection_t *c) {
        cp();
 
        ifdebug(CONNECTIONS) logger(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
 
        configure_tcp(c);
 
-       c->last_ping_time = now;
+       c->last_ping_time = time(NULL);
+       c->status.connecting = false;
 
        send_id(c);
 }
 
-void do_outgoing_connection(connection_t *c)
-{
+void do_outgoing_connection(connection_t *c) {
        char *address, *port;
        int result;
 
@@ -359,8 +353,9 @@ begin:
                if(!c->outgoing->cfg) {
                        ifdebug(CONNECTIONS) logger(LOG_ERR, _("Could not set up a meta connection to %s"),
                                           c->name);
-                       c->status.remove = true;
                        retry_outgoing(c->outgoing);
+                       c->outgoing = NULL;
+                       connection_del(c);
                        return;
                }
 
@@ -443,8 +438,22 @@ begin:
        return;
 }
 
-void setup_outgoing_connection(outgoing_t *outgoing)
-{
+void handle_meta_read(struct bufferevent *event, void *data) {
+       logger(LOG_EMERG, _("handle_meta_read() called"));
+       abort();
+}
+
+void handle_meta_write(struct bufferevent *event, void *data) {
+       ifdebug(META) logger(LOG_DEBUG, _("handle_meta_write() called"));
+}
+
+void handle_meta_connection_error(struct bufferevent *event, short what, void *data) {
+       connection_t *c = data;
+       logger(LOG_EMERG, _("handle_meta_connection_error() called: %d: %s"), what, strerror(errno));
+       terminate_connection(c, c->status.active);
+}
+
+void setup_outgoing_connection(outgoing_t *outgoing) {
        connection_t *c;
        node_t *n;
 
@@ -479,32 +488,39 @@ void setup_outgoing_connection(outgoing_t *outgoing)
        }
 
        c->outgoing = outgoing;
-       c->last_ping_time = now;
+       c->last_ping_time = time(NULL);
 
        connection_add(c);
 
        do_outgoing_connection(c);
+
+       event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
+       event_add(&c->inevent, NULL);
+       c->buffer = bufferevent_new(c->socket, handle_meta_read, handle_meta_write, handle_meta_connection_error, c);
+       if(!c->buffer) {
+               logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno));
+               abort();
+       }
+       bufferevent_disable(c->buffer, EV_READ);
 }
 
 /*
   accept a new tcp connect and create a
   new connection
 */
-bool handle_new_meta_connection(int sock)
-{
+void handle_new_meta_connection(int sock, short events, void *data) {
        connection_t *c;
        sockaddr_t sa;
        int fd;
-       socklen_t len = sizeof(sa);
+       socklen_t len = sizeof sa;
 
        cp();
 
        fd = accept(sock, &sa.sa, &len);
 
        if(fd < 0) {
-               logger(LOG_ERR, _("Accepting a new connection failed: %s"),
-                          strerror(errno));
-               return false;
+               logger(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno));
+               return;
        }
 
        sockaddrunmap(&sa);
@@ -519,18 +535,25 @@ bool handle_new_meta_connection(int sock)
        c->address = sa;
        c->hostname = sockaddr2hostname(&sa);
        c->socket = fd;
-       c->last_ping_time = now;
+       c->last_ping_time = time(NULL);
 
        ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname);
 
+       event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
+       event_add(&c->inevent, NULL);
+       c->buffer = bufferevent_new(c->socket, NULL, handle_meta_write, handle_meta_connection_error, c);
+       if(!c->buffer) {
+               logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno));
+               abort();
+       }
+       bufferevent_disable(c->buffer, EV_READ);
+               
        configure_tcp(c);
 
        connection_add(c);
 
        c->allow_request = ID;
        send_id(c);
-
-       return true;
 }
 
 void free_outgoing(outgoing_t *outgoing) {
@@ -549,7 +572,7 @@ void try_outgoing_connections(void)
        char *name;
        outgoing_t *outgoing;
        connection_t *c;
-       avl_node_t *node;
+       splay_node_t *node;
        
        cp();
 
@@ -575,7 +598,7 @@ void try_outgoing_connections(void)
                        continue;
                }
 
-               outgoing = xmalloc_and_zero(sizeof(*outgoing));
+               outgoing = xmalloc_and_zero(sizeof *outgoing);
                outgoing->name = name;
                list_insert_tail(outgoing_list, outgoing);
                setup_outgoing_connection(outgoing);
index 909441e1320101340bf3af7a2b2d209dd1d09ea6..480b716b5073dd23e84404cbfd5be385d08f9ba7 100644 (file)
@@ -34,8 +34,7 @@ bool hostnames = false;
   Turn a string into a struct addrinfo.
   Return NULL on failure.
 */
-struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype)
-{
+struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) {
        struct addrinfo *ai, hint = {0};
        int err;
 
@@ -55,8 +54,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
        return ai;
 }
 
-sockaddr_t str2sockaddr(const char *address, const char *port)
-{
+sockaddr_t str2sockaddr(const char *address, const char *port) {
        struct addrinfo *ai, hint = {0};
        sockaddr_t result;
        int err;
@@ -84,8 +82,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port)
        return result;
 }
 
-void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
-{
+void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
        char address[NI_MAXHOST];
        char port[NI_MAXSERV];
        char *scopeid;
@@ -99,7 +96,7 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
                return;
        }
 
-       err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+       err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
 
        if(err) {
                logger(LOG_ERR, _("Error while translating addresses: %s"),
@@ -118,8 +115,7 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
        *portstr = xstrdup(port);
 }
 
-char *sockaddr2hostname(const sockaddr_t *sa)
-{
+char *sockaddr2hostname(const sockaddr_t *sa) {
        char *str;
        char address[NI_MAXHOST] = "unknown";
        char port[NI_MAXSERV] = "unknown";
@@ -132,7 +128,7 @@ char *sockaddr2hostname(const sockaddr_t *sa)
                return str;
        }
 
-       err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
+       err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
                                        hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
        if(err) {
                logger(LOG_ERR, _("Error while looking up hostname: %s"),
@@ -201,20 +197,20 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
                        return strcmp(a->unknown.port, b->unknown.port);
 
                case AF_INET:
-                       result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
+                       result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof a->in.sin_addr);
 
                        if(result)
                                return result;
 
-                       return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
+                       return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof a->in.sin_port);
 
                case AF_INET6:
-                       result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
+                       result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof a->in6.sin6_addr);
 
                        if(result)
                                return result;
 
-                       return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
+                       return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
 
                default:
                        logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
@@ -246,8 +242,7 @@ void sockaddrfree(sockaddr_t *a) {
        }
 }
        
-void sockaddrunmap(sockaddr_t *sa)
-{
+void sockaddrunmap(sockaddr_t *sa) {
        cp();
 
        if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
@@ -258,8 +253,7 @@ void sockaddrunmap(sockaddr_t *sa)
 
 /* Subnet mask handling */
 
-int maskcmp(const void *va, const void *vb, int masklen)
-{
+int maskcmp(const void *va, const void *vb, int masklen) {
        int i, m, result;
        const char *a = va;
        const char *b = vb;
@@ -279,8 +273,7 @@ int maskcmp(const void *va, const void *vb, int masklen)
        return 0;
 }
 
-void mask(void *va, int masklen, int len)
-{
+void mask(void *va, int masklen, int len) {
        int i;
        char *a = va;
 
@@ -296,8 +289,7 @@ void mask(void *va, int masklen, int len)
                a[i] = 0;
 }
 
-void maskcpy(void *va, const void *vb, int masklen, int len)
-{
+void maskcpy(void *va, const void *vb, int masklen, int len) {
        int i, m;
        char *a = va;
        const char *b = vb;
@@ -316,8 +308,7 @@ void maskcpy(void *va, const void *vb, int masklen, int len)
                a[i] = 0;
 }
 
-bool maskcheck(const void *va, int masklen, int len)
-{
+bool maskcheck(const void *va, int masklen, int len) {
        int i;
        const char *a = va;
 
index 4fbec08fabcb8e1a18e8588f089661b3832f5a01..ebd2c7c2c9421d56c1225c89c95f7d593189c278 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "logger.h"
 #include "net.h"
 #include "netutl.h"
 #include "utils.h"
 #include "xalloc.h"
 
-avl_tree_t *node_tree;                 /* Known nodes, sorted by name */
-avl_tree_t *node_udp_tree;             /* Known nodes, sorted by address and port */
+splay_tree_t *node_tree;                       /* Known nodes, sorted by name */
+splay_tree_t *node_udp_tree;           /* Known nodes, sorted by address and port */
 
 node_t *myself;
 
-static int node_compare(const node_t *a, const node_t *b)
-{
+static int node_compare(const node_t *a, const node_t *b) {
        return strcmp(a->name, b->name);
 }
 
-static int node_udp_compare(const node_t *a, const node_t *b)
-{
-       return sockaddrcmp(&a->address, &b->address);
+static int node_udp_compare(const node_t *a, const node_t *b) {
+       int result;
+
+       cp();
+
+       result = sockaddrcmp(&a->address, &b->address);
+
+       if(result)
+               return result;
+
+       return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
 }
 
-void init_nodes(void)
-{
+void init_nodes(void) {
        cp();
 
-       node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node);
-       node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL);
+       node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
+       node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
 }
 
-void exit_nodes(void)
-{
+void exit_nodes(void) {
        cp();
 
-       avl_delete_tree(node_udp_tree);
-       avl_delete_tree(node_tree);
+       splay_delete_tree(node_udp_tree);
+       splay_delete_tree(node_tree);
 }
 
-node_t *new_node(void)
-{
-       node_t *n = xmalloc_and_zero(sizeof(*n));
+node_t *new_node(void) {
+       node_t *n = xmalloc_and_zero(sizeof *n);
 
        cp();
 
        n->subnet_tree = new_subnet_tree();
        n->edge_tree = new_edge_tree();
-       EVP_CIPHER_CTX_init(&n->inctx);
-       EVP_CIPHER_CTX_init(&n->outctx);
        n->mtu = MTU;
        n->maxmtu = MTU;
 
        return n;
 }
 
-void free_node(node_t *n)
-{
+void free_node(node_t *n) {
        cp();
 
-       if(n->inkey)
-               free(n->inkey);
-
-       if(n->outkey)
-               free(n->outkey);
-
        if(n->subnet_tree)
                free_subnet_tree(n->subnet_tree);
 
@@ -95,11 +90,12 @@ void free_node(node_t *n)
 
        sockaddrfree(&n->address);
 
-       EVP_CIPHER_CTX_cleanup(&n->inctx);
-       EVP_CIPHER_CTX_cleanup(&n->outctx);
+       cipher_close(&n->incipher);
+       digest_close(&n->indigest);
+       cipher_close(&n->outcipher);
+       digest_close(&n->outdigest);
 
-       if(n->mtuevent)
-               event_del(n->mtuevent);
+       event_del(&n->mtuevent);
        
        if(n->hostname)
                free(n->hostname);
@@ -110,16 +106,14 @@ void free_node(node_t *n)
        free(n);
 }
 
-void node_add(node_t *n)
-{
+void node_add(node_t *n) {
        cp();
 
-       avl_insert(node_tree, n);
+       splay_insert(node_tree, n);
 }
 
-void node_del(node_t *n)
-{
-       avl_node_t *node, *next;
+void node_del(node_t *n) {
+       splay_node_t *node, *next;
        edge_t *e;
        subnet_t *s;
 
@@ -137,23 +131,21 @@ void node_del(node_t *n)
                edge_del(e);
        }
 
-       avl_delete(node_udp_tree, n);
-       avl_delete(node_tree, n);
+       splay_delete(node_udp_tree, n);
+       splay_delete(node_tree, n);
 }
 
-node_t *lookup_node(char *name)
-{
+node_t *lookup_node(char *name) {
        node_t n = {0};
 
        cp();
        
        n.name = name;
 
-       return avl_search(node_tree, &n);
+       return splay_search(node_tree, &n);
 }
 
-node_t *lookup_node_udp(const sockaddr_t *sa)
-{
+node_t *lookup_node_udp(const sockaddr_t *sa) {
        node_t n = {0};
 
        cp();
@@ -161,12 +153,12 @@ node_t *lookup_node_udp(const sockaddr_t *sa)
        n.address = *sa;
        n.name = NULL;
 
-       return avl_search(node_udp_tree, &n);
+       return splay_search(node_udp_tree, &n);
 }
 
 void update_node_udp(node_t *n, const sockaddr_t *sa)
 {
-       avl_delete(node_udp_tree, n);
+       splay_delete(node_udp_tree, n);
 
        if(n->hostname)
                free(n->hostname);
@@ -174,8 +166,8 @@ void update_node_udp(node_t *n, const sockaddr_t *sa)
        if(sa) {
                n->address = *sa;
                n->hostname = sockaddr2hostname(&n->address);
-               avl_insert(node_udp_tree, n);
-               ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
+               splay_insert(node_udp_tree, n);
+               logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
        } else {
                memset(&n->address, 0, sizeof n->address);
                n->hostname = 0;
@@ -183,23 +175,21 @@ void update_node_udp(node_t *n, const sockaddr_t *sa)
        }
 }
 
-void dump_nodes(void)
-{
-       avl_node_t *node;
+int dump_nodes(struct evbuffer *out) {
+       splay_node_t *node;
        node_t *n;
 
        cp();
 
-       logger(LOG_DEBUG, _("Nodes:"));
-
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
-               logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"),
-                          n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0,
-                          n->outdigest ? n->outdigest->type : 0, n->outmaclength, n->outcompression,
+               if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n"),
+                          n->name, n->hostname, cipher_get_nid(&n->outcipher),
+                          digest_get_nid(&n->outdigest), digest_length(&n->outdigest), n->outcompression,
                           n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
-                          n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
+                          n->via ? n->via->name : "-", n->distance, n->mtu, n->minmtu, n->maxmtu) == -1)
+                       return errno;
        }
 
-       logger(LOG_DEBUG, _("End of nodes."));
+       return 0;
 }
index 528716de865a4d5b4106792ed535849f7b085298..37ba073ee48cb741ade5480ebdb211d690414394 100644 (file)
 #ifndef __TINC_NODE_H__
 #define __TINC_NODE_H__
 
-#include "avl_tree.h"
+#include <event.h>
+
+#include "splay_tree.h"
+#include "cipher.h"
 #include "connection.h"
-#include "event.h"
+#include "digest.h"
 #include "list.h"
 #include "subnet.h"
 
@@ -48,31 +51,22 @@ typedef struct node_t {
 
        node_status_t status;
 
-       const EVP_CIPHER *incipher;             /* Cipher type for UDP packets received from him */
-       char *inkey;                            /* Cipher key and iv */
-       int inkeylength;                        /* Cipher key and iv length */
-       EVP_CIPHER_CTX inctx;                   /* Cipher context */
-       
-       const EVP_CIPHER *outcipher;            /* Cipher type for UDP packets sent to him*/
-       char *outkey;                           /* Cipher key and iv */
-       int outkeylength;                       /* Cipher key and iv length */
-       EVP_CIPHER_CTX outctx;                  /* Cipher context */
-       
-       const EVP_MD *indigest;                 /* Digest type for MAC of packets received from him */
-       int inmaclength;                        /* Length of MAC */
-
-       const EVP_MD *outdigest;                /* Digest type for MAC of packets sent to him*/
-       int outmaclength;                       /* Length of MAC */
+       cipher_t incipher;                        /* Cipher for UDP packets */
+       digest_t indigest;                        /* Digest for UDP packets */  
+
+       cipher_t outcipher;                        /* Cipher for UDP packets */
+       digest_t outdigest;                        /* Digest for UDP packets */ 
 
        int incompression;                      /* Compressionlevel, 0 = no compression */
        int outcompression;                     /* Compressionlevel, 0 = no compression */
 
+       int distance;
        struct node_t *nexthop;                 /* nearest node from us to him */
        struct node_t *via;                     /* next hop for UDP packets */
 
-       avl_tree_t *subnet_tree;                /* Pointer to a tree of subnets belonging to this node */
+       splay_tree_t *subnet_tree;              /* Pointer to a tree of subnets belonging to this node */
 
-       avl_tree_t *edge_tree;                  /* Edges with this node as one of the endpoints */
+       splay_tree_t *edge_tree;                        /* Edges with this node as one of the endpoints */
 
        struct connection_t *connection;        /* Connection associated with this node (if a direct connection exists) */
 
@@ -84,12 +78,12 @@ typedef struct node_t {
        length_t minmtu;                        /* Probed minimum MTU */
        length_t maxmtu;                        /* Probed maximum MTU */
        int mtuprobes;                          /* Number of probes */
-       event_t *mtuevent;                      /* Probe event */
+       struct event mtuevent;                  /* Probe event */
 } node_t;
 
 extern struct node_t *myself;
-extern avl_tree_t *node_tree;
-extern avl_tree_t *node_udp_tree;
+extern splay_tree_t *node_tree;
+extern splay_tree_t *node_udp_tree;
 
 extern void init_nodes(void);
 extern void exit_nodes(void);
@@ -99,7 +93,7 @@ extern void node_add(node_t *);
 extern void node_del(node_t *);
 extern node_t *lookup_node(char *);
 extern node_t *lookup_node_udp(const sockaddr_t *);
+extern int dump_nodes(struct evbuffer *);
 extern void update_node_udp(node_t *, const sockaddr_t *);
-extern void dump_nodes(void);
 
 #endif                                                 /* __TINC_NODE_H__ */
diff --git a/src/openssl/cipher.c b/src/openssl/cipher.c
new file mode 100644 (file)
index 0000000..ccd8819
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+    cipher.c -- Symmetric block cipher handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
+#include "cipher.h"
+#include "logger.h"
+#include "xalloc.h"
+
+static bool cipher_open(cipher_t *cipher) {
+       cipher->keylen = cipher->cipher->key_len;
+       cipher->blklen = cipher->cipher->iv_len;
+
+       cipher->key = xmalloc(cipher->keylen + cipher->blklen);
+
+       EVP_CIPHER_CTX_init(&cipher->ctx);
+
+       return true;
+}
+
+bool cipher_open_by_name(cipher_t *cipher, const char *name) {
+       cipher->cipher = EVP_get_cipherbyname(name);
+
+       if(cipher->cipher)
+               return cipher_open(cipher);
+
+       logger(LOG_DEBUG, _("Unknown cipher name '%s'!"), name);
+       return false;
+}
+
+bool cipher_open_by_nid(cipher_t *cipher, int nid) {
+       cipher->cipher = EVP_get_cipherbynid(nid);
+
+       if(cipher->cipher)
+               return cipher_open(cipher);
+
+       logger(LOG_DEBUG, _("Unknown cipher nid %d!"), nid);
+       return false;
+}
+
+bool cipher_open_blowfish_ofb(cipher_t *cipher) {
+       cipher->cipher = EVP_bf_ofb();
+       return cipher_open(cipher);
+}
+
+void cipher_close(cipher_t *cipher) {
+       EVP_CIPHER_CTX_cleanup(&cipher->ctx);
+
+       if(cipher->key) {
+               free(cipher->key);
+               cipher->key = NULL;
+       }
+}
+
+size_t cipher_keylength(const cipher_t *cipher) {
+       return cipher->keylen + cipher->blklen;
+}
+
+void cipher_get_key(const cipher_t *cipher, void *key) {
+       memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
+}
+
+bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
+       memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
+       bool result;
+
+       if(encrypt)
+               result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+       else
+               result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+
+       if(result)
+               return true;
+
+       logger(LOG_ERR, _("Error while setting key: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
+       memcpy(cipher->key, key + len - (size_t)cipher->keylen, cipher->keylen);
+       memcpy(cipher->key + cipher->keylen, key + len - (size_t)cipher->keylen - (size_t)cipher->blklen, cipher->blklen);
+       bool result;
+
+       if(encrypt)
+               result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+       else
+               result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+
+       if(result)
+               return true;
+
+       logger(LOG_ERR, _("Error while setting key: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
+       bool result;
+
+       RAND_pseudo_bytes((unsigned char *)cipher->key, cipher->keylen + cipher->blklen);
+
+       if(encrypt)
+               result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+       else
+               result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)cipher->key, (unsigned char *)cipher->key + cipher->keylen);
+
+       if(result)
+               return true;
+       
+       logger(LOG_ERR, _("Error while regenerating key: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
+       if(oneshot) {
+               int len = *outlen, pad;
+               if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
+                               &&EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
+                               && EVP_EncryptFinal(&cipher->ctx, outdata + len, &pad)) {
+                       *outlen = len + pad;
+                       return true;
+               }
+       } else {
+               int len = *outlen;
+               if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
+                       *outlen = len;
+                       return true;
+               }
+       }
+
+       logger(LOG_ERR, _("Error while encrypting: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
+       if(oneshot) {
+               int len = *outlen, pad;
+               if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
+                               && EVP_DecryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)
+                               && EVP_DecryptFinal(&cipher->ctx, outdata + len, &pad)) {
+                       *outlen = len + pad;
+                       return true;
+               }
+       } else {
+               int len = *outlen;
+               if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
+                       *outlen = len;
+                       return true;
+               }
+       }
+
+       logger(LOG_ERR, _("Error while encrypting: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+int cipher_get_nid(const cipher_t *cipher) {
+       return cipher->cipher ? cipher->cipher->nid : 0;
+}
+
+bool cipher_active(const cipher_t *cipher) {
+       return cipher->cipher && cipher->cipher->nid != 0;
+}
diff --git a/src/openssl/cipher.h b/src/openssl/cipher.h
new file mode 100644 (file)
index 0000000..20535ed
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+    cipher.h -- header file cipher.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CIPHER_H__
+#define __TINC_CIPHER_H__
+
+#include <openssl/evp.h>
+
+#define CIPHER_MAX_BLOCK_SIZE EVP_MAX_BLOCK_LENGTH
+#define CIPHER_MAX_KEY_SIZE EVP_MAX_KEY_LENGTH
+#define CIPHER_MAX_IV_SIZE EVP_MAX_IV_LENGTH
+
+typedef struct cipher {
+       EVP_CIPHER_CTX ctx;
+       const EVP_CIPHER *cipher;
+       char *key;
+       uint16_t keylen;
+       uint16_t blklen;
+} cipher_t;
+
+extern bool cipher_open_by_name(cipher_t *, const char *);
+extern bool cipher_open_by_nid(cipher_t *, int);
+extern bool cipher_open_blowfish_ofb(cipher_t *);
+extern void cipher_close(cipher_t *);
+extern size_t cipher_keylength(const cipher_t *);
+extern void cipher_get_key(const cipher_t *, void *);
+extern bool cipher_set_key(cipher_t *, void *, bool);
+extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool);
+extern bool cipher_regenerate_key(cipher_t *, bool);
+extern bool cipher_encrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
+extern bool cipher_decrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
+extern int cipher_get_nid(const cipher_t *);
+extern bool cipher_active(const cipher_t *);
+
+#endif
diff --git a/src/openssl/crypto.c b/src/openssl/crypto.c
new file mode 100644 (file)
index 0000000..7e6e9f6
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    crypto.c -- Cryptographic miscellaneous functions and initialisation
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+
+#include "crypto.h"
+
+void crypto_init() {
+        RAND_load_file("/dev/urandom", 1024);
+
+        ENGINE_load_builtin_engines();
+        ENGINE_register_all_complete();
+
+        OpenSSL_add_all_algorithms();
+}
+
+void crypto_exit() {
+       EVP_cleanup();
+}
+
+void randomize(void *out, size_t outlen) {
+       RAND_pseudo_bytes(out, outlen);
+}
diff --git a/src/openssl/crypto.h b/src/openssl/crypto.h
new file mode 100644 (file)
index 0000000..3999251
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+    crypto.h -- header for crypto.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_CRYPTO_H__
+#define __TINC_CRYPTO_H__
+
+extern void crypto_init();
+extern void crypto_exit();
+extern void randomize(void *, size_t);
+
+#endif
diff --git a/src/openssl/digest.c b/src/openssl/digest.c
new file mode 100644 (file)
index 0000000..e1db934
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+    digest.c -- Digest handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <openssl/err.h>
+
+#include "digest.h"
+#include "logger.h"
+
+static void set_maclength(digest_t *digest, int maclength) {
+       int digestlen = EVP_MD_size(digest->digest);
+
+       if(maclength > digestlen || maclength < 0)
+               digest->maclength = digestlen;
+       else
+               digest->maclength = maclength;
+}
+
+bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
+       digest->digest = EVP_get_digestbyname(name);
+
+       if(!digest->digest) {
+               logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
+               return false;
+       }
+
+       set_maclength(digest, maclength);
+       return true;
+}
+
+bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
+       digest->digest = EVP_get_digestbynid(nid);
+
+       if(!digest->digest) {
+               logger(LOG_DEBUG, _("Unknown digest nid %d!"), nid);
+               return false;
+       }
+
+       set_maclength(digest, maclength);
+       return true;
+}
+
+bool digest_open_sha1(digest_t *digest, int maclength) {
+       digest->digest = EVP_sha1();
+
+       set_maclength(digest, maclength);
+       return true;
+}
+
+void digest_close(digest_t *digest) {
+}
+
+bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
+       size_t len = EVP_MD_size(digest->digest);
+       unsigned char tmpdata[len];
+
+       EVP_MD_CTX ctx;
+
+       if(!EVP_DigestInit(&ctx, digest->digest)
+                       || !EVP_DigestUpdate(&ctx, indata, inlen)
+                       || !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
+               logger(LOG_DEBUG, _("Error creating digest: %s"), ERR_error_string(ERR_get_error(), NULL));
+               return false;
+       }
+
+       memcpy(outdata, tmpdata, digest->maclength);
+       return true;
+}
+
+bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
+       size_t len = EVP_MD_size(digest->digest);
+       unsigned char outdata[len];
+
+       return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, digest->maclength);
+}
+
+int digest_get_nid(const digest_t *digest) {
+       return digest->digest ? digest->digest->type : 0;
+}
+
+size_t digest_length(const digest_t *digest) {
+       return digest->maclength;
+}
+
+bool digest_active(const digest_t *digest) {
+       return digest->digest && digest->digest->type != 0;
+}
diff --git a/src/openssl/digest.h b/src/openssl/digest.h
new file mode 100644 (file)
index 0000000..2b5a171
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+    digest.h -- header file digest.c
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_DIGEST_H__
+#define __TINC_DIGEST_H__
+
+#include <openssl/evp.h>
+
+#define DIGEST_MAX_SIZE EVP_MAX_MD_SIZE
+
+typedef struct digest {
+       const EVP_MD *digest;
+       int maclength;
+} digest_t;
+
+extern bool digest_open_by_name(struct digest *, const char *name, int maclength);
+extern bool digest_open_by_nid(struct digest *, int nid, int maclength);
+extern bool digest_open_sha1(struct digest *, int maclength);
+extern void digest_close(struct digest *);
+extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
+extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
+extern int digest_get_nid(const struct digest *);
+extern size_t digest_length(const struct digest *);
+extern bool digest_active(const struct digest *);
+
+#endif
diff --git a/src/openssl/rsa.c b/src/openssl/rsa.c
new file mode 100644 (file)
index 0000000..5e923f1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+    rsa.c -- RSA key handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+#include "logger.h"
+#include "rsa.h"
+
+// Set RSA keys
+
+bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
+       *rsa = RSA_new();
+       BN_hex2bn(&(*rsa)->n, n);
+       BN_hex2bn(&(*rsa)->e, e);
+       return true;
+}
+
+bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
+       *rsa = RSA_new();
+       BN_hex2bn(&(*rsa)->n, n);
+       BN_hex2bn(&(*rsa)->e, e);
+       BN_hex2bn(&(*rsa)->d, d);
+       return true;
+}
+
+// Read PEM RSA keys
+
+bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
+       *rsa = PEM_read_RSAPublicKey(fp, rsa, NULL, NULL);
+
+       if(*rsa)
+               return true;
+       
+       *rsa = PEM_read_RSA_PUBKEY(fp, rsa, NULL, NULL);
+
+       if(*rsa)
+               return true;
+
+       logger(LOG_ERR, _("Unable to read RSA public key: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
+       *rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+
+       if(*rsa)
+               return true;
+       
+       logger(LOG_ERR, _("Unable to read RSA private key: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;
+}
+
+size_t rsa_size(rsa_t *rsa) {
+       return RSA_size(*rsa);
+}
+
+bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+       if(RSA_public_encrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
+               return true;
+
+       logger(LOG_ERR, _("Unable to perform RSA encryption: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;   
+}
+
+bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
+       if(RSA_private_decrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
+               return true;
+
+       logger(LOG_ERR, _("Unable to perform RSA decryption: %s"), ERR_error_string(ERR_get_error(), NULL));
+       return false;   
+}
diff --git a/src/openssl/rsa.h b/src/openssl/rsa.h
new file mode 100644 (file)
index 0000000..dade1f3
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    rsa.h -- RSA key handling
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_RSA_H__
+#define __TINC_RSA_H__
+
+#include <openssl/rsa.h>
+
+typedef RSA *rsa_t;
+
+extern bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e);
+extern bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d);
+extern bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp);
+extern bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp);
+extern size_t rsa_size(rsa_t *rsa);
+extern bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t inlen, void *out);
+extern bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t inlen, void *out);
+
+#endif
diff --git a/src/openssl/rsagen.c b/src/openssl/rsagen.c
new file mode 100644 (file)
index 0000000..689e8a6
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+    rsagen.c -- RSA key generation and export
+    Copyright (C) 2008 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+#include "logger.h"
+#include "rsagen.h"
+
+/* This function prettyprints the key generation process */
+
+static void indicator(int a, int b, void *p) {
+       switch (a) {
+               case 0:
+                       fprintf(stderr, ".");
+                       break;
+
+               case 1:
+                       fprintf(stderr, "+");
+                       break;
+
+               case 2:
+                       fprintf(stderr, "-");
+                       break;
+
+               case 3:
+                       switch (b) {
+                               case 0:
+                                       fprintf(stderr, " p\n");
+                                       break;
+
+                               case 1:
+                                       fprintf(stderr, " q\n");
+                                       break;
+
+                               default:
+                                       fprintf(stderr, "?");
+                       }
+                       break;
+
+               default:
+                       fprintf(stderr, "?");
+       }
+}
+
+// Generate RSA key
+
+bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent) {
+       *rsa = RSA_generate_key(bits, exponent, indicator, NULL);
+
+       return *rsa;
+}
+
+// Write PEM RSA keys
+
+bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
+       PEM_write_RSAPublicKey(fp, *rsa);
+
+       return true;
+}
+
+bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
+       PEM_write_RSAPrivateKey(fp, *rsa, NULL, NULL, 0, NULL, NULL);
+       return true;
+}
diff --git a/src/openssl/rsagen.h b/src/openssl/rsagen.h
new file mode 100644 (file)
index 0000000..e5aff63
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    rsagen.h -- RSA key generation and export
+    Copyright (C) 2008 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#ifndef __TINC_RSAGEN_H__
+#define __TINC_RSAGEN_H__
+
+#include "rsa.h"
+
+extern bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent);
+extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp);
+extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp);
+
+#endif
index 544c2242fcce5bec1c845b520ba0bbf889ea809b..546570aa59f4dc3066ff1b26cfbd99ea646fe661 100644 (file)
 
 #include "conf.h"
 #include "connection.h"
+#include "control.h"
 #include "device.h"
 #include "edge.h"
 #include "logger.h"
 #include "node.h"
-#include "pidfile.h"
 #include "process.h"
 #include "subnet.h"
 #include "utils.h"
 
 /* If zero, don't detach from the terminal. */
 bool do_detach = true;
-bool sighup = false;
 bool sigalrm = false;
 
 extern char *identname;
-extern char *pidfilename;
 extern char **g_argv;
 extern bool use_logfile;
-extern volatile bool running;
 
 sigset_t emptysigset;
 
-static int saved_debug_level = -1;
-
-static void memory_full(int size)
-{
+static void memory_full(int size) {
        logger(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exitting."), size);
        cp_trace();
        exit(1);
@@ -168,23 +162,14 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
                        return ERROR_CALL_NOT_IMPLEMENTED;
        }
 
-       if(running) {
-               running = false;
-               status.dwWaitHint = 30000; 
-               status.dwCurrentState = SERVICE_STOP_PENDING; 
-               SetServiceStatus(statushandle, &status);
-               return NO_ERROR;
-       } else {
-               status.dwWaitHint = 0; 
-               status.dwCurrentState = SERVICE_STOPPED; 
-               SetServiceStatus(statushandle, &status);
-               exit(1);
-       }
-
+       event_loopexit(NULL);
+       status.dwWaitHint = 30000; 
+       status.dwCurrentState = SERVICE_STOP_PENDING; 
+       SetServiceStatus(statushandle, &status);
+       return NO_ERROR;
 }
 
-VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
-{
+VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
        int err = 1;
        extern int main2(int argc, char **argv);
 
@@ -238,95 +223,15 @@ bool init_service(void) {
 }
 #endif
 
-#ifndef HAVE_MINGW
-/*
-  check for an existing tinc for this net, and write pid to pidfile
-*/
-static bool write_pidfile(void)
-{
-       pid_t pid;
-
-       cp();
-
-       pid = check_pid(pidfilename);
-
-       if(pid) {
-               if(netname)
-                       fprintf(stderr, _("A tincd is already running for net `%s' with pid %ld.\n"),
-                                       netname, (long)pid);
-               else
-                       fprintf(stderr, _("A tincd is already running with pid %ld.\n"), (long)pid);
-               return false;
-       }
-
-       /* if it's locked, write-protected, or whatever */
-       if(!write_pid(pidfilename)) {
-               fprintf(stderr, _("Could write pid file %s: %s\n"), pidfilename, strerror(errno));
-               return false;
-       }
-
-       return true;
-}
-#endif
-
-/*
-  kill older tincd for this net
-*/
-bool kill_other(int signal)
-{
-#ifndef HAVE_MINGW
-       pid_t pid;
-
-       cp();
-
-       pid = read_pid(pidfilename);
-
-       if(!pid) {
-               if(netname)
-                       fprintf(stderr, _("No other tincd is running for net `%s'.\n"),
-                                       netname);
-               else
-                       fprintf(stderr, _("No other tincd is running.\n"));
-               return false;
-       }
-
-       errno = 0;                                      /* No error, sometimes errno is only changed on error */
-
-       /* ESRCH is returned when no process with that pid is found */
-       if(kill(pid, signal) && errno == ESRCH) {
-               if(netname)
-                       fprintf(stderr, _("The tincd for net `%s' is no longer running. "),
-                                       netname);
-               else
-                       fprintf(stderr, _("The tincd is no longer running. "));
-
-               fprintf(stderr, _("Removing stale lock file.\n"));
-               remove_pid(pidfilename);
-       }
-
-       return true;
-#else
-       return remove_service();
-#endif
-}
-
 /*
-  Detach from current terminal, write pidfile, kill parent
+  Detach from current terminal
 */
-bool detach(void)
-{
+bool detach(void) {
        cp();
 
        setup_signals();
 
-       /* First check if we can open a fresh new pidfile */
-
 #ifndef HAVE_MINGW
-       if(!write_pidfile())
-               return false;
-
-       /* If we succeeded in doing that, detach */
-
        closelogger();
 #endif
 
@@ -337,13 +242,6 @@ bool detach(void)
                                        strerror(errno));
                        return false;
                }
-
-               /* Now UPDATE the pid in the pidfile, because we changed it... */
-
-               if(!write_pid(pidfilename)) {
-                       fprintf(stderr, _("Could not write pid file %s: %s\n"), pidfilename, strerror(errno));
-                       return false;
-               }
 #else
                if(!statushandle)
                        exit(install_service());
@@ -360,8 +258,7 @@ bool detach(void)
        return true;
 }
 
-bool execute_script(const char *name, char **envp)
-{
+bool execute_script(const char *name, char **envp) {
 #ifdef HAVE_SYSTEM
        int status, len;
        char *scriptname, *p;
@@ -445,34 +342,14 @@ bool execute_script(const char *name, char **envp)
 */
 
 #ifndef HAVE_MINGW
-static RETSIGTYPE sigterm_handler(int a)
-{
-       logger(LOG_NOTICE, _("Got %s signal"), "TERM");
-       if(running)
-               running = false;
-       else
-               exit(1);
-}
-
-static RETSIGTYPE sigquit_handler(int a)
-{
-       logger(LOG_NOTICE, _("Got %s signal"), "QUIT");
-       if(running)
-               running = false;
-       else
-               exit(1);
-}
-
-static RETSIGTYPE fatal_signal_square(int a)
-{
+static RETSIGTYPE fatal_signal_square(int a) {
        logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a,
                   strsignal(a));
        cp_trace();
        exit(1);
 }
 
-static RETSIGTYPE fatal_signal_handler(int a)
-{
+static RETSIGTYPE fatal_signal_handler(int a) {
        struct sigaction act;
        logger(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
        cp_trace();
@@ -487,7 +364,7 @@ static RETSIGTYPE fatal_signal_handler(int a)
 
                close_network_connections();
                sleep(5);
-               remove_pid(pidfilename);
+               exit_control();
                execvp(g_argv[0], g_argv);
        } else {
                logger(LOG_NOTICE, _("Not restarting."));
@@ -495,62 +372,12 @@ static RETSIGTYPE fatal_signal_handler(int a)
        }
 }
 
-static RETSIGTYPE sighup_handler(int a)
-{
-       logger(LOG_NOTICE, _("Got %s signal"), "HUP");
-       sighup = true;
-}
-
-static RETSIGTYPE sigint_handler(int a)
-{
-       logger(LOG_NOTICE, _("Got %s signal"), "INT");
-
-       if(saved_debug_level != -1) {
-               logger(LOG_NOTICE, _("Reverting to old debug level (%d)"),
-                       saved_debug_level);
-               debug_level = saved_debug_level;
-               saved_debug_level = -1;
-       } else {
-               logger(LOG_NOTICE,
-                       _("Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d."),
-                       debug_level);
-               saved_debug_level = debug_level;
-               debug_level = 5;
-       }
-}
-
-static RETSIGTYPE sigalrm_handler(int a)
-{
-       logger(LOG_NOTICE, _("Got %s signal"), "ALRM");
-       sigalrm = true;
-}
-
-static RETSIGTYPE sigusr1_handler(int a)
-{
-       dump_connections();
-}
-
-static RETSIGTYPE sigusr2_handler(int a)
-{
-       dump_device_stats();
-       dump_nodes();
-       dump_edges();
-       dump_subnets();
-}
-
-static RETSIGTYPE sigwinch_handler(int a)
-{
-       do_purge = true;
-}
-
-static RETSIGTYPE unexpected_signal_handler(int a)
-{
+static RETSIGTYPE unexpected_signal_handler(int a) {
        logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
        cp_trace();
 }
 
-static RETSIGTYPE ignore_signal_handler(int a)
-{
+static RETSIGTYPE ignore_signal_handler(int a) {
        ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
 }
 
@@ -558,25 +385,16 @@ static struct {
        int signal;
        void (*handler)(int);
 } sighandlers[] = {
-       {SIGHUP, sighup_handler},
-       {SIGTERM, sigterm_handler},
-       {SIGQUIT, sigquit_handler},
        {SIGSEGV, fatal_signal_handler},
        {SIGBUS, fatal_signal_handler},
        {SIGILL, fatal_signal_handler},
        {SIGPIPE, ignore_signal_handler},
-       {SIGINT, sigint_handler},
-       {SIGUSR1, sigusr1_handler},
-       {SIGUSR2, sigusr2_handler},
        {SIGCHLD, ignore_signal_handler},
-       {SIGALRM, sigalrm_handler},
-       {SIGWINCH, sigwinch_handler},
        {0, NULL}
 };
 #endif
 
-void setup_signals(void)
-{
+void setup_signals(void) {
 #ifndef HAVE_MINGW
        int i;
        struct sigaction act;
@@ -598,7 +416,7 @@ void setup_signals(void)
 
        /* If we didn't detach, allow coredumps */
        if(!do_detach)
-               sighandlers[3].handler = SIG_DFL;
+               sighandlers[0].handler = SIG_DFL;
 
        /* Then, for each known signal that we want to catch, assign a
           handler to the signal, with error checking this time. */
index 5f2579f6b4f025345526251a0b8741f6c12646ed..9061b459ebd5d91b3c24f20ab644554d1200cf75 100644 (file)
@@ -24,7 +24,6 @@
 #define __TINC_PROCESS_H__
 
 extern bool do_detach;
-extern bool sighup;
 extern bool sigalrm;
 
 extern void setup_signals(void);
index 85133954b89ad642675c480c4e9756a21d5c6640..50f6fe73050b269e712554f1e78a1f24929ab386 100644 (file)
@@ -34,7 +34,7 @@ bool tunnelserver = false;
 
 /* Jumptable for the request handlers */
 
-static bool (*request_handlers[])(connection_t *) = {
+static bool (*request_handlers[])(connection_t *, char *) = {
                id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
                status_h, error_h, termreq_h,
                ping_h, pong_h,
@@ -53,10 +53,9 @@ static char (*request_name[]) = {
                "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET",
 };
 
-static avl_tree_t *past_request_tree;
+static splay_tree_t *past_request_tree;
 
-bool check_id(const char *id)
-{
+bool check_id(const char *id) {
        for(; *id; id++)
                if(!isalnum(*id) && *id != '_')
                        return false;
@@ -67,11 +66,10 @@ bool check_id(const char *id)
 /* Generic request routines - takes care of logging and error
    detection as well */
 
-bool send_request(connection_t *c, const char *format, ...)
-{
+bool send_request(connection_t *c, const char *format, ...) {
        va_list args;
-       char buffer[MAXBUFSIZE];
-       int len, request;
+       char request[MAXBUFSIZE];
+       int len;
 
        cp();
 
@@ -80,7 +78,7 @@ bool send_request(connection_t *c, const char *format, ...)
           input buffer anyway */
 
        va_start(args, format);
-       len = vsnprintf(buffer, MAXBUFSIZE, format, args);
+       len = vsnprintf(request, MAXBUFSIZE, format, args);
        va_end(args);
 
        if(len < 0 || len > MAXBUFSIZE - 1) {
@@ -90,57 +88,50 @@ bool send_request(connection_t *c, const char *format, ...)
        }
 
        ifdebug(PROTOCOL) {
-               sscanf(buffer, "%d", &request);
                ifdebug(META)
                        logger(LOG_DEBUG, _("Sending %s to %s (%s): %s"),
-                                  request_name[request], c->name, c->hostname, buffer);
+                                  request_name[atoi(request)], c->name, c->hostname, request);
                else
-                       logger(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request],
+                       logger(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[atoi(request)],
                                   c->name, c->hostname);
        }
 
-       buffer[len++] = '\n';
+       request[len++] = '\n';
 
        if(c == broadcast) {
-               broadcast_meta(NULL, buffer, len);
+               broadcast_meta(NULL, request, len);
                return true;
        } else
-               return send_meta(c, buffer, len);
+               return send_meta(c, request, len);
 }
 
-void forward_request(connection_t *from)
-{
-       int request;
-
+void forward_request(connection_t *from, char *request) {
        cp();
 
        ifdebug(PROTOCOL) {
-               sscanf(from->buffer, "%d", &request);
                ifdebug(META)
                        logger(LOG_DEBUG, _("Forwarding %s from %s (%s): %s"),
-                                  request_name[request], from->name, from->hostname,
-                                  from->buffer);
+                                  request_name[atoi(request)], from->name, from->hostname, request);
                else
                        logger(LOG_DEBUG, _("Forwarding %s from %s (%s)"),
-                                  request_name[request], from->name, from->hostname);
+                                  request_name[atoi(request)], from->name, from->hostname);
        }
 
-       from->buffer[from->reqlen - 1] = '\n';
-
-       broadcast_meta(from, from->buffer, from->reqlen);
+       int len = strlen(request);
+       request[len] = '\n';
+       broadcast_meta(from, request, len);
 }
 
-bool receive_request(connection_t *c)
-{
-       int request;
+bool receive_request(connection_t *c, char *request) {
+       int reqno = atoi(request);
 
        cp();
 
-       if(sscanf(c->buffer, "%d", &request) == 1) {
-               if((request < 0) || (request >= LAST) || !request_handlers[request]) {
+       if(reqno || *request == '0') {
+               if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) {
                        ifdebug(META)
                                logger(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
-                                          c->name, c->hostname, c->buffer);
+                                          c->name, c->hostname, request);
                        else
                                logger(LOG_ERR, _("Unknown request from %s (%s)"),
                                           c->name, c->hostname);
@@ -150,25 +141,24 @@ bool receive_request(connection_t *c)
                        ifdebug(PROTOCOL) {
                                ifdebug(META)
                                        logger(LOG_DEBUG, _("Got %s from %s (%s): %s"),
-                                                  request_name[request], c->name, c->hostname,
-                                                  c->buffer);
+                                                  request_name[reqno], c->name, c->hostname, request);
                                else
                                        logger(LOG_DEBUG, _("Got %s from %s (%s)"),
-                                                  request_name[request], c->name, c->hostname);
+                                                  request_name[reqno], c->name, c->hostname);
                        }
                }
 
-               if((c->allow_request != ALL) && (c->allow_request != request)) {
+               if((c->allow_request != ALL) && (c->allow_request != reqno)) {
                        logger(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name,
                                   c->hostname);
                        return false;
                }
 
-               if(!request_handlers[request](c)) {
+               if(!request_handlers[reqno](c, request)) {
                        /* Something went wrong. Probably scriptkiddies. Terminate. */
 
                        logger(LOG_ERR, _("Error while processing %s from %s (%s)"),
-                                  request_name[request], c->name, c->hostname);
+                                  request_name[reqno], c->name, c->hostname);
                        return false;
                }
        } else {
@@ -180,13 +170,11 @@ bool receive_request(connection_t *c)
        return true;
 }
 
-static int past_request_compare(const past_request_t *a, const past_request_t *b)
-{
+static int past_request_compare(const past_request_t *a, const past_request_t *b) {
        return strcmp(a->request, b->request);
 }
 
-static void free_past_request(past_request_t *r)
-{
+static void free_past_request(past_request_t *r) {
        cp();
 
        if(r->request)
@@ -195,45 +183,33 @@ static void free_past_request(past_request_t *r)
        free(r);
 }
 
-void init_requests(void)
-{
-       cp();
-
-       past_request_tree = avl_alloc_tree((avl_compare_t) past_request_compare, (avl_action_t) free_past_request);
-}
-
-void exit_requests(void)
-{
-       cp();
+static struct event past_request_event;
 
-       avl_delete_tree(past_request_tree);
-}
-
-bool seen_request(char *request)
-{
+bool seen_request(char *request) {
        past_request_t *new, p = {0};
 
        cp();
 
        p.request = request;
 
-       if(avl_search(past_request_tree, &p)) {
+       if(splay_search(past_request_tree, &p)) {
                ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Already seen request"));
                return true;
        } else {
-               new = xmalloc(sizeof(*new));
+               new = xmalloc(sizeof *new);
                new->request = xstrdup(request);
-               new->firstseen = now;
-               avl_insert(past_request_tree, new);
+               new->firstseen = time(NULL);
+               splay_insert(past_request_tree, new);
+               event_add(&past_request_event, &(struct timeval){10, 0});
                return false;
        }
 }
 
-void age_past_requests(void)
-{
-       avl_node_t *node, *next;
+void age_past_requests(int fd, short events, void *data) {
+       splay_node_t *node, *next;
        past_request_t *p;
        int left = 0, deleted = 0;
+       time_t now = time(NULL);
 
        cp();
 
@@ -242,7 +218,7 @@ void age_past_requests(void)
                p = node->data;
 
                if(p->firstseen + pinginterval < now)
-                       avl_delete_node(past_request_tree, node), deleted++;
+                       splay_delete_node(past_request_tree, node), deleted++;
                else
                        left++;
        }
@@ -250,4 +226,23 @@ void age_past_requests(void)
        if(left || deleted)
                ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Aging past requests: deleted %d, left %d"),
                           deleted, left);
+
+       if(left)
+               event_add(&past_request_event, &(struct timeval){10, 0});
+}
+
+void init_requests(void) {
+       cp();
+
+       past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request);
+
+       timeout_set(&past_request_event, age_past_requests, NULL);
+}
+
+void exit_requests(void) {
+       cp();
+
+       splay_delete_tree(past_request_tree);
+
+       event_del(&past_request_event);
 }
index ac86198eff14eaeb06db30f7032469d70ad732a8..8f53072105e80909cf8a2c70a372cd1fd9fb28b8 100644 (file)
@@ -72,14 +72,13 @@ extern bool tunnelserver;
 /* Basic functions */
 
 extern bool send_request(struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
-extern void forward_request(struct connection_t *);
-extern bool receive_request(struct connection_t *);
+extern void forward_request(struct connection_t *, char *);
+extern bool receive_request(struct connection_t *, char *);
 extern bool check_id(const char *);
 
 extern void init_requests(void);
 extern void exit_requests(void);
 extern bool seen_request(char *);
-extern void age_past_requests(void);
 
 /* Requests */
 
@@ -104,23 +103,23 @@ extern bool send_tcppacket(struct connection_t *, struct vpn_packet_t *);
 
 /* Request handlers  */
 
-extern bool id_h(struct connection_t *);
-extern bool metakey_h(struct connection_t *);
-extern bool challenge_h(struct connection_t *);
-extern bool chal_reply_h(struct connection_t *);
-extern bool ack_h(struct connection_t *);
-extern bool status_h(struct connection_t *);
-extern bool error_h(struct connection_t *);
-extern bool termreq_h(struct connection_t *);
-extern bool ping_h(struct connection_t *);
-extern bool pong_h(struct connection_t *);
-extern bool add_subnet_h(struct connection_t *);
-extern bool del_subnet_h(struct connection_t *);
-extern bool add_edge_h(struct connection_t *);
-extern bool del_edge_h(struct connection_t *);
-extern bool key_changed_h(struct connection_t *);
-extern bool req_key_h(struct connection_t *);
-extern bool ans_key_h(struct connection_t *);
-extern bool tcppacket_h(struct connection_t *);
+extern bool id_h(struct connection_t *, char *);
+extern bool metakey_h(struct connection_t *, char *);
+extern bool challenge_h(struct connection_t *, char *);
+extern bool chal_reply_h(struct connection_t *, char *);
+extern bool ack_h(struct connection_t *, char *);
+extern bool status_h(struct connection_t *, char *);
+extern bool error_h(struct connection_t *, char *);
+extern bool termreq_h(struct connection_t *, char *);
+extern bool ping_h(struct connection_t *, char *);
+extern bool pong_h(struct connection_t *, char *);
+extern bool add_subnet_h(struct connection_t *, char *);
+extern bool del_subnet_h(struct connection_t *, char *);
+extern bool add_edge_h(struct connection_t *, char *);
+extern bool del_edge_h(struct connection_t *, char *);
+extern bool key_changed_h(struct connection_t *, char *);
+extern bool req_key_h(struct connection_t *, char *);
+extern bool ans_key_h(struct connection_t *, char *);
+extern bool tcppacket_h(struct connection_t *, char *);
 
 #endif                                                 /* __TINC_PROTOCOL_H__ */
index 48166105874ec1f2fc75db608d26ce922ff02558..aa0fd36d20ab61ce373cc2952477872f41c54136 100644 (file)
 
 #include "system.h"
 
-#include <openssl/sha.h>
-#include <openssl/rand.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "conf.h"
 #include "connection.h"
+#include "crypto.h"
 #include "edge.h"
 #include "graph.h"
 #include "logger.h"
 #include "netutl.h"
 #include "node.h"
 #include "protocol.h"
+#include "rsa.h"
 #include "utils.h"
 #include "xalloc.h"
 
-bool send_id(connection_t *c)
-{
+bool send_id(connection_t *c) {
        cp();
 
+       gettimeofday(&c->start, NULL);
+
        return send_request(c, "%d %s %d", ID, myself->connection->name,
                                                myself->connection->protocol_version);
 }
 
-bool id_h(connection_t *c)
-{
+bool id_h(connection_t *c, char *request) {
        char name[MAX_STRING_SIZE];
 
        cp();
 
-       if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
+       if(sscanf(request, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name,
                           c->hostname);
                return false;
@@ -116,28 +113,23 @@ bool id_h(connection_t *c)
        return send_metakey(c);
 }
 
-bool send_metakey(connection_t *c)
-{
-       char *buffer;
-       int len;
-       bool x;
+bool send_metakey(connection_t *c) {
+       size_t len = rsa_size(&c->rsa);
+       char key[len];
+       char enckey[len];
+       char hexkey[2 * len + 1];
 
        cp();
 
-       len = RSA_size(c->rsa_key);
-
-       /* Allocate buffers for the meta key */
-
-       buffer = alloca(2 * len + 1);
+       if(!cipher_open_blowfish_ofb(&c->outcipher))
+               return false;
        
-       c->outkey = xrealloc(c->outkey, len);
+       if(!digest_open_sha1(&c->outdigest, -1))
+               return false;
 
-       if(!c->outctx)
-               c->outctx = xmalloc_and_zero(sizeof(*c->outctx));
-       cp();
-       /* Copy random data to the buffer */
+       /* Create a random key */
 
-       RAND_pseudo_bytes((unsigned char *)c->outkey, len);
+       randomize(key, len);
 
        /* The message we send must be smaller than the modulus of the RSA key.
           By definition, for a key of k bits, the following formula holds:
@@ -149,13 +141,14 @@ bool send_metakey(connection_t *c)
           This can be done by setting the most significant bit to zero.
         */
 
-       c->outkey[0] &= 0x7F;
+       key[0] &= 0x7F;
+
+       cipher_set_key_from_rsa(&c->outcipher, key, len, true);
 
        ifdebug(SCARY_THINGS) {
-               bin2hex(c->outkey, buffer, len);
-               buffer[len * 2] = '\0';
-               logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"),
-                          buffer);
+               bin2hex(key, hexkey, len);
+               hexkey[len * 2] = '\0';
+               logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), hexkey);
        }
 
        /* Encrypt the random data
@@ -165,161 +158,96 @@ bool send_metakey(connection_t *c)
           with a length equal to that of the modulus of the RSA key.
         */
 
-       if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
-               logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
-                          c->name, c->hostname);
+       if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) {
+               logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
                return false;
        }
 
        /* Convert the encrypted random data to a hexadecimal formatted string */
 
-       bin2hex(buffer, buffer, len);
-       buffer[len * 2] = '\0';
+       bin2hex(enckey, hexkey, len);
+       hexkey[len * 2] = '\0';
 
        /* Send the meta key */
 
-       x = send_request(c, "%d %d %d %d %d %s", METAKEY,
-                                        c->outcipher ? c->outcipher->nid : 0,
-                                        c->outdigest ? c->outdigest->type : 0, c->outmaclength,
-                                        c->outcompression, buffer);
-
-       /* Further outgoing requests are encrypted with the key we just generated */
-
-       if(c->outcipher) {
-               if(!EVP_EncryptInit(c->outctx, c->outcipher,
-                                       (unsigned char *)c->outkey + len - c->outcipher->key_len,
-                                       (unsigned char *)c->outkey + len - c->outcipher->key_len -
-                                       c->outcipher->iv_len)) {
-                       logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
-                                       c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
-                       return false;
-               }
-
-               c->status.encryptout = true;
-       }
-
-       return x;
+       bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
+                        cipher_get_nid(&c->outcipher),
+                        digest_get_nid(&c->outdigest), c->outmaclength,
+                        c->outcompression, hexkey);
+       
+       c->status.encryptout = true;
+       return result;
 }
 
-bool metakey_h(connection_t *c)
-{
-       char buffer[MAX_STRING_SIZE];
+bool metakey_h(connection_t *c, char *request) {
+       char hexkey[MAX_STRING_SIZE];
        int cipher, digest, maclength, compression;
-       int len;
+       size_t len = rsa_size(&myself->connection->rsa);
+       char enckey[len];
+       char key[len];
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name,
-                          c->hostname);
+       if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) {
+               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname);
                return false;
        }
 
-       len = RSA_size(myself->connection->rsa_key);
-
        /* Check if the length of the meta key is all right */
 
-       if(strlen(buffer) != len * 2) {
+       if(strlen(hexkey) != len * 2) {
                logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
                return false;
        }
 
-       /* Allocate buffers for the meta key */
-
-       c->inkey = xrealloc(c->inkey, len);
-
-       if(!c->inctx)
-               c->inctx = xmalloc_and_zero(sizeof(*c->inctx));
-
        /* Convert the challenge from hexadecimal back to binary */
 
-       hex2bin(buffer, buffer, len);
+       hex2bin(hexkey, enckey, len);
 
        /* Decrypt the meta key */
 
-       if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) {  /* See challenge() */
-               logger(LOG_ERR, _("Error during decryption of meta key for %s (%s)"),
-                          c->name, c->hostname);
+       if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) {
+               logger(LOG_ERR, _("Error during decryption of meta key for %s (%s)"), c->name, c->hostname);
                return false;
        }
 
        ifdebug(SCARY_THINGS) {
-               bin2hex(c->inkey, buffer, len);
-               buffer[len * 2] = '\0';
-               logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
+               bin2hex(key, hexkey, len);
+               hexkey[len * 2] = '\0';
+               logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), hexkey);
        }
 
-       /* All incoming requests will now be encrypted. */
-
        /* Check and lookup cipher and digest algorithms */
 
-       if(cipher) {
-               c->incipher = EVP_get_cipherbynid(cipher);
-               
-               if(!c->incipher) {
-                       logger(LOG_ERR, _("%s (%s) uses unknown cipher!"), c->name, c->hostname);
-                       return false;
-               }
-
-               if(!EVP_DecryptInit(c->inctx, c->incipher,
-                                       (unsigned char *)c->inkey + len - c->incipher->key_len,
-                                       (unsigned char *)c->inkey + len - c->incipher->key_len -
-                                       c->incipher->iv_len)) {
-                       logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s): %s"),
-                                       c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
-                       return false;
-               }
-
-               c->status.decryptin = true;
-       } else {
-               c->incipher = NULL;
+       if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) {
+               logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s)"), c->name, c->hostname);
+               return false;
        }
 
-       c->inmaclength = maclength;
-
-       if(digest) {
-               c->indigest = EVP_get_digestbynid(digest);
-
-               if(!c->indigest) {
-                       logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), c->name, c->hostname);
-                       return false;
-               }
-
-               if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) {
-                       logger(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname);
-                       return false;
-               }
-       } else {
-               c->indigest = NULL;
+       if(!digest_open_by_nid(&c->indigest, digest, -1)) {
+               logger(LOG_ERR, _("Error during initialisation of digest from %s (%s)"), c->name, c->hostname);
+               return false;
        }
 
-       c->incompression = compression;
+       c->status.decryptin = true;
 
        c->allow_request = CHALLENGE;
 
        return send_challenge(c);
 }
 
-bool send_challenge(connection_t *c)
-{
-       char *buffer;
-       int len;
+bool send_challenge(connection_t *c) {
+       size_t len = rsa_size(&c->rsa);
+       char buffer[len * 2 + 1];
 
        cp();
 
-       /* CHECKME: what is most reasonable value for len? */
-
-       len = RSA_size(c->rsa_key);
-
-       /* Allocate buffers for the challenge */
-
-       buffer = alloca(2 * len + 1);
-
-       c->hischallenge = xrealloc(c->hischallenge, len);
+       if(!c->hischallenge)
+               c->hischallenge = xrealloc(c->hischallenge, len);
 
        /* Copy random data to the buffer */
 
-       RAND_pseudo_bytes((unsigned char *)c->hischallenge, len);
+       randomize(c->hischallenge, len);
 
        /* Convert to hex */
 
@@ -331,80 +259,54 @@ bool send_challenge(connection_t *c)
        return send_request(c, "%d %s", CHALLENGE, buffer);
 }
 
-bool challenge_h(connection_t *c)
-{
+bool challenge_h(connection_t *c, char *request) {
        char buffer[MAX_STRING_SIZE];
-       int len;
+       size_t len = rsa_size(&myself->connection->rsa);
+       size_t digestlen = digest_length(&c->outdigest);
+       char digest[digestlen];
 
        cp();
 
-       if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name,
-                          c->hostname);
+       if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
+               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname);
                return false;
        }
 
-       len = RSA_size(myself->connection->rsa_key);
-
        /* Check if the length of the challenge is all right */
 
        if(strlen(buffer) != len * 2) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
-                          c->hostname, "wrong challenge length");
+               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length");
                return false;
        }
 
-       /* Allocate buffers for the challenge */
-
-       c->mychallenge = xrealloc(c->mychallenge, len);
-
        /* Convert the challenge from hexadecimal back to binary */
 
-       hex2bin(buffer, c->mychallenge, len);
+       hex2bin(buffer, buffer, len);
 
        c->allow_request = CHAL_REPLY;
 
-       /* Rest is done by send_chal_reply() */
-
-       return send_chal_reply(c);
-}
-
-bool send_chal_reply(connection_t *c)
-{
-       char hash[EVP_MAX_MD_SIZE * 2 + 1];
-       EVP_MD_CTX ctx;
-
        cp();
 
        /* Calculate the hash from the challenge we received */
 
-       if(!EVP_DigestInit(&ctx, c->indigest)
-                       || !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
-                       || !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) {
-               logger(LOG_ERR, _("Error during calculation of response for %s (%s): %s"),
-                       c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
-               return false;
-       }
+       digest_create(&c->indigest, buffer, len, digest);
 
        /* Convert the hash to a hexadecimal formatted string */
 
-       bin2hex(hash, hash, c->indigest->md_size);
-       hash[c->indigest->md_size * 2] = '\0';
+       bin2hex(digest, buffer, digestlen);
+       buffer[digestlen * 2] = '\0';
 
        /* Send the reply */
 
-       return send_request(c, "%d %s", CHAL_REPLY, hash);
+       return send_request(c, "%d %s", CHAL_REPLY, buffer);
 }
 
-bool chal_reply_h(connection_t *c)
-{
+bool chal_reply_h(connection_t *c, char *request) {
        char hishash[MAX_STRING_SIZE];
-       char myhash[EVP_MAX_MD_SIZE];
-       EVP_MD_CTX ctx;
 
        cp();
 
-       if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) {
+       if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name,
                           c->hostname);
                return false;
@@ -412,38 +314,19 @@ bool chal_reply_h(connection_t *c)
 
        /* Check if the length of the hash is all right */
 
-       if(strlen(hishash) != c->outdigest->md_size * 2) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
-                          c->hostname, _("wrong challenge reply length"));
+       if(strlen(hishash) != digest_length(&c->outdigest) * 2) {
+               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length"));
                return false;
        }
 
        /* Convert the hash to binary format */
 
-       hex2bin(hishash, hishash, c->outdigest->md_size);
+       hex2bin(hishash, hishash, digest_length(&c->outdigest));
 
-       /* Calculate the hash from the challenge we sent */
-
-       if(!EVP_DigestInit(&ctx, c->outdigest)
-                       || !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key))
-                       || !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) {
-               logger(LOG_ERR, _("Error during calculation of response from %s (%s): %s"),
-                       c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
-               return false;
-       }
-
-       /* Verify the incoming hash with the calculated hash */
-
-       if(memcmp(hishash, myhash, c->outdigest->md_size)) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
-                          c->hostname, _("wrong challenge reply"));
-
-               ifdebug(SCARY_THINGS) {
-                       bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
-                       hishash[SHA_DIGEST_LENGTH * 2] = '\0';
-                       logger(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
-               }
+       /* Verify the hash */
 
+       if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) {
+               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply"));
                return false;
        }
 
@@ -451,13 +334,14 @@ bool chal_reply_h(connection_t *c)
           Send an acknowledgement with the rest of the information needed.
         */
 
+       free(c->hischallenge);
+       c->hischallenge = NULL;
        c->allow_request = ACK;
 
        return send_ack(c);
 }
 
-bool send_ack(connection_t *c)
-{
+bool send_ack(connection_t *c) {
        /* ACK message contains rest of the information the other end needs
           to create node_t and edge_t structures. */
 
@@ -487,9 +371,8 @@ bool send_ack(connection_t *c)
        return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options);
 }
 
-static void send_everything(connection_t *c)
-{
-       avl_node_t *node, *node2;
+static void send_everything(connection_t *c) {
+       splay_node_t *node, *node2;
        node_t *n;
        subnet_t *s;
        edge_t *e;
@@ -520,8 +403,7 @@ static void send_everything(connection_t *c)
        }
 }
 
-bool ack_h(connection_t *c)
-{
+bool ack_h(connection_t *c, char *request) {
        char hisport[MAX_STRING_SIZE];
        char *hisaddress, *dummy;
        int weight, mtu;
@@ -530,7 +412,7 @@ bool ack_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
+       if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name,
                           c->hostname);
                return false;
@@ -547,8 +429,17 @@ bool ack_h(connection_t *c)
        } else {
                if(n->connection) {
                        /* Oh dear, we already have a connection to this node. */
-                       ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"),
-                                          n->name, n->hostname);
+                       ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->connection->name, n->connection->hostname);
+
+                       if(n->connection->outgoing) {
+                               if(c->outgoing)
+                                       logger(LOG_WARNING, _("Two outgoing connections to the same node!"));
+                               else
+                                       c->outgoing = n->connection->outgoing;
+
+                               n->connection->outgoing = NULL;
+                       }
+
                        terminate_connection(n->connection, false);
                        /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
                        graph();
index 4066a30db18e359438e73d1edc95f45b9690078b..92d31dbdd889cf35624ac7c28d9ad5f25da4eea0 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "conf.h"
 #include "connection.h"
 #include "edge.h"
@@ -36,8 +36,7 @@
 #include "utils.h"
 #include "xalloc.h"
 
-bool send_add_edge(connection_t *c, const edge_t *e)
-{
+bool send_add_edge(connection_t *c, const edge_t *e) {
        bool x;
        char *address, *port;
 
@@ -54,8 +53,7 @@ bool send_add_edge(connection_t *c, const edge_t *e)
        return x;
 }
 
-bool add_edge_h(connection_t *c)
-{
+bool add_edge_h(connection_t *c, char *request) {
        edge_t *e;
        node_t *from, *to;
        char from_name[MAX_STRING_SIZE];
@@ -68,7 +66,7 @@ bool add_edge_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
+       if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
                          from_name, to_name, to_address, to_port, &options, &weight) != 6) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name,
                           c->hostname);
@@ -89,7 +87,7 @@ bool add_edge_h(connection_t *c)
                return false;
        }
 
-       if(seen_request(c->buffer))
+       if(seen_request(request))
                return true;
 
        /* Lookup nodes */
@@ -165,7 +163,7 @@ bool add_edge_h(connection_t *c)
        /* Tell the rest about the new edge */
 
        if(!tunnelserver)
-               forward_request(c);
+               forward_request(c, request);
 
        /* Run MST before or after we tell the rest? */
 
@@ -174,16 +172,14 @@ bool add_edge_h(connection_t *c)
        return true;
 }
 
-bool send_del_edge(connection_t *c, const edge_t *e)
-{
+bool send_del_edge(connection_t *c, const edge_t *e) {
        cp();
 
        return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
                                                e->from->name, e->to->name);
 }
 
-bool del_edge_h(connection_t *c)
-{
+bool del_edge_h(connection_t *c, char *request) {
        edge_t *e;
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
@@ -191,7 +187,7 @@ bool del_edge_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
+       if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", c->name,
                           c->hostname);
                return false;
@@ -211,7 +207,7 @@ bool del_edge_h(connection_t *c)
                return false;
        }
 
-       if(seen_request(c->buffer))
+       if(seen_request(request))
                return true;
 
        /* Lookup nodes */
@@ -261,7 +257,7 @@ bool del_edge_h(connection_t *c)
        /* Tell the rest about the deleted edge */
 
        if(!tunnelserver)
-               forward_request(c);
+               forward_request(c, request);
 
        /* Delete the edge */
 
index 7ae98036a26036e82bd4a9f4ce5b13dbd008fa97..60e9d73691b7c6993effaf99ca317bcadf11a3a4 100644 (file)
 
 #include "system.h"
 
-#include <openssl/evp.h>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-
-#include "avl_tree.h"
+#include "splay_tree.h"
+#include "cipher.h"
 #include "connection.h"
+#include "crypto.h"
 #include "logger.h"
 #include "net.h"
 #include "netutl.h"
 #include "utils.h"
 #include "xalloc.h"
 
-bool mykeyused = false;
+static bool mykeyused = false;
 
-bool send_key_changed()
-{
+bool send_key_changed() {
        cp();
 
        /* Only send this message if some other daemon requested our key previously.
@@ -52,20 +49,19 @@ bool send_key_changed()
        return send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
 }
 
-bool key_changed_h(connection_t *c)
-{
+bool key_changed_h(connection_t *c, char *request) {
        char name[MAX_STRING_SIZE];
        node_t *n;
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) {
+       if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED",
                           c->name, c->hostname);
                return false;
        }
 
-       if(seen_request(c->buffer))
+       if(seen_request(request))
                return true;
 
        n = lookup_node(name);
@@ -82,27 +78,25 @@ bool key_changed_h(connection_t *c)
        /* Tell the others */
 
        if(!tunnelserver)
-               forward_request(c);
+               forward_request(c, request);
 
        return true;
 }
 
-bool send_req_key(node_t *to)
-{
+bool send_req_key(node_t *to) {
        cp();
 
        return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
 }
 
-bool req_key_h(connection_t *c)
-{
+bool req_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        node_t *from, *to;
 
        cp();
 
-       if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
+       if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", c->name,
                           c->hostname);
                return false;
@@ -127,6 +121,7 @@ bool req_key_h(connection_t *c)
        /* Check if this key request is for us */
 
        if(to == myself) {                      /* Yes, send our own key back */
+
                send_ans_key(from);
        } else {
                if(tunnelserver)
@@ -138,52 +133,42 @@ bool req_key_h(connection_t *c)
                        return true;
                }
 
-               send_request(to->nexthop->connection, "%s", c->buffer);
+               send_request(to->nexthop->connection, "%s", request);
        }
 
        return true;
 }
 
-bool send_ans_key(node_t *to)
-{
-       char *key;
+bool send_ans_key(node_t *to) {
+       size_t keylen = cipher_keylength(&myself->incipher);
+       char key[keylen * 2 + 1];
 
        cp();
 
-       // Set key parameters
-       to->incipher = myself->incipher;
-       to->inkeylength = myself->inkeylength;
-       to->indigest = myself->indigest;
-       to->inmaclength = myself->inmaclength;
+       cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher));
+       digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest), digest_length(&myself->indigest));
        to->incompression = myself->incompression;
 
-       // Allocate memory for key
-       to->inkey = xrealloc(to->inkey, to->inkeylength);
+       randomize(key, keylen);
+       cipher_set_key(&to->incipher, key, true);
 
-       // Create a new key
-       RAND_pseudo_bytes((unsigned char *)to->inkey, to->inkeylength);
-       if(to->incipher)
-               EVP_DecryptInit_ex(&to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + to->incipher->key_len);
+       bin2hex(key, key, keylen);
+       key[keylen * 2] = '\0';
 
        // Reset sequence number and late packet window
        mykeyused = true;
        to->received_seqno = 0;
        memset(to->late, 0, sizeof(to->late));
 
-       // Convert to hexadecimal and send
-       key = alloca(2 * to->inkeylength + 1);
-       bin2hex(to->inkey, key, to->inkeylength);
-       key[to->inkeylength * 2] = '\0';
-
        return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
-                       myself->name, to->name, key,
-                       to->incipher ? to->incipher->nid : 0,
-                       to->indigest ? to->indigest->type : 0, to->inmaclength,
-                       to->incompression);
+                                               myself->name, to->name, key,
+                                               cipher_get_nid(&to->incipher),
+                                               digest_get_nid(&to->indigest),
+                                               digest_length(&to->indigest),
+                                               to->incompression);
 }
 
-bool ans_key_h(connection_t *c)
-{
+bool ans_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        char key[MAX_STRING_SIZE];
@@ -192,7 +177,7 @@ bool ans_key_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
+       if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
                from_name, to_name, key, &cipher, &digest, &maclength,
                &compression) != 7) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", c->name,
@@ -224,59 +209,33 @@ bool ans_key_h(connection_t *c)
 
                if(!to->status.reachable) {
                        logger(LOG_WARNING, _("Got %s from %s (%s) destination %s which is not reachable"),
-                               "ANS_KEY", c->name, c->hostname, to_name);
+                                  "ANS_KEY", c->name, c->hostname, to_name);
                        return true;
                }
 
-               return send_request(to->nexthop->connection, "%s", c->buffer);
+               return send_request(to->nexthop->connection, "%s", request);
        }
 
-       /* Update our copy of the origin's packet key */
-       from->outkey = xrealloc(from->outkey, strlen(key) / 2);
-
-       from->outkey = xstrdup(key);
-       from->outkeylength = strlen(key) / 2;
-       hex2bin(key, from->outkey, from->outkeylength);
-
-       from->status.waitingforkey = false;
        /* Check and lookup cipher and digest algorithms */
 
-       if(cipher) {
-               from->outcipher = EVP_get_cipherbynid(cipher);
-
-               if(!from->outcipher) {
-                       logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
-                                  from->hostname);
-                       return false;
-               }
-
-               if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) {
-                       logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name,
-                                  from->hostname);
-                       return false;
-               }
-       } else {
-               from->outcipher = NULL;
+       if(!cipher_open_by_nid(&from->outcipher, cipher)) {
+               logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname);
+               return false;
        }
 
-       from->outmaclength = maclength;
-
-       if(digest) {
-               from->outdigest = EVP_get_digestbynid(digest);
+       if(strlen(key) / 2 != cipher_keylength(&from->outcipher)) {
+               logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname);
+               return false;
+       }
 
-               if(!from->outdigest) {
-                       logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
-                                  from->hostname);
-                       return false;
-               }
+       if(!digest_open_by_nid(&from->outdigest, digest, maclength)) {
+               logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname);
+               return false;
+       }
 
-               if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) {
-                       logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"),
-                                  from->name, from->hostname);
-                       return false;
-               }
-       } else {
-               from->outdigest = NULL;
+       if(maclength != digest_length(&from->outdigest)) {
+               logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname);
+               return false;
        }
 
        if(compression < 0 || compression > 11) {
@@ -286,14 +245,13 @@ bool ans_key_h(connection_t *c)
        
        from->outcompression = compression;
 
-       if(from->outcipher)
-               if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) {
-                       logger(LOG_ERR, _("Error during initialisation of key from %s (%s): %s"),
-                                       from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
-                       return false;
-               }
+       /* Update our copy of the origin's packet key */
+
+       hex2bin(key, key, cipher_keylength(&from->outcipher));
+       cipher_set_key(&from->outcipher, key, false);
 
        from->status.validkey = true;
+       from->status.waitingforkey = false;
        from->sent_seqno = 0;
 
        if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
index 18ff13c8de4bfb05a101666af22f2246f209d1a2..b8d2f67d39c6158484b89bc1ae91686c3faeaca8 100644 (file)
@@ -45,14 +45,14 @@ bool send_status(connection_t *c, int statusno, const char *statusstring)
        return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
 }
 
-bool status_h(connection_t *c)
+bool status_h(connection_t *c, char *request)
 {
        int statusno;
        char statusstring[MAX_STRING_SIZE];
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
+       if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS",
                           c->name, c->hostname);
                return false;
@@ -74,14 +74,14 @@ bool send_error(connection_t *c, int err, const char *errstring)
        return send_request(c, "%d %d %s", ERROR, err, errstring);
 }
 
-bool error_h(connection_t *c)
+bool error_h(connection_t *c, char *request)
 {
        int err;
        char errorstring[MAX_STRING_SIZE];
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
+       if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR",
                           c->name, c->hostname);
                return false;
@@ -90,9 +90,7 @@ bool error_h(connection_t *c)
        ifdebug(ERROR) logger(LOG_NOTICE, _("Error message from %s (%s): %d: %s"),
                           c->name, c->hostname, err, errorstring);
 
-       terminate_connection(c, c->status.active);
-
-       return true;
+       return false;
 }
 
 bool send_termreq(connection_t *c)
@@ -102,13 +100,11 @@ bool send_termreq(connection_t *c)
        return send_request(c, "%d", TERMREQ);
 }
 
-bool termreq_h(connection_t *c)
+bool termreq_h(connection_t *c, char *request)
 {
        cp();
 
-       terminate_connection(c, c->status.active);
-
-       return true;
+       return false;
 }
 
 bool send_ping(connection_t *c)
@@ -116,12 +112,12 @@ bool send_ping(connection_t *c)
        cp();
 
        c->status.pinged = true;
-       c->last_ping_time = now;
+       c->last_ping_time = time(NULL);
 
        return send_request(c, "%d", PING);
 }
 
-bool ping_h(connection_t *c)
+bool ping_h(connection_t *c, char *request)
 {
        cp();
 
@@ -135,7 +131,7 @@ bool send_pong(connection_t *c)
        return send_request(c, "%d", PONG);
 }
 
-bool pong_h(connection_t *c)
+bool pong_h(connection_t *c, char *request)
 {
        cp();
 
@@ -158,7 +154,7 @@ bool send_tcppacket(connection_t *c, vpn_packet_t *packet)
        /* If there already is a lot of data in the outbuf buffer, discard this packet.
            We use a very simple Random Early Drop algorithm. */
 
-       if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
+       if(2.0 * c->buffer->output->off / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
                return true;
 
        if(!send_request(c, "%d %hd", PACKET, packet->len))
@@ -167,13 +163,13 @@ bool send_tcppacket(connection_t *c, vpn_packet_t *packet)
        return send_meta(c, (char *)packet->data, packet->len);
 }
 
-bool tcppacket_h(connection_t *c)
+bool tcppacket_h(connection_t *c, char *request)
 {
        short int len;
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %hd", &len) != 1) {
+       if(sscanf(request, "%*d %hd", &len) != 1) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "PACKET", c->name,
                           c->hostname);
                return false;
index b50cf6a348cd4d0367902f615d3df57e5b576552..9c5b04c8866dca45a73ac6b5efe19380c677f63b 100644 (file)
@@ -45,7 +45,7 @@ bool send_add_subnet(connection_t *c, const subnet_t *subnet)
        return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr);
 }
 
-bool add_subnet_h(connection_t *c)
+bool add_subnet_h(connection_t *c, char *request)
 {
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
@@ -54,7 +54,7 @@ bool add_subnet_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
+       if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name,
                           c->hostname);
                return false;
@@ -76,7 +76,7 @@ bool add_subnet_h(connection_t *c)
                return false;
        }
 
-       if(seen_request(c->buffer))
+       if(seen_request(request))
                return true;
 
        /* Check if the owner of the new subnet is in the connection list */
@@ -147,7 +147,7 @@ bool add_subnet_h(connection_t *c)
        /* Tell the rest */
 
        if(!tunnelserver)
-               forward_request(c);
+               forward_request(c, request);
 
        return true;
 }
@@ -164,7 +164,7 @@ bool send_del_subnet(connection_t *c, const subnet_t *s)
        return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr);
 }
 
-bool del_subnet_h(connection_t *c)
+bool del_subnet_h(connection_t *c, char *request)
 {
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
@@ -173,7 +173,7 @@ bool del_subnet_h(connection_t *c)
 
        cp();
 
-       if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
+       if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
                logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name,
                           c->hostname);
                return false;
@@ -195,7 +195,7 @@ bool del_subnet_h(connection_t *c)
                return false;
        }
 
-       if(seen_request(c->buffer))
+       if(seen_request(request))
                return true;
 
        /* Check if the owner of the subnet being deleted is in the connection list */
@@ -239,7 +239,7 @@ bool del_subnet_h(connection_t *c)
        /* Tell the rest */
 
        if(!tunnelserver)
-               forward_request(c);
+               forward_request(c, request);
 
        /* Finally, delete it. */
 
index f2a135d3de57bea591b83d94447660d0db6a5caf..412ba41be55d6683e0fe43042820614437d68eda 100644 (file)
@@ -40,8 +40,7 @@ static char *device_info;
 static int device_total_in = 0;
 static int device_total_out = 0;
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        struct ifreq ifr;
        struct sockaddr_ll sa;
 
@@ -61,7 +60,7 @@ bool setup_device(void)
                return false;
        }
 
-       memset(&ifr, 0, sizeof(ifr));
+       memset(&ifr, 0, sizeof ifr);
        strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
        if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
                close(device_fd);
@@ -70,12 +69,12 @@ bool setup_device(void)
                return false;
        }
 
-       memset(&sa, '0', sizeof(sa));
+       memset(&sa, '0', sizeof sa);
        sa.sll_family = AF_PACKET;
        sa.sll_protocol = htons(ETH_P_ALL);
        sa.sll_ifindex = ifr.ifr_ifindex;
 
-       if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) {
+       if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof sa)) {
                logger(LOG_ERR, _("Could not bind %s to %s: %s"), device, iface, strerror(errno));
                return false;
        }
@@ -85,8 +84,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
 
        close(device_fd);
@@ -95,19 +93,18 @@ void close_device(void)
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
-       int lenin;
+bool read_packet(vpn_packet_t *packet) {
+       int inlen;
 
        cp();
 
-       if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
+       if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                           device, strerror(errno));
                return false;
        }
 
-       packet->len = lenin;
+       packet->len = inlen;
 
        device_total_in += packet->len;
 
@@ -117,8 +114,7 @@ bool read_packet(vpn_packet_t *packet)
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
+bool write_packet(vpn_packet_t *packet) {
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
@@ -135,8 +131,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index 9b689039c17250f2a57b2c9c44a37132783f478c..da37473ca930ed64a26c517248ab7f12f0f820b4 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "connection.h"
 #include "ethernet.h"
 #include "ipv4.h"
@@ -51,6 +51,8 @@ static const size_t icmp6_size = sizeof(struct icmp6_hdr);
 static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
 static const size_t opt_size = sizeof(struct nd_opt_hdr);
 
+static struct event age_subnets_event;
+
 /* RFC 1071 */
 
 static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
@@ -75,6 +77,7 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
 static bool ratelimit(int frequency) {
        static time_t lasttime = 0;
        static int count = 0;
+       time_t now = time(NULL);
        
        if(lasttime == now) {
                if(++count > frequency)
@@ -102,10 +105,47 @@ static void swap_mac_addresses(vpn_packet_t *packet) {
        memcpy(&packet->data[6], &tmp, sizeof tmp);
 }
        
+static void age_subnets(int fd, short events, void *data)
+{
+       subnet_t *s;
+       connection_t *c;
+       splay_node_t *node, *next, *node2;
+       bool left = false;
+       time_t now = time(NULL);
+
+       cp();
+
+       for(node = myself->subnet_tree->head; node; node = next) {
+               next = node->next;
+               s = node->data;
+               if(s->expires && s->expires < now) {
+                       ifdebug(TRAFFIC) {
+                               char netstr[MAXNETSTR];
+                               if(net2str(netstr, sizeof netstr, s))
+                                       logger(LOG_INFO, _("Subnet %s expired"), netstr);
+                       }
+
+                       for(node2 = connection_tree->head; node2; node2 = node2->next) {
+                               c = node2->data;
+                               if(c->status.active)
+                                       send_del_subnet(c, s);
+                       }
+
+                       subnet_del(myself, s);
+               } else {
+                       if(s->expires)
+                               left = true;
+               }
+       }
+
+       if(left)
+               event_add(&age_subnets_event, &(struct timeval){10, 0});
+}
+
 static void learn_mac(mac_t *address)
 {
        subnet_t *subnet;
-       avl_node_t *node;
+       splay_node_t *node;
        connection_t *c;
 
        cp();
@@ -121,7 +161,7 @@ static void learn_mac(mac_t *address)
 
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
-               subnet->expires = now + macexpire;
+               subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
                subnet_add(myself, subnet);
 
@@ -132,38 +172,13 @@ static void learn_mac(mac_t *address)
                        if(c->status.active)
                                send_add_subnet(c, subnet);
                }
-       }
-
-       if(subnet->expires)
-               subnet->expires = now + macexpire;
-}
-
-void age_subnets(void)
-{
-       subnet_t *s;
-       connection_t *c;
-       avl_node_t *node, *next, *node2;
 
-       cp();
-
-       for(node = myself->subnet_tree->head; node; node = next) {
-               next = node->next;
-               s = node->data;
-               if(s->expires && s->expires < now) {
-                       ifdebug(TRAFFIC) {
-                               char netstr[MAXNETSTR];
-                               if(net2str(netstr, sizeof netstr, s))
-                                       logger(LOG_INFO, _("Subnet %s expired"), netstr);
-                       }
-
-                       for(node2 = connection_tree->head; node2; node2 = node2->next) {
-                               c = node2->data;
-                               if(c->status.active)
-                                       send_del_subnet(c, s);
-                       }
-
-                       subnet_del(myself, s);
-               }
+               if(!timeout_initialized(&age_subnets_event))
+                       timeout_set(&age_subnets_event, age_subnets, NULL);
+               event_add(&age_subnets_event, &(struct timeval){10, 0});
+       } else {
+               if(subnet->expires)
+                       subnet->expires = time(NULL) + macexpire;
        }
 }
 
@@ -430,7 +445,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
 
        /* Generate checksum */
        
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&icmp6, icmp6_size, checksum);
        checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
 
@@ -555,7 +570,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
 
        /* Generate checksum */
 
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
@@ -618,7 +633,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
 
        /* Generate checksum */
 
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
@@ -685,7 +700,7 @@ static void route_arp(node_t *source, vpn_packet_t *packet)
        /* Check if this is a valid ARP request */
 
        if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
-          arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
+          arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) {
                ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
                return;
        }
@@ -709,9 +724,9 @@ static void route_arp(node_t *source, vpn_packet_t *packet)
        memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN);        /* copy destination address */
        packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
 
-       memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
-       memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
-       memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
+       memcpy(&addr, arp.arp_tpa, sizeof addr);        /* save protocol addr */
+       memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr);  /* swap destination and source protocol address */
+       memcpy(arp.arp_spa, &addr, sizeof addr);        /* ... */
 
        memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
        memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
index 807b707ad963f4a1dfcf9907564e7bee919fd7a9..0021506c47eb3b5ecfee96466d698f3927cd4b03 100644 (file)
@@ -39,7 +39,6 @@ extern int macexpire;
 
 extern mac_t mymac;
 
-extern void age_subnets(void);
 extern void route(struct node_t *, struct vpn_packet_t *);
 
 #endif                                                 /* __TINC_ROUTE_H__ */
index f76bbbd5feeb4c87db1543d64497c52eb142661a..a258e34e34f8097cd1c28c43a7eca74771d9fd20 100644 (file)
@@ -43,8 +43,7 @@ static char *device_info = NULL;
 static int device_total_in = 0;
 static int device_total_out = 0;
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        int ip_fd = -1, if_fd = -1;
        int ppa;
        char *ptr;
@@ -109,8 +108,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
 
        close(device_fd);
@@ -119,13 +117,12 @@ void close_device(void)
        free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
-       int lenin;
+bool read_packet(vpn_packet_t *packet) {
+       int inlen;
 
        cp();
 
-       if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
+       if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                           device, strerror(errno));
                return false;
@@ -147,7 +144,7 @@ bool read_packet(vpn_packet_t *packet)
                        return false;
        }
 
-       packet->len = lenin + 14;
+       packet->len = inlen + 14;
 
        device_total_in += packet->len;
 
@@ -157,8 +154,7 @@ bool read_packet(vpn_packet_t *packet)
        return true;
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
+bool write_packet(vpn_packet_t *packet) {
        cp();
 
        ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
@@ -175,8 +171,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
index 140b61450f0f5a836c83bfbd1084552256a5c37c..057550ab0760455f1626aaedebb49aed970f9c9a 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "system.h"
 
-#include "avl_tree.h"
+#include "splay_tree.h"
 #include "device.h"
 #include "logger.h"
 #include "net.h"
@@ -35,7 +35,7 @@
 
 /* lists type of subnet */
 
-avl_tree_t *subnet_tree;
+splay_tree_t *subnet_tree;
 
 /* Subnet lookup cache */
 
@@ -60,7 +60,7 @@ static int subnet_compare_mac(const subnet_t *a, const subnet_t *b)
 {
        int result;
 
-       result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
+       result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address);
 
        if(result)
                return result;
@@ -149,7 +149,7 @@ void init_subnets(void)
 {
        cp();
 
-       subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
+       subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet);
 
        subnet_cache_flush();
 }
@@ -158,21 +158,21 @@ void exit_subnets(void)
 {
        cp();
 
-       avl_delete_tree(subnet_tree);
+       splay_delete_tree(subnet_tree);
 }
 
-avl_tree_t *new_subnet_tree(void)
+splay_tree_t *new_subnet_tree(void)
 {
        cp();
 
-       return avl_alloc_tree((avl_compare_t) subnet_compare, NULL);
+       return splay_alloc_tree((splay_compare_t) subnet_compare, NULL);
 }
 
-void free_subnet_tree(avl_tree_t *subnet_tree)
+void free_subnet_tree(splay_tree_t *subnet_tree)
 {
        cp();
 
-       avl_delete_tree(subnet_tree);
+       splay_delete_tree(subnet_tree);
 }
 
 /* Allocating and freeing space for subnets */
@@ -199,8 +199,8 @@ void subnet_add(node_t *n, subnet_t *subnet)
 
        subnet->owner = n;
 
-       avl_insert(subnet_tree, subnet);
-       avl_insert(n->subnet_tree, subnet);
+       splay_insert(subnet_tree, subnet);
+       splay_insert(n->subnet_tree, subnet);
 
        subnet_cache_flush();
 }
@@ -209,8 +209,8 @@ void subnet_del(node_t *n, subnet_t *subnet)
 {
        cp();
 
-       avl_delete(n->subnet_tree, subnet);
-       avl_delete(subnet_tree, subnet);
+       splay_delete(n->subnet_tree, subnet);
+       splay_delete(subnet_tree, subnet);
 
        subnet_cache_flush();
 }
@@ -361,7 +361,7 @@ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet)
 {
        cp();
 
-       return avl_search(owner->subnet_tree, subnet);
+       return splay_search(owner->subnet_tree, subnet);
 }
 
 subnet_t *lookup_subnet_mac(const mac_t *address)
@@ -374,7 +374,7 @@ subnet_t *lookup_subnet_mac(const mac_t *address)
        subnet.net.mac.address = *address;
        subnet.owner = NULL;
 
-       p = avl_search(subnet_tree, &subnet);
+       p = splay_search(subnet_tree, &subnet);
 
        return p;
 }
@@ -382,7 +382,7 @@ subnet_t *lookup_subnet_mac(const mac_t *address)
 subnet_t *lookup_subnet_ipv4(const ipv4_t *address)
 {
        subnet_t *p, *r = NULL, subnet = {0};
-       avl_node_t *n;
+       splay_node_t *n;
        int i;
 
        cp();
@@ -429,7 +429,7 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address)
 subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
 {
        subnet_t *p, *r = NULL, subnet = {0};
-       avl_node_t *n;
+       splay_node_t *n;
        int i;
 
        cp();
@@ -474,7 +474,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
 }
 
 void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
-       avl_node_t *node;
+       splay_node_t *node;
        int i;
        char *envp[9] = {0};
        char netstr[MAXNETSTR];
@@ -540,22 +540,22 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
                free(envp[i]);
 }
 
-void dump_subnets(void)
+int dump_subnets(struct evbuffer *out)
 {
        char netstr[MAXNETSTR];
        subnet_t *subnet;
-       avl_node_t *node;
+       splay_node_t *node;
 
        cp();
 
-       logger(LOG_DEBUG, _("Subnet list:"));
-
        for(node = subnet_tree->head; node; node = node->next) {
                subnet = node->data;
                if(!net2str(netstr, sizeof netstr, subnet))
                        continue;
-               logger(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
+               if(evbuffer_add_printf(out, _(" %s owner %s\n"),
+                                                          netstr, subnet->owner->name) == -1)
+                       return errno;
        }
 
-       logger(LOG_DEBUG, _("End of subnet list."));
+       return 0;
 }
index 3efed1bea5d82cc3affe771c534ae1d0d2ef2d25..22af0d3a006ec9ba21e382fdc9092a1e69e8f962 100644 (file)
@@ -71,8 +71,8 @@ extern subnet_t *new_subnet(void) __attribute__ ((__malloc__));
 extern void free_subnet(subnet_t *);
 extern void init_subnets(void);
 extern void exit_subnets(void);
-extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
-extern void free_subnet_tree(avl_tree_t *);
+extern splay_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
+extern void free_subnet_tree(splay_tree_t *);
 extern void subnet_add(struct node_t *, subnet_t *);
 extern void subnet_del(struct node_t *, subnet_t *);
 extern void subnet_update(struct node_t *, subnet_t *, bool);
@@ -82,7 +82,7 @@ extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *);
 extern subnet_t *lookup_subnet_mac(const mac_t *);
 extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
 extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
-extern void dump_subnets(void);
+extern int dump_subnets(struct evbuffer *);
 extern void subnet_cache_flush(void);
 
 #endif                                                 /* __TINC_SUBNET_H__ */
diff --git a/src/tincctl.c b/src/tincctl.c
new file mode 100644 (file)
index 0000000..92796b6
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+    tincctl.c -- Controlling a running tincd
+    Copyright (C) 2007 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    $Id$
+*/
+
+#include "system.h"
+
+#include <sys/un.h>
+#include <getopt.h>
+
+#include "xalloc.h"
+#include "protocol.h"
+#include "control_common.h"
+#include "rsagen.h"
+
+/* The name this program was run with. */
+char *program_name = NULL;
+
+/* If nonzero, display usage information and exit. */
+bool show_help = false;
+
+/* If nonzero, print the version on standard output and exit.  */
+bool show_version = false;
+
+/* If nonzero, it will attempt to kill a running tincd and exit. */
+int kill_tincd = 0;
+
+/* If nonzero, generate public/private keypair for this host/net. */
+int generate_keys = 0;
+
+static char *identname = NULL;                         /* program name for syslog */
+static char *controlsocketname = NULL;                 /* pid file location */
+char *netname = NULL;
+char *confbase = NULL;
+
+static struct option const long_options[] = {
+       {"config", required_argument, NULL, 'c'},
+       {"net", required_argument, NULL, 'n'},
+       {"help", no_argument, NULL, 1},
+       {"version", no_argument, NULL, 2},
+       {"controlsocket", required_argument, NULL, 5},
+       {NULL, 0, NULL, 0}
+};
+
+static void usage(bool status) {
+       if(status)
+               fprintf(stderr, _("Try `%s --help\' for more information.\n"),
+                               program_name);
+       else {
+               printf(_("Usage: %s [options] command\n\n"), program_name);
+               printf(_("Valid options are:\n"
+                               "  -c, --config=DIR              Read configuration options from DIR.\n"
+                               "  -n, --net=NETNAME             Connect to net NETNAME.\n"
+                               "      --controlsocket=FILENAME  Open control socket at FILENAME.\n"
+                               "      --help                    Display this help and exit.\n"
+                               "      --version                 Output version information and exit.\n"
+                               "\n"
+                               "Valid commands are:\n"
+                               "  start                      Start tincd.\n"
+                               "  stop                       Stop tincd.\n"
+                               "  restart                    Restart tincd.\n"
+                               "  reload                     Reload configuration of running tincd.\n"
+                               "  pid                        Show PID of currently running tincd.\n"
+                               "  generate-keys [bits]       Generate a new public/private keypair.\n"
+                               "  dump                       Dump a list of one of the following things:\n"
+                               "    nodes                    - all known nodes in the VPN\n"
+                               "    edges                    - all known connections in the VPN\n"
+                               "    subnets                  - all known subnets in the VPN\n"
+                               "    connections              - all meta connections with ourself\n"
+                               "    graph                    - graph of the VPN in dotty format\n"
+                               "  purge                      Purge unreachable nodes\n"
+                               "  debug N                    Set debug level\n"
+                               "  retry                      Retry all outgoing connections\n"
+                               "  reload                     Partial reload of configuration\n"
+                               "\n"));
+               printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
+       }
+}
+
+static bool parse_options(int argc, char **argv) {
+       int r;
+       int option_index = 0;
+
+       while((r = getopt_long(argc, argv, "c:n:", long_options, &option_index)) != EOF) {
+               switch (r) {
+                       case 0:                         /* long option */
+                               break;
+
+                       case 'c':                               /* config file */
+                               confbase = xstrdup(optarg);
+                               break;
+
+                       case 'n':                               /* net name given */
+                               netname = xstrdup(optarg);
+                               break;
+
+                       case 1:                                 /* show help */
+                               show_help = true;
+                               break;
+
+                       case 2:                                 /* show version */
+                               show_version = true;
+                               break;
+
+                       case 5:                                 /* open control socket here */
+                               controlsocketname = xstrdup(optarg);
+                               break;
+
+                       case '?':
+                               usage(true);
+                               return false;
+
+                       default:
+                               break;
+               }
+       }
+
+       return true;
+}
+
+FILE *ask_and_open(const char *filename, const char *what, const char *mode) {
+       FILE *r;
+       char *directory;
+       char buf[PATH_MAX];
+       char buf2[PATH_MAX];
+       size_t len;
+
+       /* Check stdin and stdout */
+       if(isatty(0) && isatty(1)) {
+               /* Ask for a file and/or directory name. */
+               fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
+                               what, filename);
+               fflush(stdout);
+
+               if(fgets(buf, sizeof buf, stdin) < 0) {
+                       fprintf(stderr, _("Error while reading stdin: %s\n"),
+                                       strerror(errno));
+                       return NULL;
+               }
+
+               len = strlen(buf);
+               if(len)
+                       buf[--len] = 0;
+
+               if(len)
+                       filename = buf;
+       }
+
+#ifdef HAVE_MINGW
+       if(filename[0] != '\\' && filename[0] != '/' && !strchr(filename, ':')) {
+#else
+       if(filename[0] != '/') {
+#endif
+               /* The directory is a relative path or a filename. */
+               directory = get_current_dir_name();
+               snprintf(buf2, sizeof buf2, "%s/%s", directory, filename);
+               filename = buf2;
+       }
+
+       umask(0077);                            /* Disallow everything for group and other */
+
+       /* Open it first to keep the inode busy */
+
+       r = fopen(filename, mode);
+
+       if(!r) {
+               fprintf(stderr, _("Error opening file `%s': %s\n"), filename, strerror(errno));
+               return NULL;
+       }
+
+       return r;
+}
+
+/*
+  Generate a public/private RSA keypair, and ask for a file to store
+  them in.
+*/
+static bool keygen(int bits) {
+       rsa_t key;
+       FILE *f;
+       char *name = NULL;
+       char *filename;
+
+       fprintf(stderr, _("Generating %d bits keys:\n"), bits);
+
+       if(!rsa_generate(&key, bits, 0x10001)) {
+               fprintf(stderr, _("Error during key generation!\n"));
+               return false;
+       } else
+               fprintf(stderr, _("Done.\n"));
+
+       asprintf(&filename, "%s/rsa_key.priv", confbase);
+       f = ask_and_open(filename, _("private RSA key"), "a");
+
+       if(!f)
+               return false;
+  
+#ifdef HAVE_FCHMOD
+       /* Make it unreadable for others. */
+       fchmod(fileno(f), 0600);
+#endif
+               
+       if(ftell(f))
+               fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
+
+       rsa_write_pem_private_key(&key, f);
+
+       fclose(f);
+       free(filename);
+
+       if(name)
+               asprintf(&filename, "%s/hosts/%s", confbase, name);
+       else
+               asprintf(&filename, "%s/rsa_key.pub", confbase);
+
+       f = ask_and_open(filename, _("public RSA key"), "a");
+
+       if(!f)
+               return false;
+
+       if(ftell(f))
+               fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
+
+       rsa_write_pem_public_key(&key, f);
+
+       fclose(f);
+       free(filename);
+
+       return true;
+}
+
+/*
+  Set all files and paths according to netname
+*/
+static void make_names(void) {
+#ifdef HAVE_MINGW
+       HKEY key;
+       char installdir[1024] = "";
+       long len = sizeof installdir;
+#endif
+
+       if(netname)
+               asprintf(&identname, "tinc.%s", netname);
+       else
+               identname = xstrdup("tinc");
+
+#ifdef HAVE_MINGW
+       if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
+               if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) {
+                       if(!logfilename)
+                               asprintf(&logfilename, "%s/log/%s.log", identname);
+                       if(!confbase) {
+                               if(netname)
+                                       asprintf(&confbase, "%s/%s", installdir, netname);
+                               else
+                                       asprintf(&confbase, "%s", installdir);
+                       }
+               }
+               RegCloseKey(key);
+               if(*installdir)
+                       return;
+       }
+#endif
+
+       if(!controlsocketname)
+               asprintf(&controlsocketname, "%s/run/%s.control/socket", LOCALSTATEDIR, identname);
+
+       if(netname) {
+               if(!confbase)
+                       asprintf(&confbase, CONFDIR "/tinc/%s", netname);
+               else
+                       fprintf(stderr, _("Both netname and configuration directory given, using the latter...\n"));
+       } else {
+               if(!confbase)
+                       asprintf(&confbase, CONFDIR "/tinc");
+       }
+}
+
+static int fullread(int fd, void *data, size_t datalen) {
+       int rv, len = 0;
+
+       while(len < datalen) {
+               rv = read(fd, data + len, datalen - len);
+               if(rv == -1 && errno == EINTR)
+                       continue;
+               else if(rv == -1)
+                       return rv;
+               else if(rv == 0) {
+                       errno = ENODATA;
+                       return -1;
+               }
+               len += rv;
+       }
+       return 0;
+}
+
+/*
+   Send a request (raw)
+*/
+static int send_ctl_request(int fd, enum request_type type,
+                                                  void const *outdata, size_t outdatalen,
+                                                  int *res_errno_p, void **indata_p,
+                                                  size_t *indatalen_p) {
+       tinc_ctl_request_t req;
+       int rv;
+       struct iovec vector[2] = {
+               {&req, sizeof req},
+               {(void*) outdata, outdatalen}
+       };
+       void *indata;
+
+       if(res_errno_p == NULL)
+               return -1;
+
+       memset(&req, 0, sizeof req);
+       req.length = sizeof req + outdatalen;
+       req.type = type;
+       req.res_errno = 0;
+
+       while((rv = writev(fd, vector, 2)) == -1 && errno == EINTR) ;
+       if(rv != req.length)
+               return -1;
+
+       if(fullread(fd, &req, sizeof req) == -1)
+               return -1;
+
+       if(req.length < sizeof req) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if(req.length > sizeof req) {
+               if(indata_p == NULL) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               indata = xmalloc(req.length - sizeof req);
+
+               if(fullread(fd, indata, req.length - sizeof req) == -1) {
+                       free(indata);
+                       return -1;
+               }
+
+               *indata_p = indata;
+               if(indatalen_p != NULL)
+                       *indatalen_p = req.length - sizeof req;
+       }
+
+       *res_errno_p = req.res_errno;
+
+       return 0;
+}
+
+/*
+   Send a request (with printfs)
+*/
+static int send_ctl_request_cooked(int fd, enum request_type type,
+                                                                  void const *outdata, size_t outdatalen)
+{
+       int res_errno = -1;
+       char *buf = NULL;
+       size_t buflen = 0;
+
+       if(send_ctl_request(fd, type, outdata, outdatalen, &res_errno,
+                                               (void**) &buf, &buflen)) {
+               fprintf(stderr, _("Error sending request: %s\n"), strerror(errno));
+               return -1;
+       }
+
+       if(buf != NULL) {
+               printf("%*s", (int)buflen, buf);
+               free(buf);
+       }
+
+       if(res_errno != 0) {
+               fprintf(stderr, _("Server reported error: %s\n"), strerror(res_errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+int main(int argc, char *argv[], char *envp[]) {
+       struct sockaddr_un addr;
+       tinc_ctl_greeting_t greeting;
+       int fd;
+       int result;
+
+       program_name = argv[0];
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if(!parse_options(argc, argv))
+               return 1;
+       
+       make_names();
+
+       if(show_version) {
+               printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE,
+                          VERSION, __DATE__, __TIME__, PROT_CURRENT);
+               printf(_("Copyright (C) 1998-2007 Ivo Timmermans, Guus Sliepen and others.\n"
+                               "See the AUTHORS file for a complete list.\n\n"
+                               "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
+                               "and you are welcome to redistribute it under certain conditions;\n"
+                               "see the file COPYING for details.\n"));
+
+               return 0;
+       }
+
+       if(show_help) {
+               usage(false);
+               return 0;
+       }
+
+       if(optind >= argc) {
+               fprintf(stderr, _("Not enough arguments.\n"));
+               usage(true);
+               return 1;
+       }
+
+       // First handle commands that don't involve connecting to a running tinc daemon.
+
+       if(!strcasecmp(argv[optind], "generate-keys")) {
+               return !keygen(optind > argc ? atoi(argv[optind + 1]) : 2048);
+       }
+
+       if(!strcasecmp(argv[optind], "start")) {
+               argv[optind] = NULL;
+               execve(SBINDIR "/tincd", argv, envp);
+               fprintf(stderr, _("Could not start tincd: %s"), strerror(errno));
+               return 1;
+       }
+
+       /*
+        * Now handle commands that do involve connecting to a running tinc daemon.
+        * Authenticate the server by ensuring the parent directory can be
+        * traversed only by root. Note this is not totally race-free unless all
+        * ancestors are writable only by trusted users, which we don't verify.
+        */
+
+       struct stat statbuf;
+       char *lastslash = strrchr(controlsocketname, '/');
+       if(lastslash != NULL) {
+               /* control socket is not in cwd; stat its parent */
+               *lastslash = 0;
+               result = stat(controlsocketname, &statbuf);
+               *lastslash = '/';
+       } else
+               result = stat(".", &statbuf);
+
+       if(result < 0) {
+               fprintf(stderr, _("Unable to check control socket directory permissions: %s\n"), strerror(errno));
+               return 1;
+       }
+
+       if(statbuf.st_uid != 0 || (statbuf.st_mode & S_IXOTH) != 0 || (statbuf.st_gid != 0 && (statbuf.st_mode & S_IXGRP)) != 0) {
+               fprintf(stderr, _("Insecure permissions on control socket directory\n"));
+               return 1;
+       }
+
+       if(strlen(controlsocketname) >= sizeof addr.sun_path) {
+               fprintf(stderr, _("Control socket filename too long!\n"));
+               return 1;
+       }
+
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if(fd < 0) {
+               fprintf(stderr, _("Cannot create UNIX socket: %s\n"), strerror(errno));
+               return 1;
+       }
+
+       memset(&addr, 0, sizeof addr);
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, controlsocketname, sizeof addr.sun_path - 1);
+
+       if(connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
+               fprintf(stderr, _("Cannot connect to %s: %s\n"), controlsocketname, strerror(errno));
+               return 1;
+       }
+
+       if(fullread(fd, &greeting, sizeof greeting) == -1) {
+               fprintf(stderr, _("Cannot read greeting from control socket: %s\n"),
+                               strerror(errno));
+               return 1;
+       }
+
+       if(greeting.version != TINC_CTL_VERSION_CURRENT) {
+               fprintf(stderr, _("Version mismatch: server %d, client %d\n"),
+                               greeting.version, TINC_CTL_VERSION_CURRENT);
+               return 1;
+       }
+
+       if(!strcasecmp(argv[optind], "pid")) {
+               printf("%d\n", greeting.pid);
+               return 0;
+       }
+
+       if(!strcasecmp(argv[optind], "stop")) {
+               return send_ctl_request_cooked(fd, REQ_STOP, NULL, 0) != -1;
+       }
+
+       if(!strcasecmp(argv[optind], "reload")) {
+               return send_ctl_request_cooked(fd, REQ_RELOAD, NULL, 0) != -1;
+       }
+       
+       if(!strcasecmp(argv[optind], "restart")) {
+               return send_ctl_request_cooked(fd, REQ_RESTART, NULL, 0) != -1;
+       }
+
+       if(!strcasecmp(argv[optind], "dump")) {
+               if(argc < optind + 2) {
+                       fprintf(stderr, _("Not enough arguments.\n"));
+                       usage(true);
+                       return 1;
+               }
+
+               if(!strcasecmp(argv[optind+1], "nodes")) {
+                       return send_ctl_request_cooked(fd, REQ_DUMP_NODES, NULL, 0) != -1;
+               }
+
+               if(!strcasecmp(argv[optind+1], "edges")) {
+                       return send_ctl_request_cooked(fd, REQ_DUMP_EDGES, NULL, 0) != -1;
+               }
+
+               if(!strcasecmp(argv[optind+1], "subnets")) {
+                       return send_ctl_request_cooked(fd, REQ_DUMP_SUBNETS, NULL, 0) != -1;
+               }
+
+               if(!strcasecmp(argv[optind+1], "connections")) {
+                       return send_ctl_request_cooked(fd, REQ_DUMP_CONNECTIONS, NULL, 0) != -1;
+               }
+
+               if(!strcasecmp(argv[optind+1], "graph")) {
+                       return send_ctl_request_cooked(fd, REQ_DUMP_GRAPH, NULL, 0) != -1;
+               }
+
+               fprintf(stderr, _("Unknown dump type '%s'.\n"), argv[optind+1]);
+               usage(true);
+               return 1;
+       }
+
+       if(!strcasecmp(argv[optind], "purge")) {
+               return send_ctl_request_cooked(fd, REQ_PURGE, NULL, 0) != -1;
+       }
+
+       if(!strcasecmp(argv[optind], "debug")) {
+               int debuglevel;
+
+               if(argc != optind + 2) {
+                       fprintf(stderr, "Invalid arguments.\n");
+                       return 1;
+               }
+               debuglevel = atoi(argv[optind+1]);
+               return send_ctl_request_cooked(fd, REQ_SET_DEBUG, &debuglevel,
+                                                                          sizeof debuglevel) != -1;
+       }
+
+       if(!strcasecmp(argv[optind], "retry")) {
+               return send_ctl_request_cooked(fd, REQ_RETRY, NULL, 0) != -1;
+       }
+
+       if(!strcasecmp(argv[optind], "reload")) {
+               return send_ctl_request_cooked(fd, REQ_RELOAD, NULL, 0) != -1;
+       }
+
+       fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]);
+       usage(true);
+       
+       close(fd);
+
+       return 0;
+}
index 602f18b1ff99a0c7f6167e529f517393e47c0061..48f5faf88ce2dd987a18f84643dda8902a09f8cb 100644 (file)
 #include <sys/mman.h>
 #endif
 
-#include <openssl/rand.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include <openssl/evp.h>
-#include <openssl/engine.h>
-
 #include LZO1X_H
 
 #ifndef HAVE_MINGW
 #endif
 
 #include <getopt.h>
-#include "pidfile.h"
 
 #include "conf.h"
+#include "control.h"
+#include "crypto.h"
 #include "device.h"
 #include "logger.h"
 #include "net.h"
@@ -67,12 +62,6 @@ bool show_help = false;
 /* If nonzero, print the version on standard output and exit.  */
 bool show_version = false;
 
-/* If nonzero, it will attempt to kill a running tincd and exit. */
-int kill_tincd = 0;
-
-/* If nonzero, generate public/private keypair for this host/net. */
-int generate_keys = 0;
-
 /* If nonzero, use null ciphers and skip all key exchanges. */
 bool bypass_security = false;
 
@@ -89,7 +78,7 @@ static const char *switchuser = NULL;
 bool use_logfile = false;
 
 char *identname = NULL;                                /* program name for syslog */
-char *pidfilename = NULL;                      /* pid file location */
+char *controlsocketname = NULL;                        /* control socket location */
 char *logfilename = NULL;                      /* log file location */
 char **g_argv;                                 /* a copy of the cmdline arguments */
 
@@ -97,19 +86,17 @@ static int status;
 
 static struct option const long_options[] = {
        {"config", required_argument, NULL, 'c'},
-       {"kill", optional_argument, NULL, 'k'},
        {"net", required_argument, NULL, 'n'},
        {"help", no_argument, NULL, 1},
        {"version", no_argument, NULL, 2},
        {"no-detach", no_argument, NULL, 'D'},
-       {"generate-keys", optional_argument, NULL, 'K'},
        {"debug", optional_argument, NULL, 'd'},
        {"bypass-security", no_argument, NULL, 3},
        {"mlock", no_argument, NULL, 'L'},
        {"chroot", no_argument, NULL, 'R'},
        {"user", required_argument, NULL, 'U'},
        {"logfile", optional_argument, NULL, 4},
-       {"pidfile", required_argument, NULL, 5},
+       {"controlsocket", required_argument, NULL, 5},
        {NULL, 0, NULL, 0}
 };
 
@@ -125,19 +112,17 @@ static void usage(bool status)
                                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"
-                               "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
-                               "  -n, --net=NETNAME          Connect to net NETNAME.\n"
-                               "  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
-                               "  -L, --mlock                Lock tinc into main memory.\n"
-                               "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
-                               "      --pidfile=FILENAME     Write PID to FILENAME.\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"
+                               "      --controlsocket=FILENAME  Open control socket at FILENAME.\n"
+                               "      --bypass-security         Disables meta protocol security, for debugging.\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"));
        }
 }
@@ -147,7 +132,7 @@ static bool parse_options(int argc, char **argv)
        int r;
        int option_index = 0;
 
-       while((r = getopt_long(argc, argv, "c:DLd::k::n:K::RU:", long_options, &option_index)) != EOF) {
+       while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) {
                switch (r) {
                        case 0:                         /* long option */
                                break;
@@ -176,62 +161,10 @@ static bool parse_options(int argc, char **argv)
                                        debug_level++;
                                break;
 
-                       case 'k':                               /* kill old tincds */
-#ifndef HAVE_MINGW
-                               if(optarg) {
-                                       if(!strcasecmp(optarg, "HUP"))
-                                               kill_tincd = SIGHUP;
-                                       else if(!strcasecmp(optarg, "TERM"))
-                                               kill_tincd = SIGTERM;
-                                       else if(!strcasecmp(optarg, "KILL"))
-                                               kill_tincd = SIGKILL;
-                                       else if(!strcasecmp(optarg, "USR1"))
-                                               kill_tincd = SIGUSR1;
-                                       else if(!strcasecmp(optarg, "USR2"))
-                                               kill_tincd = SIGUSR2;
-                                       else if(!strcasecmp(optarg, "WINCH"))
-                                               kill_tincd = SIGWINCH;
-                                       else if(!strcasecmp(optarg, "INT"))
-                                               kill_tincd = SIGINT;
-                                       else if(!strcasecmp(optarg, "ALRM"))
-                                               kill_tincd = SIGALRM;
-                                       else {
-                                               kill_tincd = atoi(optarg);
-
-                                               if(!kill_tincd) {
-                                                       fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
-                                                                       optarg);
-                                                       usage(true);
-                                                       return false;
-                                               }
-                                       }
-                               } else
-                                       kill_tincd = SIGTERM;
-#else
-                                       kill_tincd = 1;
-#endif
-                               break;
-
                        case 'n':                               /* net name given */
                                netname = xstrdup(optarg);
                                break;
 
-                       case 'K':                               /* generate public/private keypair */
-                               if(optarg) {
-                                       generate_keys = atoi(optarg);
-
-                                       if(generate_keys < 512) {
-                                               fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"),
-                                                               optarg);
-                                               usage(true);
-                                               return false;
-                                       }
-
-                                       generate_keys &= ~7;    /* Round it to bytes */
-                               } else
-                                       generate_keys = 2048;
-                               break;
-
                        case 'R':                               /* chroot to NETNAME dir */
                                do_chroot = true;
                                break;
@@ -258,8 +191,8 @@ static bool parse_options(int argc, char **argv)
                                        logfilename = xstrdup(optarg);
                                break;
 
-                       case 5:                                 /* write PID to a file */
-                               pidfilename = xstrdup(optarg);
+                       case 5:                                 /* open control socket here */
+                               controlsocketname = xstrdup(optarg);
                                break;
 
                        case '?':
@@ -274,110 +207,6 @@ static bool parse_options(int argc, char **argv)
        return true;
 }
 
-/* This function prettyprints the key generation process */
-
-static void indicator(int a, int b, void *p)
-{
-       switch (a) {
-               case 0:
-                       fprintf(stderr, ".");
-                       break;
-
-               case 1:
-                       fprintf(stderr, "+");
-                       break;
-
-               case 2:
-                       fprintf(stderr, "-");
-                       break;
-
-               case 3:
-                       switch (b) {
-                               case 0:
-                                       fprintf(stderr, " p\n");
-                                       break;
-
-                               case 1:
-                                       fprintf(stderr, " q\n");
-                                       break;
-
-                               default:
-                                       fprintf(stderr, "?");
-                       }
-                       break;
-
-               default:
-                       fprintf(stderr, "?");
-       }
-}
-
-/*
-  Generate a public/private RSA keypair, and ask for a file to store
-  them in.
-*/
-static bool keygen(int bits)
-{
-       RSA *rsa_key;
-       FILE *f;
-       char *name = NULL;
-       char *filename;
-
-       get_config_string(lookup_config(config_tree, "Name"), &name);
-
-       if(name && !check_id(name)) {
-               fprintf(stderr, _("Invalid name for myself!\n"));
-               return false;
-       }
-
-       fprintf(stderr, _("Generating %d bits keys:\n"), bits);
-       rsa_key = RSA_generate_key(bits, 0x10001, indicator, NULL);
-
-       if(!rsa_key) {
-               fprintf(stderr, _("Error during key generation!\n"));
-               return false;
-       } else
-               fprintf(stderr, _("Done.\n"));
-
-       xasprintf(&filename, "%s/rsa_key.priv", confbase);
-       f = ask_and_open(filename, _("private RSA key"));
-
-       if(!f)
-               return false;
-
-       if(disable_old_keys(f))
-               fprintf(stderr, _("Warning: old key(s) found and disabled.\n"));
-  
-#ifdef HAVE_FCHMOD
-       /* Make it unreadable for others. */
-       fchmod(fileno(f), 0600);
-#endif
-               
-       PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL);
-       fclose(f);
-       free(filename);
-
-       if(name)
-               xasprintf(&filename, "%s/hosts/%s", confbase, name);
-       else
-               xasprintf(&filename, "%s/rsa_key.pub", confbase);
-
-       f = ask_and_open(filename, _("public RSA key"));
-
-       if(!f)
-               return false;
-
-       if(disable_old_keys(f))
-               fprintf(stderr, _("Warning: old key(s) found and disabled.\n"));
-
-       PEM_write_RSAPublicKey(f, rsa_key);
-       fclose(f);
-       free(filename);
-       if(name)
-               free(name);
-
-       return true;
-}
-
 /*
   Set all files and paths according to netname
 */
@@ -386,7 +215,7 @@ static void make_names(void)
 #ifdef HAVE_MINGW
        HKEY key;
        char installdir[1024] = "";
-       long len = sizeof(installdir);
+       long len = sizeof installdir;
 #endif
 
        if(netname)
@@ -412,8 +241,8 @@ static void make_names(void)
        }
 #endif
 
-       if(!pidfilename)
-               xasprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname);
+       if(!controlsocketname)
+               xasprintf(&controlsocketname, "%s/run/%s.control/socket", LOCALSTATEDIR, identname);
 
        if(!logfilename)
                xasprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname);
@@ -432,7 +261,7 @@ static void make_names(void)
 static void free_names() {
        if (identname) free(identname);
        if (netname) free(netname);
-       if (pidfilename) free(pidfilename);
+       if (controlsocketname) free(controlsocketname);
        if (logfilename) free(logfilename);
        if (confbase) free(confbase);
 }
@@ -524,28 +353,24 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       if(kill_tincd)
-               return !kill_other(kill_tincd);
-
        openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
 
+       if(!event_init()) {
+               logger(LOG_ERR, _("Error initializing libevent!"));
+               return 1;
+       }
+
+       if(!init_control())
+               return 1;
+
        g_argv = argv;
 
        init_configuration(&config_tree);
 
        /* Slllluuuuuuurrrrp! */
 
-       RAND_load_file("/dev/urandom", 1024);
-
-       ENGINE_load_builtin_engines();
-       ENGINE_register_all_complete();
-
-       OpenSSL_add_all_algorithms();
-
-       if(generate_keys) {
-               read_server_config();
-               return !keygen(generate_keys);
-       }
+       srand(time(NULL));
+       crypto_init();
 
        if(!read_server_config())
                return 1;
@@ -632,14 +457,10 @@ end:
        logger(LOG_NOTICE, _("Terminating"));
 
 #ifndef HAVE_MINGW
-       remove_pid(pidfilename);
+       exit_control();
 #endif
 
-       EVP_cleanup();
-       ENGINE_cleanup();
-       CRYPTO_cleanup_all_ex_data();
-       ERR_remove_state(0);
-       ERR_free_strings();
+       crypto_exit();
 
        exit_configuration(&config_tree);
        free_names();
index de0b4a556a310a5a6ebae534963d968b1c9523a4..ec9dcb1efa2b7702b1baea71ecf0cb751b0edd39 100644 (file)
@@ -57,8 +57,7 @@ static struct request {
 
 static struct sockaddr_un data_sun;
 
-bool setup_device(void)
-{
+bool setup_device(void) {
        struct sockaddr_un listen_sun;
        static const int one = 1;
        struct {
@@ -154,8 +153,7 @@ bool setup_device(void)
        return true;
 }
 
-void close_device(void)
-{
+void close_device(void) {
        cp();
 
        if(listen_fd >= 0)
@@ -176,9 +174,8 @@ void close_device(void)
        if(iface) free(iface);
 }
 
-bool read_packet(vpn_packet_t *packet)
-{
-       int lenin;
+bool read_packet(vpn_packet_t *packet) {
+       int inlen;
 
        cp();
 
@@ -208,7 +205,7 @@ bool read_packet(vpn_packet_t *packet)
                }
 
                case 1: {
-                       if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) {
+                       if((inlen = read(request_fd, &request, sizeof request)) != sizeof request) {
                                logger(LOG_ERR, _("Error while reading request from %s %s: %s"), device_info,
                                           device, strerror(errno));
                                running = false;
@@ -238,14 +235,14 @@ bool read_packet(vpn_packet_t *packet)
                }
 
                case 2: {
-                       if((lenin = read(data_fd, packet->data, MTU)) <= 0) {
+                       if((inlen = read(data_fd, packet->data, MTU)) <= 0) {
                                logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
                                           device, strerror(errno));
                                running = false;
                                return false;
                        }
 
-                       packet->len = lenin;
+                       packet->len = inlen;
 
                        device_total_in += packet->len;
 
@@ -257,8 +254,7 @@ bool read_packet(vpn_packet_t *packet)
        }
 }
 
-bool write_packet(vpn_packet_t *packet)
-{
+bool write_packet(vpn_packet_t *packet) {
        cp();
 
        if(state != 2) {
@@ -284,8 +280,7 @@ bool write_packet(vpn_packet_t *packet)
        return true;
 }
 
-void dump_device_stats(void)
-{
+void dump_device_stats(void) {
        cp();
 
        logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);