Import Debian changes 1.1~pre7-1

tinc (1.1~pre7-1) experimental; urgency=high

  * New upstream release.
    - Drop packets forwarded via TCP if they are too big (CVE-2013-1428).
This commit is contained in:
Guus Sliepen 2013-04-23 11:37:38 +02:00
commit a62bf04cde
43 changed files with 1372 additions and 867 deletions

View file

@ -1,4 +1,4 @@
Copyright (C) 1998-2012 Ivo Timmermans, Guus Sliepen and others.
Copyright (C) 1998-2013 Ivo Timmermans, Guus Sliepen and others.
See the AUTHORS file for a complete list.
This program is free software; you can redistribute it and/or modify it under

View file

@ -1,3 +1,20 @@
Version 1.1pre7 April 22 2013
------------------------------------------------------------------------
Guus Sliepen (12):
Use UDP when using sptps_test in datagram mode.
Flush output buffers in the tap reader thread on Windows.
Better default output file for generated public keys.
Allow changing configuration with tincctl without the "config" keyword.
Avoid calling time(NULL).
Include README.android in the tarballs.
Rename tincctl to tinc.
Remove references to the config keyword.
Describe the SPTPS protocol in the manual.
Fix completion of add/del/get/set commands.
Drop packets forwarded via TCP if they are too big (CVE-2013-1428).
Releasing 1.1pre7.
Version 1.1pre6 February 20 2013
------------------------------------------------------------------------

View file

@ -6,7 +6,7 @@ SUBDIRS = m4 src doc gui
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = have.h system.h COPYING.README
EXTRA_DIST = have.h system.h COPYING.README README.android
ChangeLog:
git log > ChangeLog

View file

@ -236,7 +236,7 @@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = gnu
SUBDIRS = m4 src doc gui
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = have.h system.h COPYING.README
EXTRA_DIST = have.h system.h COPYING.README README.android
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive

14
NEWS
View file

@ -1,3 +1,17 @@
Version 1.1pre7 April 22 2013
* Fixed large latencies on Windows.
* Renamed the tincctl tool to tinc.
* Simplified changing the configuration using the tinc tool.
* Added a full description of the ExperimentalProtocol to the manual.
* Drop packets forwarded via TCP if they are too big (CVE-2013-1428).
Thanks to Martin Schobert for auditing tinc and reporting the vulnerability.
Version 1.1pre6 February 20 2013
* Fixed tincd exitting immediately on Windows.

10
README
View file

@ -1,4 +1,4 @@
This is the README file for tinc version 1.1pre6. Installation
This is the README file for tinc version 1.1pre7. Installation
instructions may be found in the INSTALL file.
tinc is Copyright (C) 1998-2013 by:
@ -22,7 +22,7 @@ Please note that this is NOT a stable release. Until version 1.1.0 is released,
please use one of the 1.0.x versions if you need a stable version of tinc.
Although tinc 1.1 will be protocol compatible with tinc 1.0.x, the
functionality of the tincctl program may still change, and the control socket
functionality of the tinc program may still change, and the control socket
protocol is not fixed yet.
@ -36,11 +36,11 @@ at your own risk.
Compatibility
-------------
Version 1.1pre6 is compatible with 1.0pre8, 1.0 and later, but not with older
Version 1.1pre7 is compatible with 1.0pre8, 1.0 and later, but not with older
versions of tinc.
When the ExperimentalProtocol option is used, tinc is still compatible with
1.0.X and 1.1pre6 itself, but not with any other 1.1preX version.
1.0.X and 1.1pre7 itself, but not with any other 1.1preX version.
Requirements
@ -88,6 +88,6 @@ Windows environment this means tinc will intall itself as a service, which will
restart after reboots. To prevent tinc from detaching or running as a service,
use the -D option.
The status of the VPN can be queried using the "tincctl" tool, which connects
The status of the VPN can be queried using the "tinc" command, which connects
to a running tinc daemon via a control connection. The same tool also makes it
easy to start and stop tinc, and to change its configuration.

20
README.android Normal file
View file

@ -0,0 +1,20 @@
Quick how-o cross compile tinc for android (done from $HOME/android/):
- Download android NDK and setup local ARM toolchain:
wget http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
tar xfj android-ndk-r8b-linux-x86.tar.bz2
./android-ndk-r8b/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain
- Download and cross-compile openSSL for ARM:
wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz
tar xfz openssl-1.0.1c.tar.gz
cd openssl-1.0.1c
./Configure dist
make CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc AR="/tmp/my-android-toolchain/bin/arm-linux-androideabi-ar r" RANLIB=/tmp/my-android-toolchain/bin/arm-linux-androideabi-ranlib
- Clone and cross-compile tinc:
git clone git://tinc-vpn.org/tinc
cd tinc
autoreconf -fsi
CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc ./configure --host=arm-linux --disable-lzo --with-openssl-lib=$HOME/android/openssl-1.0.1c --with-openssl-include=$HOME/android/openssl-1.0.1c/include/
make -j5

1
THANKS
View file

@ -30,6 +30,7 @@ We would like to thank the following people for their contributions to tinc:
* Mark Glines
* Markus Goetz
* Martin Kihlgren
* Martin Schobert
* Martin Schürrer
* Matias Carrasco
* Max Rijevski

2
configure vendored
View file

@ -4095,7 +4095,7 @@ fi
# Define the identity of the package.
PACKAGE=tinc
VERSION=1.1pre6
VERSION=1.1pre7
cat >>confdefs.h <<_ACEOF

View file

@ -4,7 +4,7 @@ AC_PREREQ(2.61)
AC_INIT
AC_CONFIG_SRCDIR([src/tincd.c])
AC_GNU_SOURCE
AM_INIT_AUTOMAKE(tinc, 1.1pre6)
AM_INIT_AUTOMAKE(tinc, 1.1pre7)
AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE

7
debian/changelog vendored
View file

@ -1,3 +1,10 @@
tinc (1.1~pre7-1) experimental; urgency=high
* New upstream release.
- Drop packets forwarded via TCP if they are too big (CVE-2013-1428).
-- Guus Sliepen <guus@debian.org> Tue, 23 Apr 2013 11:37:38 +0200
tinc (1.1~pre6-1) experimental; urgency=low
* New upstream release.

2
debian/control vendored
View file

@ -3,7 +3,7 @@ Section: net
Priority: optional
Maintainer: Guus Sliepen <guus@debian.org>
Standards-Version: 3.9.3
Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 9), texi2html, texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libreadline-dev
Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 9), texi2html, texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libreadline-dev, libvdeplug-dev
Homepage: http://www.tinc-vpn.org/
Package: tinc

2
debian/rules vendored
View file

@ -15,7 +15,7 @@
dh $@ --parallel
override_dh_auto_configure:
dh_auto_configure -- --disable-uml --disable-vde
dh_auto_configure -- --enable-uml --enable-vde
override_dh_auto_build:
dh_auto_build

2
debian/tinc.files vendored
View file

@ -1,5 +1,5 @@
usr/sbin/tincd
usr/sbin/tincctl
usr/sbin/tinc
usr/share/man
etc
usr/share/doc/tinc

View file

@ -3,7 +3,7 @@
set -e
if [ "$IF_TINC_NET" ] ; then
tincctl -n "$IF_TINC_NET" stop
tinc -n "$IF_TINC_NET" stop
sleep 0.1
i=0;
while [ -f "/var/run/tinc.$IF_TINC_NET.pid" ] ; do

2
debian/tinc.init vendored
View file

@ -19,7 +19,7 @@
# Based on Lubomir Bulej's Redhat init script.
DAEMON="/usr/sbin/tincd"
CONTROL="/usr/sbin/tincctl"
CONTROL="/usr/sbin/tinc"
NAME="tinc"
DESC="tinc daemons"
TCONF="/etc/tinc"

4
debian/tinc.install vendored
View file

