Import Upstream version 1.1~pre7
This commit is contained in:
parent
26033edb96
commit
2ebbac3278
36 changed files with 1358 additions and 860 deletions
2
COPYING
2
COPYING
|
@ -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.
|
See the AUTHORS file for a complete list.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
|
17
ChangeLog
17
ChangeLog
|
@ -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
|
Version 1.1pre6 February 20 2013
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ SUBDIRS = m4 src doc gui
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
EXTRA_DIST = have.h system.h COPYING.README
|
EXTRA_DIST = have.h system.h COPYING.README README.android
|
||||||
|
|
||||||
ChangeLog:
|
ChangeLog:
|
||||||
git log > ChangeLog
|
git log > ChangeLog
|
||||||
|
|
|
@ -236,7 +236,7 @@ top_srcdir = @top_srcdir@
|
||||||
AUTOMAKE_OPTIONS = gnu
|
AUTOMAKE_OPTIONS = gnu
|
||||||
SUBDIRS = m4 src doc gui
|
SUBDIRS = m4 src doc gui
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
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
|
all: config.h
|
||||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||||
|
|
||||||
|
|
14
NEWS
14
NEWS
|
@ -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
|
Version 1.1pre6 February 20 2013
|
||||||
|
|
||||||
* Fixed tincd exitting immediately on Windows.
|
* Fixed tincd exitting immediately on Windows.
|
||||||
|
|
10
README
10
README
|
@ -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.
|
instructions may be found in the INSTALL file.
|
||||||
|
|
||||||
tinc is Copyright (C) 1998-2013 by:
|
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.
|
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
|
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.
|
protocol is not fixed yet.
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@ at your own risk.
|
||||||
Compatibility
|
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.
|
versions of tinc.
|
||||||
|
|
||||||
When the ExperimentalProtocol option is used, tinc is still compatible with
|
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
|
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,
|
restart after reboots. To prevent tinc from detaching or running as a service,
|
||||||
use the -D option.
|
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
|
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.
|
easy to start and stop tinc, and to change its configuration.
|
||||||
|
|
20
README.android
Normal file
20
README.android
Normal 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
1
THANKS
|
@ -30,6 +30,7 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Mark Glines
|
* Mark Glines
|
||||||
* Markus Goetz
|
* Markus Goetz
|
||||||
* Martin Kihlgren
|
* Martin Kihlgren
|
||||||
|
* Martin Schobert
|
||||||
* Martin Schürrer
|
* Martin Schürrer
|
||||||
* Matias Carrasco
|
* Matias Carrasco
|
||||||
* Max Rijevski
|
* Max Rijevski
|
||||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -4095,7 +4095,7 @@ fi
|
||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE=tinc
|
PACKAGE=tinc
|
||||||
VERSION=1.1pre6
|
VERSION=1.1pre7
|
||||||
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
|
|
@ -4,7 +4,7 @@ AC_PREREQ(2.61)
|
||||||
AC_INIT
|
AC_INIT
|
||||||
AC_CONFIG_SRCDIR([src/tincd.c])
|
AC_CONFIG_SRCDIR([src/tincd.c])
|
||||||
AC_GNU_SOURCE
|
AC_GNU_SOURCE
|
||||||
AM_INIT_AUTOMAKE(tinc, 1.1pre6)
|
AM_INIT_AUTOMAKE(tinc, 1.1pre7)
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
info_TEXINFOS = tinc.texi
|
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
|
# Use `ginstall' in the definition of man_MANS to avoid
|
||||||
# confusion with the `install' target. The install rule transforms `ginstall'
|
# confusion with the `install' target. The install rule transforms `ginstall'
|
||||||
|
@ -25,7 +25,7 @@ texi2html: tinc.texi
|
||||||
tincd.8.html: tincd.8
|
tincd.8.html: tincd.8
|
||||||
w3mman2html $? > $@
|
w3mman2html $? > $@
|
||||||
|
|
||||||
tincctl.8.html: tincctl.8
|
tinc.8.html: tinc.8
|
||||||
w3mman2html $? > $@
|
w3mman2html $? > $@
|
||||||
|
|
||||||
tinc-gui.8.html: tinc-gui.8
|
tinc-gui.8.html: tinc-gui.8
|
||||||
|
@ -43,7 +43,7 @@ substitute = sed \
|
||||||
tincd.8: tincd.8.in
|
tincd.8: tincd.8.in
|
||||||
$(substitute) $? > $@
|
$(substitute) $? > $@
|
||||||
|
|
||||||
tincctl.8: tincctl.8.in
|
tinc.8: tinc.8.in
|
||||||
$(substitute) $? > $@
|
$(substitute) $? > $@
|
||||||
|
|
||||||
tinc-gui.8: tinc-gui.8.in
|
tinc-gui.8: tinc-gui.8.in
|
||||||
|
|
|
@ -224,9 +224,9 @@ top_build_prefix = @top_build_prefix@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
info_TEXINFOS = tinc.texi
|
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
|
||||||
substitute = sed \
|
substitute = sed \
|
||||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||||
-e s,'@VERSION\@',"$(VERSION)",g \
|
-e s,'@VERSION\@',"$(VERSION)",g \
|
||||||
|
@ -772,7 +772,7 @@ texi2html: tinc.texi
|
||||||
tincd.8.html: tincd.8
|
tincd.8.html: tincd.8
|
||||||
w3mman2html $? > $@
|
w3mman2html $? > $@
|
||||||
|
|
||||||
tincctl.8.html: tincctl.8
|
tinc.8.html: tinc.8
|
||||||
w3mman2html $? > $@
|
w3mman2html $? > $@
|
||||||
|
|
||||||
tinc-gui.8.html: tinc-gui.8
|
tinc-gui.8.html: tinc-gui.8
|
||||||
|
@ -784,7 +784,7 @@ tinc.conf.5.html: tinc.conf.5
|
||||||
tincd.8: tincd.8.in
|
tincd.8: tincd.8.in
|
||||||
$(substitute) $? > $@
|
$(substitute) $? > $@
|
||||||
|
|
||||||
tincctl.8: tincctl.8.in
|
tinc.8: tinc.8.in
|
||||||
$(substitute) $? > $@
|
$(substitute) $? > $@
|
||||||
|
|
||||||
tinc-gui.8: tinc-gui.8.in
|
tinc-gui.8: tinc-gui.8.in
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.\" Manual page created by:
|
.\" Manual page created by:
|
||||||
.\" Scott Lamb
|
.\" Scott Lamb
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm tincctl
|
.Nm tinc
|
||||||
.Nd tinc VPN control
|
.Nd tinc VPN control
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -51,12 +51,12 @@ Create initial configuration files and RSA and ECDSA keypairs with default lengt
|
||||||
If no
|
If no
|
||||||
.Ar name
|
.Ar name
|
||||||
for this node is given, it will be asked for.
|
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
|
Print the current value of configuration variable
|
||||||
.Ar variable .
|
.Ar variable .
|
||||||
If more than one variable with the same name exists,
|
If more than one variable with the same name exists,
|
||||||
the value of each of them will be printed on a separate line.
|
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
|
Set configuration variable
|
||||||
.Ar variable
|
.Ar variable
|
||||||
to the given
|
to the given
|
||||||
|
@ -64,9 +64,9 @@ to the given
|
||||||
All previously existing configuration variables with the same name are removed.
|
All previously existing configuration variables with the same name are removed.
|
||||||
To set a variable for a specific host, use the notation
|
To set a variable for a specific host, use the notation
|
||||||
.Ar host Ns Li . Ns Ar variable .
|
.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.
|
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
|
Remove configuration variables with the same name and
|
||||||
.Ar value .
|
.Ar value .
|
||||||
If no
|
If no
|
||||||
|
@ -147,7 +147,7 @@ Sets debug level to
|
||||||
.It log Op Ar N
|
.It log Op Ar N
|
||||||
Capture log messages from a running tinc daemon.
|
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
|
An optional debug level can be given that will be applied only for log messages sent to
|
||||||
.Nm tincctl .
|
.Nm tinc .
|
||||||
.It retry
|
.It retry
|
||||||
Forces
|
Forces
|
||||||
.Xr tincd 8
|
.Xr tincd 8
|
||||||
|
@ -182,19 +182,19 @@ such as
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
Examples of some commands:
|
Examples of some commands:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
tincctl -n vpn dump graph | circo -Txlib
|
tinc -n vpn dump graph | circo -Txlib
|
||||||
tincctl -n vpn pcap | tcpdump -r -
|
tinc -n vpn pcap | tcpdump -r -
|
||||||
tincctl -n vpn top
|
tinc -n vpn top
|
||||||
.Pp
|
.Pp
|
||||||
.Ed
|
.Ed
|
||||||
Example of configuring tinc using
|
Example of configuring tinc using
|
||||||
.Nm :
|
.Nm :
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
tincctl -n vpn init foo
|
tinc -n vpn init foo
|
||||||
tincctl -n vpn config Subnet 192.168.1.0/24
|
tinc -n vpn add Subnet 192.168.1.0/24
|
||||||
tincctl -n vpn config bar.Address bar.example.com
|
tinc -n vpn add bar.Address bar.example.com
|
||||||
tincctl -n vpn config ConnectTo bar
|
tinc -n vpn add ConnectTo bar
|
||||||
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
|
tinc -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
|
||||||
.Ed
|
.Ed
|
||||||
.Sh TOP
|
.Sh TOP
|
||||||
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
|
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
|
|
@ -55,15 +55,15 @@ However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-
|
||||||
.Sh INITIAL CONFIGURATION
|
.Sh INITIAL CONFIGURATION
|
||||||
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
|
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
|
||||||
.Bd -literal -offset indent
|
.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
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
You can further change the configuration as needed either by manually editing the configuration files,
|
You can further change the configuration as needed either by manually editing the configuration files,
|
||||||
or by using
|
or by using
|
||||||
.Xr tincctl 8 .
|
.Xr tinc 8 .
|
||||||
.Sh PUBLIC/PRIVATE KEYS
|
.Sh PUBLIC/PRIVATE KEYS
|
||||||
The
|
The
|
||||||
.Nm tincctl Li init
|
.Nm tinc Li init
|
||||||
command will have generated both RSA and ECDSA public/private keypairs.
|
command will have generated both RSA and ECDSA public/private keypairs.
|
||||||
The private keys should be stored in files named
|
The private keys should be stored in files named
|
||||||
.Pa rsa_key.priv
|
.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,
|
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:
|
but you will need to create ECDSA keys using the following command:
|
||||||
.Bd -literal -offset indent
|
.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
|
.Ed
|
||||||
.Sh SERVER CONFIGURATION
|
.Sh SERVER CONFIGURATION
|
||||||
The server configuration of the daemon is done in the file
|
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.
|
as this makes it easy to exchange with other nodes.
|
||||||
.Pp
|
.Pp
|
||||||
You can edit the config file manually, but it is recommended that you use
|
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.
|
to change configuration variables for you.
|
||||||
.Pp
|
.Pp
|
||||||
Here are all valid variables, listed in alphabetical order.
|
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,
|
Ephemeral ECDH will be used for key exchanges,
|
||||||
and ECDSA will be used instead of RSA for authentication.
|
and ECDSA will be used instead of RSA for authentication.
|
||||||
When enabled, an ECDSA key must have been generated before with
|
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,
|
The experimental protocol may change at any time,
|
||||||
and there is no guarantee that tinc will run stable when it is used.
|
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
|
.It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
|
||||||
|
@ -482,6 +482,8 @@ Furthermore, specifying
|
||||||
.Qq none
|
.Qq none
|
||||||
will turn off packet encryption.
|
will turn off packet encryption.
|
||||||
It is best to use only those ciphers which support CBC mode.
|
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
|
.It Va ClampMSS Li = yes | no Pq yes
|
||||||
This option specifies whether tinc should clamp the maximum segment size (MSS)
|
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
|
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
|
Furthermore, specifying
|
||||||
.Qq none
|
.Qq none
|
||||||
will turn off packet authentication.
|
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
|
.It Va IndirectData Li = yes | no Pq no
|
||||||
When set to yes, other nodes which do not already have a meta connection to you
|
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.
|
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
|
Can be anything from
|
||||||
.Qq 0
|
.Qq 0
|
||||||
up to the length of the digest produced by the digest algorithm.
|
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
|
.It Va PMTU Li = Ar mtu Po 1514 Pc
|
||||||
This option controls the initial path MTU to this node.
|
This option controls the initial path MTU to this node.
|
||||||
.It Va PMTUDiscovery Li = yes | no Po yes Pc
|
.It Va PMTUDiscovery Li = yes | no Po yes Pc
|
||||||
|
@ -653,7 +659,7 @@ its connection to the virtual network device.
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr tincd 8 ,
|
.Xr tincd 8 ,
|
||||||
.Xr tincctl 8 ,
|
.Xr tinc 8 ,
|
||||||
.Pa http://www.tinc-vpn.org/ ,
|
.Pa http://www.tinc-vpn.org/ ,
|
||||||
.Pa http://www.tldp.org/LDP/nag2/ .
|
.Pa http://www.tldp.org/LDP/nag2/ .
|
||||||
.Pp
|
.Pp
|
||||||
|
|
1211
doc/tinc.info
1211
doc/tinc.info
File diff suppressed because it is too large
Load diff
459
doc/tinc.texi
459
doc/tinc.texi
|
@ -30,6 +30,10 @@ permission notice identical to this one.
|
||||||
|
|
||||||
@end ifinfo
|
@end ifinfo
|
||||||
|
|
||||||
|
@afourpaper
|
||||||
|
@paragraphindent none
|
||||||
|
@finalout
|
||||||
|
|
||||||
@titlepage
|
@titlepage
|
||||||
@title tinc Manual
|
@title tinc Manual
|
||||||
@subtitle Setting up a Virtual Private Network with tinc
|
@subtitle Setting up a Virtual Private Network with tinc
|
||||||
|
@ -462,7 +466,7 @@ default).
|
||||||
@subsection libcurses
|
@subsection libcurses
|
||||||
|
|
||||||
@cindex 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
|
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
|
configure script. You can either install a suitable curses library, or disable
|
||||||
|
@ -485,7 +489,7 @@ of this package.
|
||||||
@subsection libreadline
|
@subsection libreadline
|
||||||
|
|
||||||
@cindex 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
|
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
|
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:
|
proceed in the following order:
|
||||||
First, create the initial configuration files and public/private keypairs using the following command:
|
First, create the initial configuration files and public/private keypairs using the following command:
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{NETNAME} init @var{NAME}
|
tinc -n @var{NETNAME} init @var{NAME}
|
||||||
@end example
|
@end example
|
||||||
Second, use @samp{tincctl -n @var{NETNAME} config ...} to further configure tinc.
|
Second, use @samp{tinc -n @var{NETNAME} add ...} to further configure tinc.
|
||||||
Finally, export your host configuration file using @samp{tincctl -n @var{NETNAME} export} and send it to those
|
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.
|
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.
|
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.
|
but it is recommended that you choose one anyway.
|
||||||
|
|
||||||
We will asume you use a netname throughout this document.
|
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.
|
which will specify the netname.
|
||||||
|
|
||||||
The effect of this option is that tinc will set its configuration
|
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.
|
makes it easy to exchange with other nodes.
|
||||||
|
|
||||||
You can edit the config file manually, but it is recommended that you use
|
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.
|
In the following two subsections all valid variables are listed in alphabetical order.
|
||||||
The default value is given between parentheses,
|
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,
|
Ephemeral ECDH will be used for key exchanges,
|
||||||
and ECDSA will be used instead of RSA for authentication.
|
and ECDSA will be used instead of RSA for authentication.
|
||||||
When enabled, an ECDSA key must have been generated before with
|
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,
|
The experimental protocol may change at any time,
|
||||||
and there is no guarantee that tinc will run stable when it is used.
|
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
|
@cindex PrivateKeyFile
|
||||||
@item PrivateKeyFile = <@var{path}> (@file{@value{sysconfdir}/tinc/@var{netname}/rsa_key.priv})
|
@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
|
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.
|
relative directory.
|
||||||
|
|
||||||
@cindex ProcessPriority
|
@cindex ProcessPriority
|
||||||
|
@ -1217,10 +1221,11 @@ If no port is specified, the default Port is used.
|
||||||
|
|
||||||
@cindex Cipher
|
@cindex Cipher
|
||||||
@item Cipher = <@var{cipher}> (blowfish)
|
@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.
|
Any cipher supported by OpenSSL is recognized.
|
||||||
Furthermore, specifying "none" will turn off packet encryption.
|
Furthermore, specifying "none" will turn off packet encryption.
|
||||||
It is best to use only those ciphers which support CBC mode.
|
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
|
@cindex ClampMSS
|
||||||
@item ClampMSS = <yes|no> (yes)
|
@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
|
@cindex Digest
|
||||||
@item Digest = <@var{digest}> (sha1)
|
@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.
|
Any digest supported by OpenSSL is recognized.
|
||||||
Furthermore, specifying "none" will turn off packet authentication.
|
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
|
@cindex IndirectData
|
||||||
@item IndirectData = <yes|no> (no)
|
@item IndirectData = <yes|no> (no)
|
||||||
|
@ -1248,9 +1254,10 @@ It is best to leave this option out or set it to no.
|
||||||
|
|
||||||
@cindex MACLength
|
@cindex MACLength
|
||||||
@item MACLength = <@var{bytes}> (4)
|
@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
|
Can be anything from 0
|
||||||
up to the length of the digest produced by the digest algorithm.
|
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
|
@cindex PMTU
|
||||||
@item PMTU = <@var{mtu}> (1514)
|
@item PMTU = <@var{mtu}> (1514)
|
||||||
|
@ -1273,7 +1280,7 @@ This is the RSA public key for this host.
|
||||||
@cindex PublicKeyFile
|
@cindex PublicKeyFile
|
||||||
@item PublicKeyFile = <@var{path}> [obsolete]
|
@item PublicKeyFile = <@var{path}> [obsolete]
|
||||||
This is the full path name of the RSA public key file that was generated
|
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.
|
directory.
|
||||||
|
|
||||||
@cindex PEM format
|
@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:
|
The initial directory structure, configuration files and public/private keypairs are created using the following command:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} init @var{name}
|
tinc -n @var{netname} init @var{name}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
(You will need to run this as root, or use "sudo".)
|
(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:
|
Then you should run the following command:
|
||||||
|
|
||||||
@example
|
@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
|
@end example
|
||||||
|
|
||||||
This will add a Subnet statement to your host configuration file.
|
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:
|
For example, if you also use the IPv6 subnet fec0:0:0:2::/64, you can add it as well:
|
||||||
|
|
||||||
@example
|
@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
|
@end example
|
||||||
|
|
||||||
This will add another line to the file @file{hosts/@var{name}}.
|
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,
|
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.
|
you should add your public IP address or hostname to your host configuration file.
|
||||||
For example, if your hostname is foo.example.org, run:
|
For example, if your hostname is foo.example.org, run:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} config add address foo.example.org
|
tinc -n @var{netname} add address foo.example.org
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
If you already know to which daemons your daemon should make meta-connections,
|
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:
|
Suppose you want to connect to a daemon named "bar", run:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} config add connectto bar
|
tinc -n @var{netname} add connectto bar
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Note that you specify the Name of the other daemon here, not an IP address or hostname!
|
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):
|
(assuming the owner of bar has the email address bar@@example.org):
|
||||||
|
|
||||||
@example
|
@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
|
@end example
|
||||||
|
|
||||||
If the owner of bar does the same to send his host configuration file to you,
|
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:
|
or you can just start this command in a terminal and copy&paste the email:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} import
|
tinc -n @var{netname} import
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
If you are the owner of bar yourself, and you have SSH access to that computer,
|
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:
|
you can also swap the host configuration files using the following command:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} export \
|
tinc -n @var{netname} export \
|
||||||
| ssh bar.example.org tincctl -n @var{netname} exchange \
|
| ssh bar.example.org tinc -n @var{netname} exchange \
|
||||||
| tincctl -n @var{netname} import
|
| tinc -n @var{netname} import
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
You should repeat this for all nodes you ConnectTo, or which ConnectTo you.
|
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:
|
You can manually open the script in an editor, or use the following command:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} edit tinc-up
|
tinc -n @var{netname} edit tinc-up
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
An example @file{tinc-up} script, that would be appropriate for the scenario in the previous section, is:
|
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'
|
how these example host is set up. All branches use the netname `company'
|
||||||
for this particular VPN.
|
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:
|
here we just show the end results:
|
||||||
|
|
||||||
@subsubheading For Branch A
|
@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:
|
If everything else is done, you can start tinc by typing the following command:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} start
|
tinc -n @var{netname} start
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@cindex daemon
|
@cindex daemon
|
||||||
|
@ -1834,7 +1841,7 @@ Specifying . for @var{netname} is the same as not specifying any @var{netname}.
|
||||||
@xref{Multiple networks}.
|
@xref{Multiple networks}.
|
||||||
|
|
||||||
@item --pidfile=@var{filename}
|
@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
|
If unspecified, the default is
|
||||||
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
|
@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
|
@node Controlling tinc
|
||||||
@chapter 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:
|
command. A quick example:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n @var{netname} reload
|
tinc -n @var{netname} reload
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* tincctl runtime options::
|
* tinc runtime options::
|
||||||
* tincctl environment variables::
|
* tinc environment variables::
|
||||||
* tincctl commands::
|
* tinc commands::
|
||||||
* tincctl examples::
|
* tinc examples::
|
||||||
* tincctl top::
|
* tinc top::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node tincctl runtime options
|
@node tinc runtime options
|
||||||
@section tincctl runtime options
|
@section tinc runtime options
|
||||||
|
|
||||||
@c from the manpage
|
@c from the manpage
|
||||||
@table @option
|
@table @option
|
||||||
|
@ -2151,8 +2158,8 @@ Output version information and exit.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node tincctl environment variables
|
@node tinc environment variables
|
||||||
@section tincctl environment variables
|
@section tinc environment variables
|
||||||
|
|
||||||
@table @env
|
@table @env
|
||||||
@cindex NETNAME
|
@cindex NETNAME
|
||||||
|
@ -2162,8 +2169,8 @@ the value of this environment variable is used.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node tincctl commands
|
@node tinc commands
|
||||||
@section tincctl commands
|
@section tinc commands
|
||||||
|
|
||||||
@c from the manpage
|
@c from the manpage
|
||||||
@table @code
|
@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.
|
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.
|
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}.
|
Print the current value of configuration variable @var{variable}.
|
||||||
If more than one variable with the same name exists,
|
If more than one variable with the same name exists,
|
||||||
the value of each of them will be printed on a separate line.
|
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}.
|
Set configuration variable @var{variable} to the given @var{value}.
|
||||||
All previously existing configuration variables with the same name are removed.
|
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}.
|
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.
|
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}.
|
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.
|
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.
|
Export all host configuration files to standard output.
|
||||||
|
|
||||||
@item import [--force]
|
@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.
|
Already existing host configuration files are not overwritten unless the option --force is used.
|
||||||
|
|
||||||
@item exchange [--force]
|
@item exchange [--force]
|
||||||
|
@ -2263,7 +2270,7 @@ Sets debug level to @var{level}.
|
||||||
|
|
||||||
@item log [@var{level}]
|
@item log [@var{level}]
|
||||||
Capture log messages from a running tinc daemon.
|
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
|
@item retry
|
||||||
Forces tinc to try to connect to all uplinks immediately.
|
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}.
|
Closes the meta connection with the given @var{node}.
|
||||||
|
|
||||||
@item top
|
@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.
|
similar to the UNIX top command.
|
||||||
See below for more information.
|
See below for more information.
|
||||||
|
|
||||||
|
@ -2288,30 +2295,30 @@ such as tcpdump.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node tincctl examples
|
@node tinc examples
|
||||||
@section tincctl examples
|
@section tinc examples
|
||||||
|
|
||||||
Examples of some commands:
|
Examples of some commands:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n vpn dump graph | circo -Txlib
|
tinc -n vpn dump graph | circo -Txlib
|
||||||
tincctl -n vpn pcap | tcpdump -r -
|
tinc -n vpn pcap | tcpdump -r -
|
||||||
tincctl -n vpn top
|
tinc -n vpn top
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Example of configuring tinc using tincctl:
|
Example of configuring tinc using the tinc command:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tincctl -n vpn init foo
|
tinc -n vpn init foo
|
||||||
tincctl -n vpn config Subnet 192.168.1.0/24
|
tinc -n vpn add Subnet 192.168.1.0/24
|
||||||
tincctl -n vpn config bar.Address bar.example.com
|
tinc -n vpn add bar.Address bar.example.com
|
||||||
tincctl -n vpn config ConnectTo bar
|
tinc -n vpn add ConnectTo bar
|
||||||
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
|
tinc -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node tincctl top
|
@node tinc top
|
||||||
@section tincctl top
|
@section tinc top
|
||||||
|
|
||||||
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
|
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,
|
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
|
and to read and write requests by hand, provided that one
|
||||||
understands the numeric codes sent.
|
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
|
successful authentication, the server and the client will exchange all the
|
||||||
information about other tinc daemons and subnets they know of, so that both
|
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
|
sides (and all the other tinc daemons behind them) have their information
|
||||||
|
@ -2624,29 +2631,28 @@ the tinc project after TINC.
|
||||||
But in order to be ``immune'' to eavesdropping, you'll have to encrypt
|
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.
|
exactly that: encrypt.
|
||||||
Tinc by default uses blowfish encryption with 128 bit keys in CBC mode, 32 bit
|
However, encryption in itself does not prevent an attacker from modifying the encrypted data.
|
||||||
sequence numbers and 4 byte long message authentication codes to make sure
|
Therefore, tinc also authenticates the data.
|
||||||
eavesdroppers cannot get and cannot change any information at all from the
|
Finally, tinc uses sequence numbers (which themselves are also authenticated) to prevent an attacker from replaying valid packets.
|
||||||
packets they can intercept. The encryption algorithm and message authentication
|
|
||||||
algorithm can be changed in the configuration. The length of the message
|
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.
|
||||||
authentication codes is also adjustable. The length of the key for the
|
The SPTPS protocol is designed to address some weaknesses in the legacy protocol.
|
||||||
encryption algorithm is always the default length used by OpenSSL.
|
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
|
@menu
|
||||||
* Authentication protocol::
|
* Legacy authentication protocol::
|
||||||
|
* Simple Peer-to-Peer Security::
|
||||||
* Encryption of network packets::
|
* Encryption of network packets::
|
||||||
* Security issues::
|
* Security issues::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
@c ==================================================================
|
@c ==================================================================
|
||||||
@node Authentication protocol
|
@node Legacy authentication protocol
|
||||||
@subsection Authentication protocol
|
@subsection Legacy authentication protocol
|
||||||
|
|
||||||
@cindex authentication
|
@cindex legacy authentication protocol
|
||||||
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 ID
|
@cindex ID
|
||||||
@cindex META_KEY
|
@cindex META_KEY
|
||||||
|
@ -2660,28 +2666,50 @@ client <attempts connection>
|
||||||
|
|
||||||
server <accepts connection>
|
server <accepts connection>
|
||||||
|
|
||||||
client ID client 12
|
client ID client 17.2
|
||||||
| +---> version
|
| | +-> minor protocol version
|
||||||
+-------> name of tinc daemon
|
| +----> major protocol version
|
||||||
|
+--------> name of tinc daemon
|
||||||
|
|
||||||
server ID server 12
|
server ID server 17.2
|
||||||
| +---> version
|
| | +-> minor protocol version
|
||||||
+-------> name of tinc daemon
|
| +----> major protocol version
|
||||||
|
+--------> name of tinc daemon
|
||||||
|
|
||||||
client META_KEY 5f0823a93e35b69e...7086ec7866ce582b
|
client META_KEY 94 64 0 0 5f0823a93e35b69e...7086ec7866ce582b
|
||||||
\_________________________________/
|
| | | | \_________________________________/
|
||||||
+-> RSAKEYLEN bits totally random string S1,
|
| | | | +-> RSAKEYLEN bits totally random string S1,
|
||||||
encrypted with server's public RSA key
|
| | | | encrypted with server's public RSA key
|
||||||
|
| | | +-> compression level
|
||||||
|
| | +---> MAC length
|
||||||
|
| +------> digest algorithm NID
|
||||||
|
+---------> cipher algorithm NID
|
||||||
|
|
||||||
server META_KEY 6ab9c1640388f8f0...45d1a07f8a672630
|
server META_KEY 94 64 0 0 6ab9c1640388f8f0...45d1a07f8a672630
|
||||||
\_________________________________/
|
| | | | \_________________________________/
|
||||||
+-> RSAKEYLEN bits totally random string S2,
|
| | | | +-> RSAKEYLEN bits totally random string S2,
|
||||||
encrypted with client's public RSA key
|
| | | | 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:
|
From now on:
|
||||||
- the client will symmetrically encrypt outgoing traffic using S1
|
@itemize
|
||||||
- the server will symmetrically encrypt outgoing traffic using S2
|
@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
|
client CHALLENGE da02add1817c1920989ba6ae2a49cecbda0
|
||||||
\_________________________________/
|
\_________________________________/
|
||||||
+-> CHALLEN bits totally random string H1
|
+-> CHALLEN bits totally random string H1
|
||||||
|
@ -2711,47 +2739,178 @@ server ACK 655 321 0
|
||||||
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
||||||
@end example
|
@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
|
@c ==================================================================
|
||||||
as the client. The previous versions of tinc first authenticated the client,
|
@node Simple Peer-to-Peer Security
|
||||||
and then the server. This scheme even allows both sides to send their messages
|
@subsection Simple Peer-to-Peer Security
|
||||||
simultaneously, there is no need to wait for the other to send something first.
|
@cindex SPTPS
|
||||||
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.
|
|
||||||
|
|
||||||
Second, only one RSA encrypted message is sent instead of two. This reduces the
|
The SPTPS protocol is designed to address the weaknesses in the legacy protocol.
|
||||||
amount of information attackers can see (and thus use for a cryptographic
|
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.
|
||||||
attack). It also improves speed by a factor two, making the total speedup a
|
Instead, SPTPS always uses a very strong cipher suite:
|
||||||
factor 4.
|
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:
|
Similar to TLS, messages are split up in records.
|
||||||
The symmetric cipher keys are exchanged first, the challenge is done
|
A complete logical record contains the following information:
|
||||||
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.
|
|
||||||
|
|
||||||
This new scheme makes sure that first of all, symmetric keys are exchanged. The
|
@itemize
|
||||||
rest of the messages are then encrypted with the symmetric cipher. Then, each
|
@item uint32_t seqno (network byte order)
|
||||||
side can only read received messages if they have their private key. The
|
@item uint16_t length (network byte order)
|
||||||
challenge is there to let the other side know that the private key is really
|
@item uint8_t type
|
||||||
known, because a challenge reply can only be sent back if the challenge is
|
@item opaque data[length]
|
||||||
decrypted correctly, and that can only be done with knowledge of the private
|
@item opaque hmac[HMAC_SIZE] (HMAC over all preceding fields)
|
||||||
key.
|
@end itemize
|
||||||
|
|
||||||
Fourth: the first thing that is sent via the symmetric cipher encrypted
|
Depending on whether SPTPS records are sent via TCP or UDP, either the seqno or the length field is omitted on the wire
|
||||||
connection is a totally random string, so that there is no known plaintext (for
|
(but they are still included in the calculation of the HMAC);
|
||||||
an attacker) in the beginning of the encrypted stream.
|
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 ==================================================================
|
@c ==================================================================
|
||||||
@node Encryption of network packets
|
@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
|
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
|
parties, and the connection is activated. If the encryption key is not
|
||||||
known, a request is sent to the destination using the meta connection
|
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
|
to retrieve it.
|
||||||
key to arrive.
|
|
||||||
|
|
||||||
@cindex UDP
|
@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
|
@example
|
||||||
... | IP header | UDP header | seqno | VPN packet | MAC | UDP trailer
|
... | 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
|
Encrypted with symmetric cipher
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
So, the entire VPN packet is encrypted using a symmetric cipher, including a 32 bits
|
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
|
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
|
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
|
is added to the UDP packet to prevent alteration of packets.
|
||||||
first 4 bytes of the digest are used for this, but this can be changed using
|
Tinc by default encrypts network packets using Blowfish with 128 bit keys in CBC mode
|
||||||
the MACLength configuration variable.
|
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 ==================================================================
|
@c ==================================================================
|
||||||
@node Security issues
|
@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,
|
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
|
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
|
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.
|
in the legacy protocol of tinc, but it is not as strong as TLS or IPsec.
|
||||||
We will address these issues in tinc 2.0.
|
|
||||||
|
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
|
Cryptography is a hard thing to get right. We cannot make any
|
||||||
guarantees. Time, review and feedback are the only things that can
|
guarantees. Time, review and feedback are the only things that can
|
||||||
|
|
|
@ -92,7 +92,7 @@ is omitted, the default is
|
||||||
Store a cookie in
|
Store a cookie in
|
||||||
.Ar FILENAME
|
.Ar FILENAME
|
||||||
which allows
|
which allows
|
||||||
.Xr tincctl 8
|
.Xr tinc 8
|
||||||
to authenticate.
|
to authenticate.
|
||||||
If
|
If
|
||||||
.Ar FILE
|
.Ar FILE
|
||||||
|
@ -186,7 +186,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
|
||||||
.Sh TODO
|
.Sh TODO
|
||||||
A lot, especially security auditing.
|
A lot, especially security auditing.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr tincctl 8 ,
|
.Xr tinc 8 ,
|
||||||
.Xr tinc.conf 5 ,
|
.Xr tinc.conf 5 ,
|
||||||
.Pa http://www.tinc-vpn.org/ ,
|
.Pa http://www.tinc-vpn.org/ ,
|
||||||
.Pa http://www.cabal.org/ .
|
.Pa http://www.cabal.org/ .
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
## Produce this file with automake to get Makefile.in
|
## 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
|
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ endif
|
||||||
nodist_tincd_SOURCES = \
|
nodist_tincd_SOURCES = \
|
||||||
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
|
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 \
|
utils.c getopt.c getopt1.c dropin.c \
|
||||||
info.c list.c subnet_parse.c tincctl.c top.c names.c
|
info.c list.c subnet_parse.c tincctl.c top.c names.c
|
||||||
|
|
||||||
nodist_tincctl_SOURCES = \
|
nodist_tinc_SOURCES = \
|
||||||
ecdsagen.c rsagen.c
|
ecdsagen.c rsagen.c
|
||||||
|
|
||||||
sptps_test_SOURCES = \
|
sptps_test_SOURCES = \
|
||||||
|
@ -37,7 +37,7 @@ if TUNEMU
|
||||||
tincd_SOURCES += bsd/tunemu.c
|
tincd_SOURCES += bsd/tunemu.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||||
|
|
||||||
DEFAULT_INCLUDES =
|
DEFAULT_INCLUDES =
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ PRE_UNINSTALL = :
|
||||||
POST_UNINSTALL = :
|
POST_UNINSTALL = :
|
||||||
build_triplet = @build@
|
build_triplet = @build@
|
||||||
host_triplet = @host@
|
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
|
@UML_TRUE@am__append_1 = uml_device.c
|
||||||
@VDE_TRUE@am__append_2 = vde_device.c
|
@VDE_TRUE@am__append_2 = vde_device.c
|
||||||
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.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.$(OBJEXT) utils.$(OBJEXT)
|
||||||
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
|
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
|
||||||
sptps_test_LDADD = $(LDADD)
|
sptps_test_LDADD = $(LDADD)
|
||||||
am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
|
am_tinc_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
|
||||||
getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
|
dropin.$(OBJEXT) info.$(OBJEXT) list.$(OBJEXT) \
|
||||||
list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
|
subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) top.$(OBJEXT) \
|
||||||
top.$(OBJEXT) names.$(OBJEXT)
|
names.$(OBJEXT)
|
||||||
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
|
nodist_tinc_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
|
||||||
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
|
tinc_OBJECTS = $(am_tinc_OBJECTS) $(nodist_tinc_OBJECTS)
|
||||||
am__DEPENDENCIES_1 =
|
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 \
|
am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
|
||||||
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.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 \
|
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)
|
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
CCLD = $(CC)
|
CCLD = $(CC)
|
||||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||||
SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
|
SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) $(nodist_tinc_SOURCES) \
|
||||||
$(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
|
$(tincd_SOURCES) $(nodist_tincd_SOURCES)
|
||||||
$(nodist_tincd_SOURCES)
|
DIST_SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) \
|
||||||
DIST_SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
|
|
||||||
$(am__tincd_SOURCES_DIST)
|
$(am__tincd_SOURCES_DIST)
|
||||||
am__can_run_installinfo = \
|
am__can_run_installinfo = \
|
||||||
case $$AM_UPDATE_INFO_DIR in \
|
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 = \
|
nodist_tincd_SOURCES = \
|
||||||
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
|
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 \
|
utils.c getopt.c getopt1.c dropin.c \
|
||||||
info.c list.c subnet_parse.c tincctl.c top.c names.c
|
info.c list.c subnet_parse.c tincctl.c top.c names.c
|
||||||
|
|
||||||
nodist_tincctl_SOURCES = \
|
nodist_tinc_SOURCES = \
|
||||||
ecdsagen.c rsagen.c
|
ecdsagen.c rsagen.c
|
||||||
|
|
||||||
sptps_test_SOURCES = \
|
sptps_test_SOURCES = \
|
||||||
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
|
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
|
||||||
sptps.c sptps_test.c utils.c
|
sptps.c sptps_test.c utils.c
|
||||||
|
|
||||||
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||||
DEFAULT_INCLUDES =
|
DEFAULT_INCLUDES =
|
||||||
noinst_HEADERS = \
|
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 \
|
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)
|
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
|
||||||
@rm -f sptps_test$(EXEEXT)
|
@rm -f sptps_test$(EXEEXT)
|
||||||
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
|
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
|
||||||
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES) $(EXTRA_tincctl_DEPENDENCIES)
|
tinc$(EXEEXT): $(tinc_OBJECTS) $(tinc_DEPENDENCIES) $(EXTRA_tinc_DEPENDENCIES)
|
||||||
@rm -f tincctl$(EXEEXT)
|
@rm -f tinc$(EXEEXT)
|
||||||
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS)
|
$(LINK) $(tinc_OBJECTS) $(tinc_LDADD) $(LIBS)
|
||||||
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
|
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
|
||||||
@rm -f tincd$(EXEEXT)
|
@rm -f tincd$(EXEEXT)
|
||||||
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
|
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
|
||||||
|
|
|
@ -245,6 +245,12 @@ bool event_loop(void) {
|
||||||
return true;
|
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) {
|
void event_exit(void) {
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 void signal_del(signal_t *sig);
|
||||||
|
|
||||||
extern bool event_loop(void);
|
extern bool event_loop(void);
|
||||||
|
extern void event_flush_output(void);
|
||||||
extern void event_exit(void);
|
extern void event_exit(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -204,7 +204,7 @@ static void check_reachability(void) {
|
||||||
for splay_each(node_t, n, node_tree) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
if(n->status.visited != n->status.reachable) {
|
if(n->status.visited != n->status.reachable) {
|
||||||
n->status.reachable = !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) {
|
if(n->status.reachable) {
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
|
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
|
||||||
|
|
|
@ -80,6 +80,7 @@ static DWORD WINAPI tapreader(void *bla) {
|
||||||
packet.len = len;
|
packet.len = len;
|
||||||
packet.priority = 0;
|
packet.priority = 0;
|
||||||
route(myself, &packet);
|
route(myself, &packet);
|
||||||
|
event_flush_output();
|
||||||
LeaveCriticalSection(&mutex);
|
LeaveCriticalSection(&mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,7 +406,7 @@ int reload_configuration(void) {
|
||||||
free(fname);
|
free(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_config_check = time(NULL);
|
last_config_check = now.tv_sec;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,7 @@ extern int udp_sndbuf;
|
||||||
extern bool do_prune;
|
extern bool do_prune;
|
||||||
extern char *myport;
|
extern char *myport;
|
||||||
extern int autoconnect;
|
extern int autoconnect;
|
||||||
|
extern bool disablebuggypeers;
|
||||||
extern int contradicting_add_edge;
|
extern int contradicting_add_edge;
|
||||||
extern int contradicting_del_edge;
|
extern int contradicting_del_edge;
|
||||||
extern time_t last_config_check;
|
extern time_t last_config_check;
|
||||||
|
|
|
@ -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) {
|
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
||||||
vpn_packet_t outpkt;
|
vpn_packet_t outpkt;
|
||||||
|
|
||||||
|
if(len > sizeof outpkt.data)
|
||||||
|
return;
|
||||||
|
|
||||||
outpkt.len = len;
|
outpkt.len = len;
|
||||||
if(c->options & OPTION_TCPONLY)
|
if(c->options & OPTION_TCPONLY)
|
||||||
outpkt.priority = 0;
|
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);
|
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
|
||||||
if(!n->status.waitingforkey)
|
if(!n->status.waitingforkey)
|
||||||
send_req_key(n);
|
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);
|
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
|
||||||
sptps_stop(&n->sptps);
|
sptps_stop(&n->sptps);
|
||||||
n->status.waitingforkey = false;
|
n->status.waitingforkey = false;
|
||||||
|
|
|
@ -52,6 +52,7 @@ char *proxyuser;
|
||||||
char *proxypass;
|
char *proxypass;
|
||||||
proxytype_t proxytype;
|
proxytype_t proxytype;
|
||||||
int autoconnect;
|
int autoconnect;
|
||||||
|
bool disablebuggypeers;
|
||||||
|
|
||||||
char *scriptinterpreter;
|
char *scriptinterpreter;
|
||||||
char *scriptextension;
|
char *scriptextension;
|
||||||
|
@ -598,6 +599,8 @@ bool setup_myself_reloadable(void) {
|
||||||
|
|
||||||
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
|
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
|
||||||
|
|
||||||
|
get_config_bool(lookup_config(config_tree, "DisableBuggyPeers"), &disablebuggypeers);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +754,7 @@ static bool setup_myself(void) {
|
||||||
myself->nexthop = myself;
|
myself->nexthop = myself;
|
||||||
myself->via = myself;
|
myself->via = myself;
|
||||||
myself->status.reachable = true;
|
myself->status.reachable = true;
|
||||||
myself->last_state_change = time(NULL);
|
myself->last_state_change = now.tv_sec;
|
||||||
myself->status.sptps = experimental;
|
myself->status.sptps = experimental;
|
||||||
node_add(myself);
|
node_add(myself);
|
||||||
|
|
||||||
|
@ -958,7 +961,7 @@ static bool setup_myself(void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_config_check = time(NULL);
|
last_config_check = now.tv_sec;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,7 +294,7 @@ void retry_outgoing(outgoing_t *outgoing) {
|
||||||
void finish_connecting(connection_t *c) {
|
void finish_connecting(connection_t *c) {
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
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;
|
c->status.connecting = false;
|
||||||
|
|
||||||
send_id(c);
|
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) {
|
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);
|
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
|
||||||
if(outlen <= 0) {
|
if(outlen <= 0) {
|
||||||
if(!errno || errno == EPIPE) {
|
if(!errno || errno == EPIPE) {
|
||||||
|
@ -505,7 +508,7 @@ begin:
|
||||||
c->outdigest = myself->connection->outdigest;
|
c->outdigest = myself->connection->outdigest;
|
||||||
c->outmaclength = myself->connection->outmaclength;
|
c->outmaclength = myself->connection->outmaclength;
|
||||||
c->outcompression = myself->connection->outcompression;
|
c->outcompression = myself->connection->outcompression;
|
||||||
c->last_ping_time = time(NULL);
|
c->last_ping_time = now.tv_sec;
|
||||||
|
|
||||||
connection_add(c);
|
connection_add(c);
|
||||||
|
|
||||||
|
@ -568,7 +571,7 @@ void handle_new_meta_connection(void *data, int flags) {
|
||||||
c->address = sa;
|
c->address = sa;
|
||||||
c->hostname = sockaddr2hostname(&sa);
|
c->hostname = sockaddr2hostname(&sa);
|
||||||
c->socket = fd;
|
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);
|
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->address = sa;
|
||||||
c->hostname = xstrdup("localhost port unix");
|
c->hostname = xstrdup("localhost port unix");
|
||||||
c->socket = fd;
|
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);
|
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ bool seen_request(const char *request) {
|
||||||
} else {
|
} else {
|
||||||
new = xmalloc(sizeof *new);
|
new = xmalloc(sizeof *new);
|
||||||
new->request = xstrdup(request);
|
new->request = xstrdup(request);
|
||||||
new->firstseen = time(NULL);
|
new->firstseen = now.tv_sec;
|
||||||
splay_insert(past_request_tree, new);
|
splay_insert(past_request_tree, new);
|
||||||
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
|
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -160,7 +160,7 @@ bool id_h(connection_t *c, const char *request) {
|
||||||
if(name[0] == '^' && !strcmp(name + 1, controlcookie)) {
|
if(name[0] == '^' && !strcmp(name + 1, controlcookie)) {
|
||||||
c->status.control = true;
|
c->status.control = true;
|
||||||
c->allow_request = CONTROL;
|
c->allow_request = CONTROL;
|
||||||
c->last_ping_time = time(NULL) + 3600;
|
c->last_ping_time = now.tv_sec + 3600;
|
||||||
|
|
||||||
free(c->name);
|
free(c->name);
|
||||||
c->name = xstrdup("<control>");
|
c->name = xstrdup("<control>");
|
||||||
|
@ -510,6 +510,17 @@ bool send_ack(connection_t *c) {
|
||||||
static void send_everything(connection_t *c) {
|
static void send_everything(connection_t *c) {
|
||||||
/* Send all known subnets and edges */
|
/* 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) {
|
if(tunnelserver) {
|
||||||
for splay_each(subnet_t, s, myself->subnet_tree)
|
for splay_each(subnet_t, s, myself->subnet_tree)
|
||||||
send_add_subnet(c, s);
|
send_add_subnet(c, s);
|
||||||
|
|
|
@ -111,7 +111,7 @@ bool send_req_key(node_t *to) {
|
||||||
sptps_stop(&to->sptps);
|
sptps_stop(&to->sptps);
|
||||||
to->status.validkey = false;
|
to->status.validkey = false;
|
||||||
to->status.waitingforkey = true;
|
to->status.waitingforkey = true;
|
||||||
to->last_req_key = time(NULL);
|
to->last_req_key = now.tv_sec;
|
||||||
to->incompression = myself->incompression;
|
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);
|
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);
|
sptps_stop(&from->sptps);
|
||||||
from->status.validkey = false;
|
from->status.validkey = false;
|
||||||
from->status.waitingforkey = true;
|
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_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);
|
sptps_receive_data(&from->sptps, buf, len);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -89,7 +89,7 @@ bool termreq_h(connection_t *c, const char *request) {
|
||||||
|
|
||||||
bool send_ping(connection_t *c) {
|
bool send_ping(connection_t *c) {
|
||||||
c->status.pinged = true;
|
c->status.pinged = true;
|
||||||
c->last_ping_time = time(NULL);
|
c->last_ping_time = now.tv_sec;
|
||||||
|
|
||||||
return send_request(c, "%d", PING);
|
return send_request(c, "%d", PING);
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ static void learn_mac(mac_t *address) {
|
||||||
|
|
||||||
subnet = new_subnet();
|
subnet = new_subnet();
|
||||||
subnet->type = SUBNET_MAC;
|
subnet->type = SUBNET_MAC;
|
||||||
subnet->expires = time(NULL) + macexpire;
|
subnet->expires = now.tv_sec + macexpire;
|
||||||
subnet->net.mac.address = *address;
|
subnet->net.mac.address = *address;
|
||||||
subnet->weight = 10;
|
subnet->weight = 10;
|
||||||
subnet_add(myself, subnet);
|
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});
|
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
|
||||||
} else {
|
} else {
|
||||||
if(subnet->expires)
|
if(subnet->expires)
|
||||||
subnet->expires = time(NULL) + macexpire;
|
subnet->expires = now.tv_sec + macexpire;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,8 @@ int main(int argc, char *argv[]) {
|
||||||
memset(&hint, 0, sizeof hint);
|
memset(&hint, 0, sizeof hint);
|
||||||
|
|
||||||
hint.ai_family = AF_UNSPEC;
|
hint.ai_family = AF_UNSPEC;
|
||||||
hint.ai_socktype = SOCK_STREAM;
|
hint.ai_socktype = datagram ? SOCK_DGRAM : SOCK_STREAM;
|
||||||
hint.ai_protocol = IPPROTO_TCP;
|
hint.ai_protocol = datagram ? IPPROTO_UDP : IPPROTO_TCP;
|
||||||
hint.ai_flags = initiator ? 0 : AI_PASSIVE;
|
hint.ai_flags = initiator ? 0 : AI_PASSIVE;
|
||||||
|
|
||||||
if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
|
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;
|
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) {
|
if(sock < 0) {
|
||||||
fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
|
fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -106,6 +106,8 @@ int main(int argc, char *argv[]) {
|
||||||
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
|
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!datagram) {
|
||||||
if(listen(sock, 1)) {
|
if(listen(sock, 1)) {
|
||||||
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
|
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -117,6 +119,23 @@ int main(int argc, char *argv[]) {
|
||||||
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
|
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
|
||||||
return 1;
|
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");
|
fprintf(stderr, "Connected\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,11 +112,10 @@ static void usage(bool status) {
|
||||||
"\n"
|
"\n"
|
||||||
"Valid commands are:\n"
|
"Valid commands are:\n"
|
||||||
" init [name] Create initial configuration files.\n"
|
" init [name] Create initial configuration files.\n"
|
||||||
" config Change configuration:\n"
|
" get VARIABLE Print current value of VARIABLE\n"
|
||||||
" [get] VARIABLE - print current value of VARIABLE\n"
|
" set VARIABLE VALUE Set VARIABLE to VALUE\n"
|
||||||
" [set] VARIABLE VALUE - set VARIABLE to VALUE\n"
|
" add VARIABLE VALUE Add VARIABLE with the given VALUE\n"
|
||||||
" add VARIABLE VALUE - add VARIABLE with the given VALUE\n"
|
" del VARIABLE [VALUE] Remove VARIABLE [only ones with watching VALUE]\n"
|
||||||
" del VARIABLE [VALUE] - remove VARIABLE [only ones with watching VALUE]\n"
|
|
||||||
" start [tincd options] Start tincd.\n"
|
" start [tincd options] Start tincd.\n"
|
||||||
" stop Stop tincd.\n"
|
" stop Stop tincd.\n"
|
||||||
" restart Restart tincd.\n"
|
" restart Restart tincd.\n"
|
||||||
|
@ -1148,7 +1147,7 @@ static int cmd_top(int argc, char *argv[]) {
|
||||||
top(fd);
|
top(fd);
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#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;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1199,9 +1198,10 @@ static int rstrip(char *value) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_my_name() {
|
static char *get_my_name(bool verbose) {
|
||||||
FILE *f = fopen(tinc_conf, "r");
|
FILE *f = fopen(tinc_conf, "r");
|
||||||
if(!f) {
|
if(!f) {
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
|
fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1228,6 +1228,7 @@ static char *get_my_name() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
if(verbose)
|
||||||
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
|
fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1309,6 +1310,9 @@ static int cmd_config(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strcasecmp(argv[0], "config"))
|
||||||
|
argv--, argc++;
|
||||||
|
|
||||||
int action = -2;
|
int action = -2;
|
||||||
if(!strcasecmp(argv[1], "get")) {
|
if(!strcasecmp(argv[1], "get")) {
|
||||||
argv++, argc--;
|
argv++, argc--;
|
||||||
|
@ -1402,7 +1406,7 @@ static int cmd_config(int argc, char *argv[]) {
|
||||||
/* Should this go into our own host config file? */
|
/* Should this go into our own host config file? */
|
||||||
|
|
||||||
if(!node && !(variables[i].type & VAR_SERVER)) {
|
if(!node && !(variables[i].type & VAR_SERVER)) {
|
||||||
node = get_my_name();
|
node = get_my_name(true);
|
||||||
if(!node)
|
if(!node)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1692,6 +1696,9 @@ static int cmd_generate_keys(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!name)
|
||||||
|
name = get_my_name(false);
|
||||||
|
|
||||||
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ecdsa_keygen(true));
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!name)
|
||||||
|
name = get_my_name(false);
|
||||||
|
|
||||||
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!name)
|
||||||
|
name = get_my_name(false);
|
||||||
|
|
||||||
return !ecdsa_keygen(true);
|
return !ecdsa_keygen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1831,7 +1844,7 @@ static int cmd_export(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = get_my_name();
|
char *name = get_my_name(true);
|
||||||
if(!name)
|
if(!name)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -1961,6 +1974,7 @@ static int cmd_exchange_all(int argc, char *argv[]) {
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *command;
|
const char *command;
|
||||||
int (*function)(int argc, char *argv[]);
|
int (*function)(int argc, char *argv[]);
|
||||||
|
bool hidden;
|
||||||
} commands[] = {
|
} commands[] = {
|
||||||
{"start", cmd_start},
|
{"start", cmd_start},
|
||||||
{"stop", cmd_stop},
|
{"stop", cmd_stop},
|
||||||
|
@ -1976,7 +1990,11 @@ static const struct {
|
||||||
{"pcap", cmd_pcap},
|
{"pcap", cmd_pcap},
|
||||||
{"log", cmd_log},
|
{"log", cmd_log},
|
||||||
{"pid", cmd_pid},
|
{"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},
|
{"init", cmd_init},
|
||||||
{"generate-keys", cmd_generate_keys},
|
{"generate-keys", cmd_generate_keys},
|
||||||
{"generate-rsa-keys", cmd_generate_rsa_keys},
|
{"generate-rsa-keys", cmd_generate_rsa_keys},
|
||||||
|
@ -2003,7 +2021,7 @@ static char *complete_command(const char *text, int state) {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
while(commands[i].command) {
|
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);
|
return xstrdup(commands[i].command);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -2030,31 +2048,14 @@ static char *complete_dump(const char *text, int state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *complete_config(const char *text, int state) {
|
static char *complete_config(const char *text, int state) {
|
||||||
const char *sub[] = {"get", "set", "add", "del"};
|
|
||||||
static int i;
|
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(!state)
|
||||||
if(i < 0 && !strncasecmp(sub[i + 4], text, strlen(text)))
|
i = 0;
|
||||||
return xstrdup(sub[i + 4]);
|
else
|
||||||
if(i >= 0) {
|
i++;
|
||||||
|
|
||||||
|
while(variables[i].name) {
|
||||||
char *dot = strchr(text, '.');
|
char *dot = strchr(text, '.');
|
||||||
if(dot) {
|
if(dot) {
|
||||||
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
|
if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
|
||||||
|
@ -2066,7 +2067,6 @@ static char *complete_config(const char *text, int state) {
|
||||||
if(!strncasecmp(variables[i].name, text, strlen(text)))
|
if(!strncasecmp(variables[i].name, text, strlen(text)))
|
||||||
return xstrdup(variables[i].name);
|
return xstrdup(variables[i].name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2118,7 +2118,13 @@ static char **completion (const char *text, int start, int end) {
|
||||||
matches = rl_completion_matches(text, complete_command);
|
matches = rl_completion_matches(text, complete_command);
|
||||||
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
|
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
|
||||||
matches = rl_completion_matches(text, complete_dump);
|
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);
|
matches = rl_completion_matches(text, complete_config);
|
||||||
else if(!strncasecmp(rl_line_buffer, "info ", 5))
|
else if(!strncasecmp(rl_line_buffer, "info ", 5))
|
||||||
matches = rl_completion_matches(text, complete_info);
|
matches = rl_completion_matches(text, complete_info);
|
||||||
|
|
|
@ -346,7 +346,8 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
/* Slllluuuuuuurrrrp! */
|
/* Slllluuuuuuurrrrp! */
|
||||||
|
|
||||||
srand(time(NULL));
|
gettimeofday(&now, NULL);
|
||||||
|
srand(now.tv_sec + now.tv_usec);
|
||||||
crypto_init();
|
crypto_init();
|
||||||
|
|
||||||
if(!read_server_config())
|
if(!read_server_config())
|
||||||
|
|
Loading…
Reference in a new issue