@ -1,6 +1,6 @@
usr/sbin/tincd
usr/sbin/tincctl
usr/sbin/tinc
usr/share/man/man5
usr/share/man/man8/tincd.*
usr/share/man/man8/tincctl.*
usr/share/man/man8/tinc.*
usr/share/info

View file

@ -2,11 +2,11 @@
info_TEXINFOS = tinc.texi
man_MANS = tincd.8 tincctl.8 tinc.conf.5 tinc-gui.8
man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8
EXTRA_DIST = tincinclude.texi.in tincd.8.in tincctl.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz
CLEANFILES = *.html tinc.info tincd.8 tincctl.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
CLEANFILES = *.html tinc.info tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
# Use `ginstall' in the definition of man_MANS to avoid
# confusion with the `install' target. The install rule transforms `ginstall'
@ -25,7 +25,7 @@ texi2html: tinc.texi
tincd.8.html: tincd.8
w3mman2html $? > $@
tincctl.8.html: tincctl.8
tinc.8.html: tinc.8
w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8
@ -43,7 +43,7 @@ substitute = sed \
tincd.8: tincd.8.in
$(substitute) $? > $@
tincctl.8: tincctl.8.in
tinc.8: tinc.8.in
$(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in

View file

@ -224,9 +224,9 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
info_TEXINFOS = tinc.texi
man_MANS = tincd.8 tincctl.8 tinc.conf.5 tinc-gui.8
EXTRA_DIST = tincinclude.texi.in tincd.8.in tincctl.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz
CLEANFILES = *.html tinc.info tincd.8 tincctl.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz
CLEANFILES = *.html tinc.info tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
-e s,'@VERSION\@',"$(VERSION)",g \
@ -772,7 +772,7 @@ texi2html: tinc.texi
tincd.8.html: tincd.8
w3mman2html $? > $@
tincctl.8.html: tincctl.8
tinc.8.html: tinc.8
w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8
@ -784,7 +784,7 @@ tinc.conf.5.html: tinc.conf.5
tincd.8: tincd.8.in
$(substitute) $? > $@
tincctl.8: tincctl.8.in
tinc.8: tinc.8.in
$(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in

View file

@ -3,7 +3,7 @@
.\" Manual page created by:
.\" Scott Lamb
.Sh NAME
.Nm tincctl
.Nm tinc
.Nd tinc VPN control
.Sh SYNOPSIS
.Nm
@ -51,12 +51,12 @@ Create initial configuration files and RSA and ECDSA keypairs with default lengt
If no
.Ar name
for this node is given, it will be asked for.
.It config Oo get Oc Ar variable
.It get Ar variable
Print the current value of configuration variable
.Ar variable .
If more than one variable with the same name exists,
the value of each of them will be printed on a separate line.
.It config Oo set Oc Ar variable Ar value
.It set Ar variable Ar value
Set configuration variable
.Ar variable
to the given
@ -64,9 +64,9 @@ to the given
All previously existing configuration variables with the same name are removed.
To set a variable for a specific host, use the notation
.Ar host Ns Li . Ns Ar variable .
.It config add Ar variable Ar value
.It add Ar variable Ar value
As above, but without removing any previously existing configuration variables.
.It config del Ar variable Op Ar value
.It del Ar variable Op Ar value
Remove configuration variables with the same name and
.Ar value .
If no
@ -147,7 +147,7 @@ Sets debug level to
.It log Op Ar N
Capture log messages from a running tinc daemon.
An optional debug level can be given that will be applied only for log messages sent to
.Nm tincctl .
.Nm tinc .
.It retry
Forces
.Xr tincd 8
@ -182,19 +182,19 @@ such as
.Sh EXAMPLES
Examples of some commands:
.Bd -literal -offset indent
tincctl -n vpn dump graph | circo -Txlib
tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top
tinc -n vpn dump graph | circo -Txlib
tinc -n vpn pcap | tcpdump -r -
tinc -n vpn top
.Pp
.Ed
Example of configuring tinc using
.Nm :
.Bd -literal -offset indent
tincctl -n vpn init foo
tincctl -n vpn config Subnet 192.168.1.0/24
tincctl -n vpn config bar.Address bar.example.com
tincctl -n vpn config ConnectTo bar
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
tinc -n vpn init foo
tinc -n vpn add Subnet 192.168.1.0/24
tinc -n vpn add bar.Address bar.example.com
tinc -n vpn add ConnectTo bar
tinc -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
.Ed
.Sh TOP
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.

View file

@ -55,15 +55,15 @@ However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-
.Sh INITIAL CONFIGURATION
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
.Bd -literal -offset indent
.Nm tincctl Fl n Ar NETNAME Li init Ar NAME
.Nm tinc Fl n Ar NETNAME Li init Ar NAME
.Ed
.Pp
You can further change the configuration as needed either by manually editing the configuration files,
or by using
.Xr tincctl 8 .
.Xr tinc 8 .
.Sh PUBLIC/PRIVATE KEYS
The
.Nm tincctl Li init
.Nm tinc Li init
command will have generated both RSA and ECDSA public/private keypairs.
The private keys should be stored in files named
.Pa rsa_key.priv
@ -77,7 +77,7 @@ The RSA keys are used for backwards compatibility with tinc version 1.0.
If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files,
but you will need to create ECDSA keys using the following command:
.Bd -literal -offset indent
.Nm tincctl Fl n Ar NETNAME Li generate-ecdsa-keys
.Nm tinc Fl n Ar NETNAME Li generate-ecdsa-keys
.Ed
.Sh SERVER CONFIGURATION
The server configuration of the daemon is done in the file
@ -102,7 +102,7 @@ it is recommended to put host specific configuration options in the host configu
as this makes it easy to exchange with other nodes.
.Pp
You can edit the config file manually, but it is recommended that you use
.Xr tincctl 8
.Xr tinc 8
to change configuration variables for you.
.Pp
Here are all valid variables, listed in alphabetical order.
@ -279,7 +279,7 @@ When this option is enabled, experimental protocol enhancements will be used.
Ephemeral ECDH will be used for key exchanges,
and ECDSA will be used instead of RSA for authentication.
When enabled, an ECDSA key must have been generated before with
.Nm tincctl generate-ecdsa-keys .
.Nm tinc generate-ecdsa-keys .
The experimental protocol may change at any time,
and there is no guarantee that tinc will run stable when it is used.
.It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
@ -482,6 +482,8 @@ Furthermore, specifying
.Qq none
will turn off packet encryption.
It is best to use only those ciphers which support CBC mode.
This option has no effect for connections between nodes using
.Va ExperimentalProtocol .
.It Va ClampMSS Li = yes | no Pq yes
This option specifies whether tinc should clamp the maximum segment size (MSS)
of TCP packets to the path MTU. This helps in situations where ICMP
@ -496,6 +498,8 @@ Any digest supported by OpenSSL is recognised.
Furthermore, specifying
.Qq none
will turn off packet authentication.
This option has no effect for connections between nodes using
.Va ExperimentalProtocol .
.It Va IndirectData Li = yes | no Pq no
When set to yes, other nodes which do not already have a meta connection to you
will not try to establish direct communication with you.
@ -505,6 +509,8 @@ The length of the message authentication code used to authenticate UDP packets.
Can be anything from
.Qq 0
up to the length of the digest produced by the digest algorithm.
This option has no effect for connections between nodes using
.Va ExperimentalProtocol .
.It Va PMTU Li = Ar mtu Po 1514 Pc
This option controls the initial path MTU to this node.
.It Va PMTUDiscovery Li = yes | no Po yes Pc
@ -653,7 +659,7 @@ its connection to the virtual network device.
.El
.Sh SEE ALSO
.Xr tincd 8 ,
.Xr tincctl 8 ,
.Xr tinc 8 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa http://www.tldp.org/LDP/nag2/ .
.Pp

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,10 @@ permission notice identical to this one.
@end ifinfo
@afourpaper
@paragraphindent none
@finalout
@titlepage
@title tinc Manual
@subtitle Setting up a Virtual Private Network with tinc
@ -462,7 +466,7 @@ default).
@subsection libcurses
@cindex libcurses
For the "tincctl top" command, tinc requires a curses library.
For the "tinc top" command, tinc requires a curses library.
If this library is not installed, you wil get an error when running the
configure script. You can either install a suitable curses library, or disable
@ -485,7 +489,7 @@ of this package.
@subsection libreadline
@cindex libreadline
For the "tincctl" command's shell functionality, tinc uses the readline library.
For the "tinc" command's shell functionality, tinc uses the readline library.
If this library is not installed, you wil get an error when running the
configure script. You can either install a suitable readline library, or
@ -696,12 +700,12 @@ If you have everything clearly pictured in your mind,
proceed in the following order:
First, create the initial configuration files and public/private keypairs using the following command:
@example
tincctl -n @var{NETNAME} init @var{NAME}
tinc -n @var{NETNAME} init @var{NAME}
@end example
Second, use @samp{tincctl -n @var{NETNAME} config ...} to further configure tinc.
Finally, export your host configuration file using @samp{tincctl -n @var{NETNAME} export} and send it to those
Second, use @samp{tinc -n @var{NETNAME} add ...} to further configure tinc.
Finally, export your host configuration file using @samp{tinc -n @var{NETNAME} export} and send it to those
people or computers you want tinc to connect to.
They should send you their host configuration file back, which you can import using @samp{tincctl -n @var{NETNAME} import}.
They should send you their host configuration file back, which you can import using @samp{tinc -n @var{NETNAME} import}.
These steps are described in the subsections below.
@ -721,7 +725,7 @@ it doesn't even have to be the same on all the nodes of your VPN,
but it is recommended that you choose one anyway.
We will asume you use a netname throughout this document.
This means that you call tincctl with the -n argument,
This means that you call tinc with the -n argument,
which will specify the netname.
The effect of this option is that tinc will set its configuration
@ -809,7 +813,7 @@ put host specific configuration options in the host configuration file, as this
makes it easy to exchange with other nodes.
You can edit the config file manually, but it is recommended that you use
tincctl to change configuration variables for you.
the tinc command to change configuration variables for you.
In the following two subsections all valid variables are listed in alphabetical order.
The default value is given between parentheses,
@ -1003,7 +1007,7 @@ When this option is enabled, experimental protocol enhancements will be used.
Ephemeral ECDH will be used for key exchanges,
and ECDSA will be used instead of RSA for authentication.
When enabled, an ECDSA key must have been generated before with
@samp{tincctl generate-ecdsa-keys}.
@samp{tinc generate-ecdsa-keys}.
The experimental protocol may change at any time,
and there is no guarantee that tinc will run stable when it is used.
@ -1130,7 +1134,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{tincctl generate-keys}. It must be a full path, not a
generated by @samp{tinc generate-keys}. It must be a full path, not a
relative directory.
@cindex ProcessPriority
@ -1217,10 +1221,11 @@ If no port is specified, the default Port is used.
@cindex Cipher
@item Cipher = <@var{cipher}> (blowfish)
The symmetric cipher algorithm used to encrypt UDP packets.
The symmetric cipher algorithm used to encrypt UDP packets using the legacy protocol.
Any cipher supported by OpenSSL is recognized.
Furthermore, specifying "none" will turn off packet encryption.
It is best to use only those ciphers which support CBC mode.
This option has no effect for connections using the SPTPS protocol, which always use AES-256-CTR.
@cindex ClampMSS
@item ClampMSS = <yes|no> (yes)
@ -1236,9 +1241,10 @@ Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
@cindex Digest
@item Digest = <@var{digest}> (sha1)
The digest algorithm used to authenticate UDP packets.
The digest algorithm used to authenticate UDP packets using the legacy protocol.
Any digest supported by OpenSSL is recognized.
Furthermore, specifying "none" will turn off packet authentication.
This option has no effect for connections using the SPTPS protocol, which always use HMAC-SHA-256.
@cindex IndirectData
@item IndirectData = <yes|no> (no)
@ -1248,9 +1254,10 @@ It is best to leave this option out or set it to no.
@cindex MACLength
@item MACLength = <@var{bytes}> (4)
The length of the message authentication code used to authenticate UDP packets.
The length of the message authentication code used to authenticate UDP packets using the legacy protocol.
Can be anything from 0
up to the length of the digest produced by the digest algorithm.
This option has no effect for connections using the SPTPS protocol, which never truncate MACs.
@cindex PMTU
@item PMTU = <@var{mtu}> (1514)
@ -1273,7 +1280,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{tincctl generate-keys}. It must be a full path, not a relative
by @samp{tinc generate-keys}. It must be a full path, not a relative
directory.
@cindex PEM format
@ -1421,7 +1428,7 @@ When a subnet becomes (un)reachable, this is set to the subnet.
The initial directory structure, configuration files and public/private keypairs are created using the following command:
@example
tincctl -n @var{netname} init @var{name}
tinc -n @var{netname} init @var{name}
@end example
(You will need to run this as root, or use "sudo".)
@ -1449,7 +1456,7 @@ and you yourself have a smaller portion of that range: 192.168.2.0/24.
Then you should run the following command:
@example
tincctl -n @var{netname} config add subnet 192.168.2.0/24
tinc -n @var{netname} add subnet 192.168.2.0/24
@end example
This will add a Subnet statement to your host configuration file.
@ -1465,18 +1472,18 @@ If you will use more than one address range, you can add more Subnets.
For example, if you also use the IPv6 subnet fec0:0:0:2::/64, you can add it as well:
@example
tincctl -n @var{netname} config add subnet fec0:0:0:2::/24
tinc -n @var{netname} add subnet fec0:0:0:2::/24
@end example
This will add another line to the file @file{hosts/@var{name}}.
If you make a mistake, you can undo it by simply using @samp{config del} instead of @samp{config add}.
If you make a mistake, you can undo it by simply using @samp{del} instead of @samp{add}.
If you want other tinc daemons to create meta-connections to your daemon,
you should add your public IP address or hostname to your host configuration file.
For example, if your hostname is foo.example.org, run:
@example
tincctl -n @var{netname} config add address foo.example.org
tinc -n @var{netname} add address foo.example.org
@end example
If you already know to which daemons your daemon should make meta-connections,
@ -1484,7 +1491,7 @@ you should configure that now as well.
Suppose you want to connect to a daemon named "bar", run:
@example
tincctl -n @var{netname} config add connectto bar
tinc -n @var{netname} add connectto bar
@end example
Note that you specify the Name of the other daemon here, not an IP address or hostname!
@ -1501,7 +1508,7 @@ If you are on a UNIX platform, you can easily send an email containing the neces
(assuming the owner of bar has the email address bar@@example.org):
@example
tincctl -n @var{netname} export | mail -s "My config file" bar@@example.org
tinc -n @var{netname} export | mail -s "My config file" bar@@example.org
@end example
If the owner of bar does the same to send his host configuration file to you,
@ -1509,16 +1516,16 @@ you can probably pipe his email through the following command,
or you can just start this command in a terminal and copy&paste the email:
@example
tincctl -n @var{netname} import
tinc -n @var{netname} import
@end example
If you are the owner of bar yourself, and you have SSH access to that computer,
you can also swap the host configuration files using the following command:
@example
tincctl -n @var{netname} export \
| ssh bar.example.org tincctl -n @var{netname} exchange \
| tincctl -n @var{netname} import
tinc -n @var{netname} export \
| ssh bar.example.org tinc -n @var{netname} exchange \
| tinc -n @var{netname} import
@end example
You should repeat this for all nodes you ConnectTo, or which ConnectTo you.
@ -1551,7 +1558,7 @@ When tinc starts, this script will be executed. When tinc exits, it will execute
You can manually open the script in an editor, or use the following command:
@example
tincctl -n @var{netname} edit tinc-up
tinc -n @var{netname} edit tinc-up
@end example
An example @file{tinc-up} script, that would be appropriate for the scenario in the previous section, is:
@ -1612,7 +1619,7 @@ the real interface is also shown as a comment, to give you an idea of
how these example host is set up. All branches use the netname `company'
for this particular VPN.
Each branch is set up using the @samp{tincctl init} and @samp{tincctl config} commands,
Each branch is set up using the @samp{tinc init} and @samp{tinc config} commands,
here we just show the end results:
@subsubheading For Branch A
@ -1783,7 +1790,7 @@ their daemons, tinc will try connecting until they are available.
If everything else is done, you can start tinc by typing the following command:
@example
tincctl -n @var{netname} start
tinc -n @var{netname} start
@end example
@cindex daemon
@ -1834,7 +1841,7 @@ Specifying . for @var{netname} is the same as not specifying any @var{netname}.
@xref{Multiple networks}.
@item --pidfile=@var{filename}
Store a cookie in @var{filename} which allows tincctl to authenticate.
Store a cookie in @var{filename} which allows tinc to authenticate.
If unspecified, the default is
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
@ -2108,25 +2115,25 @@ Be sure to include the following information in your bugreport:
@node Controlling tinc
@chapter Controlling tinc
You can control and inspect a running tincd through the tincctl
You can control and inspect a running tincd through the tinc
command. A quick example:
@example
tincctl -n @var{netname} reload
tinc -n @var{netname} reload
@end example
@menu
* tincctl runtime options::
* tincctl environment variables::
* tincctl commands::
* tincctl examples::
* tincctl top::
* tinc runtime options::
* tinc environment variables::
* tinc commands::
* tinc examples::
* tinc top::
@end menu
@c ==================================================================
@node tincctl runtime options
@section tincctl runtime options
@node tinc runtime options
@section tinc runtime options
@c from the manpage
@table @option
@ -2151,8 +2158,8 @@ Output version information and exit.
@end table
@c ==================================================================
@node tincctl environment variables
@section tincctl environment variables
@node tinc environment variables
@section tinc environment variables
@table @env
@cindex NETNAME
@ -2162,8 +2169,8 @@ the value of this environment variable is used.
@end table
@c ==================================================================
@node tincctl commands
@section tincctl commands
@node tinc commands
@section tinc commands
@c from the manpage
@table @code
@ -2172,20 +2179,20 @@ the value of this environment variable is used.
Create initial configuration files and RSA and ECDSA keypairs with default length.
If no @var{name} for this node is given, it will be asked for.
@item config [get] @var{variable}
@item get @var{variable}
Print the current value of configuration variable @var{variable}.
If more than one variable with the same name exists,
the value of each of them will be printed on a separate line.
@item config [set] @var{variable} @var{value}
@item set @var{variable} @var{value}
Set configuration variable @var{variable} to the given @var{value}.
All previously existing configuration variables with the same name are removed.
To set a variable for a specific host, use the notation @var{host}.@var{variable}.
@item config add @var{variable} @var{value}
@item add @var{variable} @var{value}
As above, but without removing any previously existing configuration variables.
@item config del @var{variable} [@var{value}]
@item del @var{variable} [@var{value}]
Remove configuration variables with the same name and @var{value}.
If no @var{value} is given, all configuration variables with the same name will be removed.
@ -2200,7 +2207,7 @@ Export the host configuration file of the local node to standard output.
Export all host configuration files to standard output.
@item import [--force]
Import host configuration file(s) generated by the tincctl export command from standard input.
Import host configuration file(s) generated by the tinc export command from standard input.
Already existing host configuration files are not overwritten unless the option --force is used.
@item exchange [--force]
@ -2263,7 +2270,7 @@ Sets debug level to @var{level}.
@item log [@var{level}]
Capture log messages from a running tinc daemon.
An optional debug level can be given that will be applied only for log messages sent to tincctl.
An optional debug level can be given that will be applied only for log messages sent to tinc.
@item retry
Forces tinc to try to connect to all uplinks immediately.
@ -2276,7 +2283,7 @@ it defaults to the maximum time of 15 minutes.
Closes the meta connection with the given @var{node}.
@item top
If tincctl is compiled with libcurses support, this will display live traffic statistics for all the known nodes,
If tinc is compiled with libcurses support, this will display live traffic statistics for all the known nodes,
similar to the UNIX top command.
See below for more information.
@ -2288,30 +2295,30 @@ such as tcpdump.
@end table
@c ==================================================================
@node tincctl examples
@section tincctl examples
@node tinc examples
@section tinc examples
Examples of some commands:
@example
tincctl -n vpn dump graph | circo -Txlib
tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top
tinc -n vpn dump graph | circo -Txlib
tinc -n vpn pcap | tcpdump -r -
tinc -n vpn top
@end example
Example of configuring tinc using tincctl:
Example of configuring tinc using the tinc command:
@example
tincctl -n vpn init foo
tincctl -n vpn config Subnet 192.168.1.0/24
tincctl -n vpn config bar.Address bar.example.com
tincctl -n vpn config ConnectTo bar
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
tinc -n vpn init foo
tinc -n vpn add Subnet 192.168.1.0/24
tinc -n vpn add bar.Address bar.example.com
tinc -n vpn add ConnectTo bar
tinc -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
@end example
@c ==================================================================
@node tincctl top
@section tincctl top
@node tinc top
@section tinc top
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
It displays a list of all the known nodes in the left-most column,
@ -2504,7 +2511,7 @@ daemon started with the --bypass-security option
and to read and write requests by hand, provided that one
understands the numeric codes sent.
The authentication scheme is described in @ref{Authentication protocol}. After a
The authentication scheme is described in @ref{Security}. After a
successful authentication, the server and the client will exchange all the
information about other tinc daemons and subnets they know of, so that both
sides (and all the other tinc daemons behind them) have their information
@ -2591,10 +2598,10 @@ destination.
@cindex PING
@cindex PONG
@example
daemon message
daemon message
------------------------------------------------------------------
origin PING
dest. PONG
origin PING
dest. PONG
------------------------------------------------------------------
@end example
@ -2622,31 +2629,30 @@ the tinc project after TINC.
@cindex SVPN
But in order to be ``immune'' to eavesdropping, you'll have to encrypt
your data. Because tinc is a @emph{Secure} VPN (SVPN) daemon, it does
your data. Because tinc is a @emph{Secure} VPN (SVPN) daemon, it does
exactly that: encrypt.
Tinc by default uses blowfish encryption with 128 bit keys in CBC mode, 32 bit
sequence numbers and 4 byte long message authentication codes to make sure
eavesdroppers cannot get and cannot change any information at all from the
packets they can intercept. The encryption algorithm and message authentication
algorithm can be changed in the configuration. The length of the message
authentication codes is also adjustable. The length of the key for the
encryption algorithm is always the default length used by OpenSSL.
However, encryption in itself does not prevent an attacker from modifying the encrypted data.
Therefore, tinc also authenticates the data.
Finally, tinc uses sequence numbers (which themselves are also authenticated) to prevent an attacker from replaying valid packets.
Since version 1.1pre3, tinc has two protocols used to protect your data; the legacy protocol, and the new Simple Peer-to-Peer Security (SPTPS) protocol.
The SPTPS protocol is designed to address some weaknesses in the legacy protocol.
The new authentication protocol is used when two nodes connect to each other that both have the ExperimentalProtocol option set to yes,
otherwise the legacy protocol will be used.
@menu
* Authentication protocol::
* Legacy authentication protocol::
* Simple Peer-to-Peer Security::
* Encryption of network packets::
* Security issues::
@end menu
@c ==================================================================
@node Authentication protocol
@subsection Authentication protocol
@node Legacy authentication protocol
@subsection Legacy authentication protocol
@cindex authentication
A new scheme for authentication in tinc has been devised, which offers some
improvements over the protocol used in 1.0pre2 and 1.0pre3. Explanation is
below.
@cindex legacy authentication protocol
@cindex ID
@cindex META_KEY
@ -2660,28 +2666,50 @@ client <attempts connection>
server <accepts connection>
client ID client 12
| +---> version
+-------> name of tinc daemon
client ID client 17.2
| | +-> minor protocol version
| +----> major protocol version
+--------> name of tinc daemon
server ID server 12
| +---> version
+-------> name of tinc daemon
server ID server 17.2
| | +-> minor protocol version
| +----> major protocol version
+--------> name of tinc daemon
client META_KEY 5f0823a93e35b69e...7086ec7866ce582b
\_________________________________/
+-> RSAKEYLEN bits totally random string S1,
encrypted with server's public RSA key
client META_KEY 94 64 0 0 5f0823a93e35b69e...7086ec7866ce582b
| | | | \_________________________________/
| | | | +-> RSAKEYLEN bits totally random string S1,
| | | | encrypted with server's public RSA key
| | | +-> compression level
| | +---> MAC length
| +------> digest algorithm NID
+---------> cipher algorithm NID
server META_KEY 6ab9c1640388f8f0...45d1a07f8a672630
\_________________________________/
+-> RSAKEYLEN bits totally random string S2,
encrypted with client's public RSA key
server META_KEY 94 64 0 0 6ab9c1640388f8f0...45d1a07f8a672630
| | | | \_________________________________/
| | | | +-> RSAKEYLEN bits totally random string S2,
| | | | encrypted with client's public RSA key
| | | +-> compression level
| | +---> MAC length
| +------> digest algorithm NID
+---------> cipher algorithm NID
--------------------------------------------------------------------------
@end example
The protocol allows each side to specify encryption algorithms and parameters,
but in practice they are always fixed, since older versions of tinc did not
allow them to be different from the default values. The cipher is always
Blowfish in OFB mode, the digest is SHA1, but the MAC length is zero and no
compression is used.
From now on:
- the client will symmetrically encrypt outgoing traffic using S1
- the server will symmetrically encrypt outgoing traffic using S2
@itemize
@item the client will symmetrically encrypt outgoing traffic using S1
@item the server will symmetrically encrypt outgoing traffic using S2
@end itemize
@example
--------------------------------------------------------------------------
client CHALLENGE da02add1817c1920989ba6ae2a49cecbda0
\_________________________________/
+-> CHALLEN bits totally random string H1
@ -2701,57 +2729,188 @@ their identity. Further information is exchanged.
client ACK 655 123 0
| | +-> options
| +----> estimated weight
+--------> listening port of client
| +----> estimated weight
+--------> listening port of client
server ACK 655 321 0
| | +-> options
| +----> estimated weight
+--------> listening port of server
| +----> estimated weight
+--------> listening port of server
--------------------------------------------------------------------------
@end example
This new scheme has several improvements, both in efficiency and security.
This legacy authentication protocol has several weaknesses, pointed out by security export Peter Gutmann.
First, data is encrypted with RSA without padding.
Padding schemes are designed to prevent attacks when the size of the plaintext is not equal to the size of the RSA key.
Tinc always encrypts random nonces that have the same size as the RSA key, so we do not believe this leads to a break of the security.
There might be timing or other side-channel attacks against RSA encryption and decryption, tinc does not employ any protection against those.
Furthermore, both sides send identical messages to each other, there is no distinction between server and client,
which could make a MITM attack easier.
However, no exploit is known in which a third party who is not already trusted by other nodes in the VPN could gain access.
Finally, the RSA keys are used to directly encrypt the session keys, which means that if the RSA keys are compromised, it is possible to decrypt all previous VPN traffic.
In other words, the legacy protocol does not provide perfect forward secrecy.
First of all, the server sends exactly the same kind of messages over the wire
as the client. The previous versions of tinc first authenticated the client,
and then the server. This scheme even allows both sides to send their messages
simultaneously, there is no need to wait for the other to send something first.
This means that any calculations that need to be done upon sending or receiving
a message can also be done in parallel. This is especially important when doing
RSA encryption/decryption. Given that these calculations are the main part of
the CPU time spent for the authentication, speed is improved by a factor 2.
@c ==================================================================
@node Simple Peer-to-Peer Security
@subsection Simple Peer-to-Peer Security
@cindex SPTPS
Second, only one RSA encrypted message is sent instead of two. This reduces the
amount of information attackers can see (and thus use for a cryptographic
attack). It also improves speed by a factor two, making the total speedup a
factor 4.
The SPTPS protocol is designed to address the weaknesses in the legacy protocol.
SPTPS is based on TLS 1.2, but has been simplified: there is no support for exchanging public keys, and there is no cipher suite negotiation.
Instead, SPTPS always uses a very strong cipher suite:
peers authenticate each other using 521 bits ECC keys,
Diffie-Hellman using ephemeral 521 bits ECC keys is used to provide perfect forward secrecy (PFS),
AES-256-CTR is used for encryption, and HMAC-SHA-256 for message authentication.
Third, and most important:
The symmetric cipher keys are exchanged first, the challenge is done
afterwards. In the previous authentication scheme, because a man-in-the-middle
could pass the challenge/chal_reply phase (by just copying the messages between
the two real tinc daemons), but no information was exchanged that was really
needed to read the rest of the messages, the challenge/chal_reply phase was of
no real use. The man-in-the-middle was only stopped by the fact that only after
the ACK messages were encrypted with the symmetric cipher. Potentially, it
could even send it's own symmetric key to the server (if it knew the server's
public key) and read some of the metadata the server would send it (it was
impossible for the mitm to read actual network packets though). The new scheme
however prevents this.
Similar to TLS, messages are split up in records.
A complete logical record contains the following information:
This new scheme makes sure that first of all, symmetric keys are exchanged. The
rest of the messages are then encrypted with the symmetric cipher. Then, each
side can only read received messages if they have their private key. The
challenge is there to let the other side know that the private key is really
known, because a challenge reply can only be sent back if the challenge is
decrypted correctly, and that can only be done with knowledge of the private
key.
@itemize
@item uint32_t seqno (network byte order)
@item uint16_t length (network byte order)
@item uint8_t type
@item opaque data[length]
@item opaque hmac[HMAC_SIZE] (HMAC over all preceding fields)
@end itemize
Fourth: the first thing that is sent via the symmetric cipher encrypted
connection is a totally random string, so that there is no known plaintext (for
an attacker) in the beginning of the encrypted stream.
Depending on whether SPTPS records are sent via TCP or UDP, either the seqno or the length field is omitted on the wire
(but they are still included in the calculation of the HMAC);
for TCP packets are guaranteed to arrive in-order so we can infer the seqno, but packets can be split or merged, so we still need the length field to determine the boundaries between records;
for UDP packets we know that there is exactly one record per packet, and we know the length of a packet, but packets can be dropped, duplicated and/or reordered, so we need to include the seqno.
The type field is used to distinguish between application records or handshake records.
Types 0 to 127 are application records, type 128 is a handshake record, and types 129 to 255 are reserved.
Before the initial handshake, no fields are encrypted, and the HMAC field is not present.
After the authentication handshake, the length (if present), type and data fields are encrypted, and the HMAC field is present.
For UDP packets, the seqno field is not encrypted, as it is used to determine the value of the counter used for encryption.
The authentication consists of an exchange of Key EXchange, SIGnature and ACKnowledge messages, transmitted using type 128 records.
Overview:
@example
Initiator Responder
---------------------
KEX ->
<- KEX
SIG ->
<- SIG
...encrypt and HMAC using session keys from now on...
App ->
<- App
...
...
...key renegotiation starts here...
KEX ->
<- KEX
SIG ->
<- SIG
ACK ->
<- ACK
...encrypt and HMAC using new session keys from now on...
App ->
<- App
...
...
---------------------
@end example
Note that the responder does not need to wait before it receives the first KEX message,
it can immediately send its own once it has accepted an incoming connection.
Key EXchange message:
@itemize
@item uint8_t kex_version (always 0 in this version of SPTPS)
@item opaque nonce[32] (random number)
@item opaque ecdh_key[ECDH_SIZE]
@end itemize
SIGnature message:
@itemize
@item opaque ecdsa_signature[ECDSA_SIZE]
@end itemize
ACKnowledge message:
@itemize
@item empty (only sent after key renegotiation)
@end itemize
Remarks:
@itemize
@item At the start, both peers generate a random nonce and an Elliptic Curve public key and send it to the other in the KEX message.
@item After receiving the other's KEX message, both KEX messages are concatenated (see below),
and the result is signed using ECDSA.
The result is sent to the other.
@item After receiving the other's SIG message, the signature is verified.
If it is correct, the shared secret is calculated from the public keys exchanged in the KEX message using the Elliptic Curve Diffie-Helman algorithm.
@item The shared secret key is expanded using a PRF.
Both nonces and the application specific label are also used as input for the PRF.
@item An ACK message is sent only when doing key renegotiation, and is sent using the old encryption keys.
@item The expanded key is used to key the encryption and HMAC algorithms.
@end itemize
The signature is calculated over this string:
@itemize
@item uint8_t initiator (0 = local peer, 1 = remote peer is initiator)
@item opaque remote_kex_message[1 + 32 + ECDH_SIZE]
@item opaque local_kex_message[1 + 32 + ECDH_SIZE]
@item opaque label[label_length]
@end itemize
The PRF is calculated as follows:
@itemize
@item A HMAC using SHA512 is used, the shared secret is used as the key.
@item For each block of 64 bytes, a HMAC is calculated. For block n: hmac[n] =
HMAC_SHA512(hmac[n - 1] + seed)
@item For the first block (n = 1), hmac[0] is given by HMAC_SHA512(zeroes + seed),
where zeroes is a block of 64 zero bytes.
@end itemize
The seed is as follows:
@itemize
@item const char[13] "key expansion"
@item opaque responder_nonce[32]
@item opaque initiator_nonce[32]
@item opaque label[label_length]
@end itemize
The expanded key is used as follows:
@itemize
@item opaque responder_cipher_key[CIPHER_KEYSIZE]
@item opaque responder_digest_key[DIGEST_KEYSIZE]
@item opaque initiator_cipher_key[CIPHER_KEYSIZE]
@item opaque initiator_digest_key[DIGEST_KEYSIZE]
@end itemize
Where initiator_cipher_key is the key used by session initiator to encrypt
messages sent to the responder.
When using 521 bits EC keys, the AES-256-CTR cipher and HMAC-SHA-256 digest algorithm,
the sizes are as follows:
@example
ECDH_SIZE: 67 (= ceil(521/8) + 1)
ECDSA_SIZE: 141 (= 2 * ceil(521/8) + 9)
CIPHER_KEYSIZE: 48 (= 256/8 + 128/8)
DIGEST_KEYSIZE: 32 (= 256/8)
@end example
Note that the cipher key also includes the initial value for the counter.
@c ==================================================================
@node Encryption of network packets
@ -2761,11 +2920,11 @@ an attacker) in the beginning of the encrypted stream.
A data packet can only be sent if the encryption key is known to both
parties, and the connection is activated. If the encryption key is not
known, a request is sent to the destination using the meta connection
to retrieve it. The packet is stored in a queue while waiting for the
key to arrive.
to retrieve it.
@cindex UDP
The UDP packet containing the network packet from the VPN has the following layout:
The UDP packets can be either encrypted with the legacy protocol or with SPTPS.
In case of the legacy protocol, the UDP packet containing the network packet from the VPN has the following layout:
@example
... | IP header | UDP header | seqno | VPN packet | MAC | UDP trailer
@ -2775,12 +2934,38 @@ The UDP packet containing the network packet from the VPN has the following layo
Encrypted with symmetric cipher
@end example
So, the entire VPN packet is encrypted using a symmetric cipher, including a 32 bits
sequence number that is added in front of the actual VPN packet, to act as a unique
IV for each packet and to prevent replay attacks. A message authentication code
is added to the UDP packet to prevent alteration of packets. By default the
first 4 bytes of the digest are used for this, but this can be changed using
the MACLength configuration variable.
is added to the UDP packet to prevent alteration of packets.
Tinc by default encrypts network packets using Blowfish with 128 bit keys in CBC mode
and uses 4 byte long message authentication codes to make sure
eavesdroppers cannot get and cannot change any information at all from the
packets they can intercept. The encryption algorithm and message authentication
algorithm can be changed in the configuration. The length of the message
authentication codes is also adjustable. The length of the key for the
encryption algorithm is always the default length used by OpenSSL.
The SPTPS protocol is described in @ref{Simple Peer-to-Peer Security}.
For comparison, this is how SPTPS UDP packets look:
@example
... | IP header | UDP header | seqno | type | VPN packet | MAC | UDP trailer
\__________________/\_____/
| |
V +---> digest algorithm
Encrypted with symmetric cipher
@end example
The difference is that the seqno is not encrypted, since the encryption cipher is used in CTR mode,
and therefore the seqno must be known before the packet can be decrypted.
Furthermore, the MAC is never truncated.
The SPTPS protocol always uses the AES-256-CTR cipher and HMAC-SHA-256 digest,
this cannot be changed.
@c ==================================================================
@node Security issues
@ -2803,8 +2988,10 @@ On the 15th of September 2003, Peter Gutmann posted a security analysis of tinc
1.0.1. He argues that the 32 bit sequence number used by tinc is not a good IV,
that tinc's default length of 4 bytes for the MAC is too short, and he doesn't
like tinc's use of RSA during authentication. We do not know of a security hole
in this version of tinc, but tinc's security is not as strong as TLS or IPsec.
We will address these issues in tinc 2.0.
in the legacy protocol of tinc, but it is not as strong as TLS or IPsec.
This version of tinc comes with an improved protocol, called Simple Peer-to-Peer Security,
which aims to be as strong as TLS with one of the strongest cipher suites.
Cryptography is a hard thing to get right. We cannot make any
guarantees. Time, review and feedback are the only things that can

View file

@ -92,7 +92,7 @@ is omitted, the default is
Store a cookie in
.Ar FILENAME
which allows
.Xr tincctl 8
.Xr tinc 8
to authenticate.
If
.Ar FILE
@ -186,7 +186,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 8 ,
.Xr tinc.conf 5 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa http://www.cabal.org/ .

View file

@ -1,6 +1,6 @@
## Produce this file with automake to get Makefile.in
sbin_PROGRAMS = tincd tincctl sptps_test
sbin_PROGRAMS = tincd tinc sptps_test
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
@ -22,11 +22,11 @@ endif
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
tinc_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
info.c list.c subnet_parse.c tincctl.c top.c names.c
nodist_tincctl_SOURCES = \
nodist_tinc_SOURCES = \
ecdsagen.c rsagen.c
sptps_test_SOURCES = \
@ -37,7 +37,7 @@ if TUNEMU
tincd_SOURCES += bsd/tunemu.c
endif
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =

View file

@ -52,7 +52,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sptps_test$(EXEEXT)
sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
@UML_TRUE@am__append_1 = uml_device.c
@VDE_TRUE@am__append_2 = vde_device.c
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c
@ -79,14 +79,14 @@ am_sptps_test_OBJECTS = logger.$(OBJEXT) cipher.$(OBJEXT) \
sptps_test.$(OBJEXT) utils.$(OBJEXT)
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
sptps_test_LDADD = $(LDADD)
am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
top.$(OBJEXT) names.$(OBJEXT)
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
am_tinc_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
dropin.$(OBJEXT) info.$(OBJEXT) list.$(OBJEXT) \
subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) top.$(OBJEXT) \
names.$(OBJEXT)
nodist_tinc_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tinc_OBJECTS = $(am_tinc_OBJECTS) $(nodist_tinc_OBJECTS)
am__DEPENDENCIES_1 =
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
tinc_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
hash.c buffer.c conf.c connection.c control.c edge.c graph.c \
@ -128,10 +128,9 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
$(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
$(nodist_tincd_SOURCES)
DIST_SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) $(nodist_tinc_SOURCES) \
$(tincd_SOURCES) $(nodist_tincd_SOURCES)
DIST_SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) \
$(am__tincd_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
@ -258,18 +257,18 @@ tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
tinc_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
info.c list.c subnet_parse.c tincctl.c top.c names.c
nodist_tincctl_SOURCES = \
nodist_tinc_SOURCES = \
ecdsagen.c rsagen.c
sptps_test_SOURCES = \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
sptps.c sptps_test.c utils.c
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =
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 ipv6.h ipv4.h ethernet.h \
@ -357,9 +356,9 @@ clean-sbinPROGRAMS:
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
@rm -f sptps_test$(EXEEXT)
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES) $(EXTRA_tincctl_DEPENDENCIES)
@rm -f tincctl$(EXEEXT)
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS)
tinc$(EXEEXT): $(tinc_OBJECTS) $(tinc_DEPENDENCIES) $(EXTRA_tinc_DEPENDENCIES)
@rm -f tinc$(EXEEXT)
$(LINK) $(tinc_OBJECTS) $(tinc_LDADD) $(LIBS)
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
@rm -f tincd$(EXEEXT)
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)

View file

@ -245,6 +245,12 @@ bool event_loop(void) {
return true;
}
void event_flush_output(void) {
for splay_each(io_t, io, &io_tree)
if(FD_ISSET(io->fd, &writefds))
io->cb(io->data, IO_WRITE);
}
void event_exit(void) {
running = false;
}

View file

@ -65,6 +65,7 @@ extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
extern void signal_del(signal_t *sig);
extern bool event_loop(void);
extern void event_flush_output(void);
extern void event_exit(void);
#endif

View file

@ -204,7 +204,7 @@ static void check_reachability(void) {
for splay_each(node_t, n, node_tree) {
if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable;
n->last_state_change = time(NULL);
n->last_state_change = now.tv_sec;
if(n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",

View file

@ -80,6 +80,7 @@ static DWORD WINAPI tapreader(void *bla) {
packet.len = len;
packet.priority = 0;
route(myself, &packet);
event_flush_output();
LeaveCriticalSection(&mutex);
}
}

View file

@ -406,7 +406,7 @@ int reload_configuration(void) {
free(fname);
}
last_config_check = time(NULL);
last_config_check = now.tv_sec;
return 0;
}

View file

@ -135,6 +135,7 @@ extern int udp_sndbuf;
extern bool do_prune;
extern char *myport;
extern int autoconnect;
extern bool disablebuggypeers;
extern int contradicting_add_edge;
extern int contradicting_del_edge;
extern time_t last_config_check;

View file

@ -443,6 +443,9 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
vpn_packet_t outpkt;
if(len > sizeof outpkt.data)
return;
outpkt.len = len;
if(c->options & OPTION_TCPONLY)
outpkt.priority = 0;
@ -458,7 +461,7 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
if(!n->status.waitingforkey)
send_req_key(n);
else if(n->last_req_key + 10 < time(NULL)) {
else if(n->last_req_key + 10 < now.tv_sec) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;

View file

@ -52,6 +52,7 @@ char *proxyuser;
char *proxypass;
proxytype_t proxytype;
int autoconnect;
bool disablebuggypeers;
char *scriptinterpreter;
char *scriptextension;
@ -598,6 +599,8 @@ bool setup_myself_reloadable(void) {
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
get_config_bool(lookup_config(config_tree, "DisableBuggyPeers"), &disablebuggypeers);
return true;
}
@ -751,7 +754,7 @@ static bool setup_myself(void) {
myself->nexthop = myself;
myself->via = myself;
myself->status.reachable = true;
myself->last_state_change = time(NULL);
myself->last_state_change = now.tv_sec;
myself->status.sptps = experimental;
node_add(myself);
@ -958,7 +961,7 @@ static bool setup_myself(void) {
return false;
}
last_config_check = time(NULL);
last_config_check = now.tv_sec;
return true;
}

View file

@ -294,7 +294,7 @@ void retry_outgoing(outgoing_t *outgoing) {
void finish_connecting(connection_t *c) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
c->status.connecting = false;
send_id(c);
@ -349,6 +349,9 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
}
static void handle_meta_write(connection_t *c) {
if(c->outbuf.len <= c->outbuf.offset)
return;
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
if(outlen <= 0) {
if(!errno || errno == EPIPE) {
@ -505,7 +508,7 @@ begin:
c->outdigest = myself->connection->outdigest;
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
connection_add(c);
@ -568,7 +571,7 @@ void handle_new_meta_connection(void *data, int flags) {
c->address = sa;
c->hostname = sockaddr2hostname(&sa);
c->socket = fd;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
@ -607,7 +610,7 @@ void handle_new_unix_connection(void *data, int flags) {
c->address = sa;
c->hostname = xstrdup("localhost port unix");
c->socket = fd;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);

View file

@ -195,7 +195,7 @@ bool seen_request(const char *request) {
} else {
new = xmalloc(sizeof *new);
new->request = xstrdup(request);
new->firstseen = time(NULL);
new->firstseen = now.tv_sec;
splay_insert(past_request_tree, new);
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
return false;

View file

@ -160,7 +160,7 @@ bool id_h(connection_t *c, const char *request) {
if(name[0] == '^' && !strcmp(name + 1, controlcookie)) {
c->status.control = true;
c->allow_request = CONTROL;
c->last_ping_time = time(NULL) + 3600;
c->last_ping_time = now.tv_sec + 3600;
free(c->name);
c->name = xstrdup("<control>");
@ -510,6 +510,17 @@ bool send_ack(connection_t *c) {
static void send_everything(connection_t *c) {
/* Send all known subnets and edges */
if(disablebuggypeers) {
static struct {
vpn_packet_t pkt;
char pad[MAXBUFSIZE - MAXSIZE];
} zeropkt;
memset(&zeropkt, 0, sizeof zeropkt);
zeropkt.pkt.len = MAXBUFSIZE;
send_tcppacket(c, &zeropkt.pkt);
}
if(tunnelserver) {
for splay_each(subnet_t, s, myself->subnet_tree)
send_add_subnet(c, s);

View file

@ -111,7 +111,7 @@ bool send_req_key(node_t *to) {
sptps_stop(&to->sptps);
to->status.validkey = false;
to->status.waitingforkey = true;
to->last_req_key = time(NULL);
to->last_req_key = now.tv_sec;
to->incompression = myself->incompression;
return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof label, send_initial_sptps_data, receive_sptps_record);
}
@ -169,7 +169,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
sptps_stop(&from->sptps);
from->status.validkey = false;
from->status.waitingforkey = true;
from->last_req_key = time(NULL);
from->last_req_key = now.tv_sec;
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
sptps_receive_data(&from->sptps, buf, len);
return true;

View file

@ -89,7 +89,7 @@ bool termreq_h(connection_t *c, const char *request) {
bool send_ping(connection_t *c) {
c->status.pinged = true;
c->last_ping_time = time(NULL);
c->last_ping_time = now.tv_sec;
return send_request(c, "%d", PING);
}

View file

@ -229,7 +229,7 @@ static void learn_mac(mac_t *address) {
subnet = new_subnet();
subnet->type = SUBNET_MAC;
subnet->expires = time(NULL) + macexpire;
subnet->expires = now.tv_sec + macexpire;
subnet->net.mac.address = *address;
subnet->weight = 10;
subnet_add(myself, subnet);
@ -244,7 +244,7 @@ static void learn_mac(mac_t *address) {
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
} else {
if(subnet->expires)
subnet->expires = time(NULL) + macexpire;
subnet->expires = now.tv_sec + macexpire;
}
}

View file

@ -77,8 +77,8 @@ int main(int argc, char *argv[]) {
memset(&hint, 0, sizeof hint);
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
hint.ai_socktype = datagram ? SOCK_DGRAM : SOCK_STREAM;
hint.ai_protocol = datagram ? IPPROTO_UDP : IPPROTO_TCP;
hint.ai_flags = initiator ? 0 : AI_PASSIVE;
if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
return 1;
}
int sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sock < 0) {
fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
return 1;
@ -106,16 +106,35 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
return 1;
}
if(listen(sock, 1)) {
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
return 1;
}
fprintf(stderr, "Listening...\n");
sock = accept(sock, NULL, NULL);
if(sock < 0) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
if(!datagram) {
if(listen(sock, 1)) {
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
return 1;
}
fprintf(stderr, "Listening...\n");
sock = accept(sock, NULL, NULL);
if(sock < 0) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
}
} else {
fprintf(stderr, "Listening...\n");
char buf[65536];
struct sockaddr addr;
socklen_t addrlen = sizeof addr;
if(recvfrom(sock, buf, sizeof buf, MSG_PEEK, &addr, &addrlen) <= 0) {
fprintf(stderr, "Could not read from socket: %s\n", strerror(errno));
return 1;
}
if(connect(sock, &addr, addrlen)) {
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
return 1;
}
}
fprintf(stderr, "Connected\n");

View file

@ -112,11 +112,10 @@ static void usage(bool status) {
"\n"
"Valid commands are:\n"
" init [name] Create initial configuration files.\n"
" config Change configuration:\n"
" [get] VARIABLE - print current value of VARIABLE\n"
" [set] VARIABLE VALUE - set VARIABLE to VALUE\n"
" add VARIABLE VALUE - add VARIABLE with the given VALUE\n"
" del VARIABLE [VALUE] - remove VARIABLE [only ones with watching VALUE]\n"
" get VARIABLE Print current value of VARIABLE\n"
" set VARIABLE VALUE Set VARIABLE to VALUE\n"
" add VARIABLE VALUE Add VARIABLE with the given VALUE\n"
" del VARIABLE [VALUE] Remove VARIABLE [only ones with watching VALUE]\n"
" start [tincd options] Start tincd.\n"
" stop Stop tincd.\n"
" restart Restart tincd.\n"
@ -1148,7 +1147,7 @@ static int cmd_top(int argc, char *argv[]) {
top(fd);
return 0;
#else
fprintf(stderr, "This version of tincctl was compiled without support for the curses library.\n");
fprintf(stderr, "This version of tinc was compiled without support for the curses library.\n");
return 1;
#endif
}
@ -1199,10 +1198,11 @@ static int rstrip(char *value) {
return len;
}
static char *get_my_name() {
static char *get_my_name(bool verbose) {
FILE *f = fopen(tinc_conf, "r");
if(!f) {
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
if(verbose)
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
return NULL;
}
@ -1228,7 +1228,8 @@ static char *get_my_name() {
}
fclose(f);
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
if(verbose)
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
return NULL;
}
@ -1309,6 +1310,9 @@ static int cmd_config(int argc, char *argv[]) {
return 1;
}
if(strcasecmp(argv[0], "config"))
argv--, argc++;
int action = -2;
if(!strcasecmp(argv[1], "get")) {
argv++, argc--;
@ -1402,7 +1406,7 @@ static int cmd_config(int argc, char *argv[]) {
/* Should this go into our own host config file? */
if(!node && !(variables[i].type & VAR_SERVER)) {
node = get_my_name();
node = get_my_name(true);
if(!node)
return 1;
}
@ -1692,6 +1696,9 @@ static int cmd_generate_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ecdsa_keygen(true));
}
@ -1701,6 +1708,9 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
}
@ -1710,6 +1720,9 @@ static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
return 1;
}
if(!name)
name = get_my_name(false);
return !ecdsa_keygen(true);
}
@ -1831,7 +1844,7 @@ static int cmd_export(int argc, char *argv[]) {
return 1;
}
char *name = get_my_name();
char *name = get_my_name(true);
if(!name)
return 1;
@ -1961,6 +1974,7 @@ static int cmd_exchange_all(int argc, char *argv[]) {
static const struct {
const char *command;
int (*function)(int argc, char *argv[]);
bool hidden;
} commands[] = {
{"start", cmd_start},
{"stop", cmd_stop},
@ -1976,7 +1990,11 @@ static const struct {
{"pcap", cmd_pcap},
{"log", cmd_log},
{"pid", cmd_pid},
{"config", cmd_config},
{"config", cmd_config, true},
{"add", cmd_config},
{"del", cmd_config},
{"get", cmd_config},
{"set", cmd_config},
{"init", cmd_init},
{"generate-keys", cmd_generate_keys},
{"generate-rsa-keys", cmd_generate_rsa_keys},
@ -2003,7 +2021,7 @@ static char *complete_command(const char *text, int state) {
i++;
while(commands[i].command) {
if(!strncasecmp(commands[i].command, text, strlen(text)))
if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text)))
return xstrdup(commands[i].command);
i++;
}
@ -2030,42 +2048,24 @@ static char *complete_dump(const char *text, int state) {
}
static char *complete_config(const char *text, int state) {
const char *sub[] = {"get", "set", "add", "del"};
static int i;
if(!state) {
i = 0;
if(!strchr(rl_line_buffer + 7, ' '))
i = -4;
else {
bool found = false;
for(int i = 0; i < 4; i++) {
if(!strncasecmp(rl_line_buffer + 7, sub[i], strlen(sub[i])) && rl_line_buffer[7 + strlen(sub[i])] == ' ') {
found = true;
break;
}
}
if(!found)
return NULL;
}
} else {
i++;
}
while(i < 0 || variables[i].name) {
if(i < 0 && !strncasecmp(sub[i + 4], text, strlen(text)))
return xstrdup(sub[i + 4]);
if(i >= 0) {
char *dot = strchr(text, '.');
if(dot) {
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
char *match;
xasprintf(&match, "%.*s.%s", dot - text, text, variables[i].name);
return match;
}
} else {
if(!strncasecmp(variables[i].name, text, strlen(text)))
return xstrdup(variables[i].name);
if(!state)
i = 0;
else
i++;
while(variables[i].name) {
char *dot = strchr(text, '.');
if(dot) {
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
char *match;
xasprintf(&match, "%.*s.%s", dot - text, text, variables[i].name);
return match;
}
} else {
if(!strncasecmp(variables[i].name, text, strlen(text)))
return xstrdup(variables[i].name);
}
i++;
}
@ -2118,7 +2118,13 @@ static char **completion (const char *text, int start, int end) {
matches = rl_completion_matches(text, complete_command);
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
matches = rl_completion_matches(text, complete_dump);
else if(!strncasecmp(rl_line_buffer, "config ", 7))
else if(!strncasecmp(rl_line_buffer, "add ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "del ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "get ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "set ", 4))
matches = rl_completion_matches(text, complete_config);
else if(!strncasecmp(rl_line_buffer, "info ", 5))
matches = rl_completion_matches(text, complete_info);

View file

@ -346,7 +346,8 @@ int main(int argc, char **argv) {
/* Slllluuuuuuurrrrp! */
srand(time(NULL));
gettimeofday(&now, NULL);
srand(now.tv_sec + now.tv_usec);
crypto_init();
if(!read_server_config())