Merge remote-tracking branch 'guus/1.1' into thkr-foor2Vup

This commit is contained in:
thorkill 2016-05-08 15:58:29 +02:00
commit 4be26caf4e
64 changed files with 3013 additions and 2400 deletions

47
.gitignore vendored
View file

@ -1,23 +1,40 @@
Makefile
Makefile.in
*.o
*.lo
*.la
*.a
/config.*
/src/tincd
/src/tinc
.libs/
/autom4te.cache
*.dirstamp
*.o
*.orig
*.swp
.deps
.libs
/ChangeLog
/INSTALL
/aclocal.m4
/autom4te.cache
/compile
/config.*
/configure
/depcomp
/doc/sample-config.tar.gz
/doc/*.tex
/doc/*.info
/doc/*.5
/doc/*.8
/doc/*.html
/doc/*.pdf
/doc/*.t2p
/doc/tincinclude.texi
/install-sh
/missing
/m4/
INSTALL
.deps
.dir-locals.el
stamp-h1
/src/device.c
/src/tincd
/src/tinc
/src/sptps_keypair
/src/sptps_speed
/src/sptps_test
/src/version_git.h
/stamp-h1
/test-driver
Makefile
Makefile.in
core*
*.tar.gz*
.Tpo

View file

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

View file

@ -1,19 +1,17 @@
The following applies to tinc:
This program is released under the GPL with the additional exemption that
compiling, linking, and/or using OpenSSL is allowed. You may provide binary
packages linked to the OpenSSL libraries, provided that all other requirements
of the GPL are met.
> This program is released under the GPL with the additional exemption that
> compiling, linking, and/or using OpenSSL is allowed. You may provide binary
> packages linked to the OpenSSL libraries, provided that all other requirements
> of the GPL are met.
The following applies to the LZO library:
Hereby I grant a special exception to the tinc VPN project
(http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library
(http://www.openssl.org).
Markus F.X.J. Oberhumer
> Hereby I grant a special exception to the tinc VPN project
> (https://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library
> (https://openssl.org).
>
> Markus F.X.J. Oberhumer
When tinc is compiled with the --enable-tunemu option, the resulting binary
falls under the GPL version 3 or later.

1301
NEWS

File diff suppressed because it is too large Load diff

36
README
View file

@ -1,11 +1,7 @@
This is the README file for tinc version 1.1pre11. Installation
This is the README file for tinc version 1.1pre14. Installation
instructions may be found in the INSTALL file.
tinc is Copyright (C) 1998-2014 by:
Ivo Timmermans,
Guus Sliepen <guus@tinc-vpn.org>,
and others.
tinc is Copyright © 1998-2016 Ivo Timmermans, Guus Sliepen <guus@tinc-vpn.org>, and others.
For a complete list of authors see the AUTHORS file.
@ -36,11 +32,12 @@ at your own risk.
Compatibility
-------------
Version 1.1pre11 is compatible with 1.0pre8, 1.0 and later, but not with older
Version 1.1pre14 is compatible with 1.0pre8, 1.0 and later, but not with older
versions of tinc.
When the ExperimentalProtocol option is used, tinc is still compatible with
1.0.X and 1.1pre11 itself, but not with any other 1.1preX version.
1.0.X, 1.1pre11 and later, but not with any version between 1.1pre1 and
1.1pre10.
Requirements
@ -49,15 +46,14 @@ Requirements
In order to compile tinc, you will need a GNU C compiler environment. Please
ensure you have the latest stable versions of all the required libraries:
- OpenSSL (http://www.openssl.org/) version 1.0.0 or later, with support for
elliptic curve cryptography (ECC) and Galois counter mode (GCM) enabled.
- LibreSSL (http://www.libressl.org/) or OpenSSL (https://openssl.org/) version 1.0.0 or later.
The following libraries are used by default, but can be disabled if necessary:
- zlib (http://www.gzip.org/zlib/)
- lzo (http://www.oberhumer.com/opensource/lzo/)
- zlib (http://www.zlib.net/)
- LZO (https://www.oberhumer.com/opensource/lzo/)
- ncurses (http://invisible-island.net/ncurses/)
- readline (ftp://ftp.gnu.org/pub/gnu/readline/)
- readline (https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)
Features
@ -70,12 +66,12 @@ those nodes, tinc will learn about all other nodes on the VPN, and will make
connections automatically. When direct connections are not possible, data will
be forwarded by intermediate nodes.
By default, nodes authenticate each other using 2048 bit RSA (or 521 bit
ECDSA*) keys. Traffic is encrypted using Blowfish in CBC mode (or AES-256 in
GCM mode*), authenticated using HMAC-SHA1 (or GCM*), and is protected against
replay attacks.
*) When using the ExperimentalProtocol option.
Tinc 1.1 support two protocols. The first is a legacy protocol that provides
backwards compatibility with tinc 1.0 nodes, and which by default uses 2048 bit
RSA keys for authentication, and encrypts traffic using Blowfish in CBC mode
and HMAC-SHA1. The second is a new protocol which uses Curve25519 keys for
authentication, and encrypts traffic using Chacha20-Poly1305, and provides
forward secrecy.
Tinc fully supports IPv6.
@ -85,7 +81,7 @@ modes, "switch" and "hub", let the tinc daemons work together to form a virtual
Ethernet network switch or hub.
Normally, when started tinc will detach and run in the background. In a native
Windows environment this means tinc will intall itself as a service, which will
Windows environment this means tinc will install itself as a service, which will
restart after reboots. To prevent tinc from detaching or running as a service,
use the -D option.

View file

@ -1,20 +1,23 @@
Quick how-o cross compile tinc for android (done from $HOME/android/):
Quick how-to 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 Android NDK and setup local ARM 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
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
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

View file

@ -1,9 +1,9 @@
Before you can start compiling tinc from a fresh git clone, you have
to install the very latest versions of the following packages:
- OpenSSL
- LibreSSL or OpenSSL
- zlib
- lzo
- LZO
- GCC
- automake
- autoconf
@ -13,14 +13,14 @@ to install the very latest versions of the following packages:
Then you have to let the autotools create all the autogenerated files, using
this command:
autoreconf -fsi
autoreconf -fsi
If you change configure.in or any Makefile.am file, you will have to rerun
autoreconf. After this, you can run configure and make as usual. To create a
tarball suitable for release, run:
make dist
make dist
To clean up your working copy so that no autogenerated files remain, run:
git clean -f
git clean -f

16
THANKS
View file

@ -14,6 +14,7 @@ We would like to thank the following people for their contributions to tinc:
* Cheng LI
* Cris van Pelt
* Darius Jahandarie
* Dato Simó
* David Pflug
* Delf Eldkraft
* Dennis Joachimsthaler
@ -22,6 +23,8 @@ We would like to thank the following people for their contributions to tinc:
* Erik Tews
* Etienne Dechamps
* Florent Clairambault
* Florian Klink
* Florian Weik
* Flynn Marquardt
* Franz Pletz
* Gary Kessler and Claudia Gonzalez
@ -45,6 +48,7 @@ We would like to thank the following people for their contributions to tinc:
* Loïc Dachary
* Loïc Grenié
* Lubomír Bulej
* LunarShaddow
* Mads Kiilerich
* Marc A. Lehmann
* Mark Glines
@ -53,17 +57,22 @@ We would like to thank the following people for their contributions to tinc:
* Martin Kihlgren
* Martin Schobert
* Martin Schürrer
* Martin Weinelt
* Matias Carrasco
* Max Rijevski
* Menno Smits
* Mesar Hameed
* Michael Tokarev
* Miles Nordin
* Nathan Stratton Treadway
* Murat Donmez
* Nick Hibma
* Nick Patavalis
* Paul Littlefield
* Philipp Babel
* Pierre Emeriaud
* Rafał Leśniak
* Rhosyn Celyn
* Robert van der Meulen
* Rumko
* Sam Bryan
@ -80,15 +89,18 @@ We would like to thank the following people for their contributions to tinc:
* Tomislav Čohar
* Tommy Arnkværn
* Tonnerre Lombard
* Ulrich Seifert
* Vil Brekin
* Vittorio Gambaletta
* Wessel Dankers
* William A. Kennington III
* William McArthur
* Wouter van Heyst
* xentec
* 戴 鸣
And everyone we forgot (if we did, please let us know). Thank you!
Ivo Timmermans
Guus Sliepen
---
Ivo Timmermans,
Guus Sliepen.

View file

@ -5,7 +5,7 @@ _tinc() {
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="-c -d -D -K -n -o -L -R -U --config --no-detach --debug --net --option --mlock --logfile --pidfile --chroot --user --help --version"
confvars="Address AddressFamily BindToAddress BindToInterface Broadcast BroadcastSubnet Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceStandby DeviceType Digest DirectOnly Ed25519PrivateKeyFile Ed25519PublicKey Ed25519PublicKeyFile ExperimentalProtocol Forwarding GraphDumpFile Hostnames IffOneQueue IndirectData Interface KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode MTUInfoInterval Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPDiscovery UDPDiscoveryKeepaliveInterval UDPDiscoveryInterval UDPDiscoveryTimeout UDPInfoInterval UDPRcvBuf UDPSndBuf UPnP UPnPDiscoverWait UPnPRefreshPeriod VDEGroup VDEPort Weight"
commands="add connect debug del disconnect dump edit export export-all generate-ed25519-keys generate-keys generate-rsa-keys get help import info init invite join list log network pcap pid purge reload restart retry set start stop top version"
commands="add connect debug del disconnect dump edit export export-all generate-ed25519-keys generate-keys generate-rsa-keys get help import info init invite join list log network pcap pid purge reload restart retry set sign start stop top verify version"
case ${prev} in
-c|--config)

View file

@ -1,15 +1,13 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_CONFIG_MACRO_DIRS([m4])
AC_INIT([tinc], m4_esyscmd_s((git describe || echo UNKNOWN) | sed 's/release-//'))
AC_CONFIG_SRCDIR([src/tincd.c])
AC_GNU_SOURCE
AM_INIT_AUTOMAKE([std-options subdir-objects -Wall])
AM_INIT_AUTOMAKE([std-options subdir-objects nostdinc silent-rules -Wall])
AC_CONFIG_HEADERS([config.h])
AM_PROG_AR
LT_INIT
AC_CONFIG_MACRO_DIR([m4])
AM_SILENT_RULES([yes])
# Enable GNU extensions.
# Define this here, not in acconfig's @TOP@ section, since definitions
@ -116,24 +114,6 @@ AC_ARG_ENABLE(tunemu,
[tunemu=false]
)
AC_ARG_ENABLE(devel,
AS_HELP_STRING([--enable-devel], [enable compiler warnings/errors for developement]),
[ AS_IF([test "x$enable_devel" = "xyes"],
[ AC_DEFINE(ENABLE_DEVEL, 1, [Support for devel])
devel=true
],
[devel=false])
],
[devel=false]
)
AC_ARG_WITH(windows2000,
AS_HELP_STRING([--with-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]),
[ AS_IF([test "x$with_windows2000" = "xyes"],
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])])
]
)
AC_ARG_WITH(systemd,
AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd service files @<:@to DIR if specified@:>@]),
[ systemd=true; systemd_path="$with_systemd" ],
@ -166,15 +146,6 @@ dnl Compiler hardening flags
dnl No -fstack-protector-all because it doesn't work on all platforms or architectures.
AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [disable compiler and linker hardening flags]))
AS_IF([test "x$enable_devel" = "xyes"],
[AX_CHECK_COMPILE_FLAG([-Werror=conditional-uninitialized], [CFLAGS="$CFLAGS -Werror=conditional-uninitialized"])
AX_CHECK_COMPILE_FLAG([-Werror=uninitialized], [CFLAGS="$CFLAGS -Werror=uninitialized"])
AX_CHECK_COMPILE_FLAG([-Werror=unused-variable], [CFLAGS="$CFLAGS -Werror=unused-variable"])
AX_CHECK_COMPILE_FLAG([-Werror=unused-parameter], [CFLAGS="$CFLAGS -Werror=unused-parameter"])
AX_CHECK_COMPILE_FLAG([-Werror=missing-field-initializers], [CFLAGS="$CFLAGS -Werror=missing-field-initializers"])
AX_CHECK_COMPILE_FLAG([-Werror=missing-variable-declarations], [CFLAGS="$CFLAGS -Werror=missing-variable-declarations"])
AX_CHECK_COMPILE_FLAG([-Werror=missing-prototypes], [CFLAGS="$CFLAGS -Werror=missing-prototypes"])
])
AS_IF([test "x$enable_hardening" != "xno"],
[AX_CHECK_COMPILE_FLAG([-DFORTIFY_SOURCE=2], [CPPFLAGS="$CPPFLAGS -DFORTIFY_SOURCE=2"])
@ -210,9 +181,8 @@ dnl AX_CHECK_COMPILE_FLAG([-Wno-cast-qual], [CFLAGS="$CFLAGS -Wno-cast-qual"])
dnl Checks for header files.
dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
AC_CHECK_HEADERS([syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h getopt.h])
AC_CHECK_HEADERS([net/if.h net/if_types.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h],
[], [], [#include "$srcdir/src/have.h"]
)
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
@ -223,44 +193,46 @@ AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_VOLATILE
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_STRUCT_TM
tinc_ATTRIBUTE(__malloc__)
tinc_ATTRIBUTE(__warn_unused_result__)
AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
AC_CHECK_TYPES([struct ether_header, struct arphdr, struct ether_arp, struct ip, struct icmp, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
[#include "$srcdir/src/have.h"]
)
dnl Checks for library functions.
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random recvmmsg select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork gettimeofday mlockall putenv recvmmsg strsignal nanosleep unsetenv vsyslog devname fdevname],
[], [], [#include "$srcdir/src/have.h"]
)
dnl Support for SunOS
AC_CHECK_FUNC(socket, [], [
AC_CHECK_LIB(socket, connect)
])
AC_CHECK_FUNC(gethostbyname, [], [
AC_CHECK_LIB(nsl, gethostbyname)
])
AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo],
[], [], [#include "$srcdir/src/have.h"]
)
AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false])
AM_CONDITIONAL(GETOPT, test "$getopt" = true)
AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
#include <netinet/in.h>
#include <resolv.h>
])
dnl Operating system specific checks
case $host_os in
*linux*)
AC_CHECK_HEADERS([linux/if_tun.h],
[], [AC_MSG_ERROR([Required header file missng])], [#include "$srcdir/src/have.h"]
)
;;
*bsd*|*dragonfly*|*darwin*)
AC_CHECK_HEADERS([net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h],
[], [], [#include "$srcdir/src/have.h"]
)
;;
*solaris*)
AC_CHECK_FUNC(socket, [], [AC_CHECK_LIB(socket, connect)])
;;
*)
;;
esac
AC_CACHE_SAVE
AC_ARG_ENABLE(legacy-protocol,

View file

@ -6,7 +6,7 @@ man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz
CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi sample-config.tar.gz
# Use `ginstall' in the definition of man_MANS to avoid
# confusion with the `install' target. The install rule transforms `ginstall'
@ -17,19 +17,19 @@ transform = s/ginstall/install/; @program_transform_name@
# see GNUmakefile and Makefile.maint.
sample-config.tar.gz: sample-config
GZIP=$(GZIP_ENV) $(AMTAR) chozf $@ --exclude .svn $<
$(AM_V_GEN)GZIP=$(GZIP_ENV) $(AMTAR) chozf $@ --exclude .svn $<
tincd.8.html: tincd.8
w3mman2html $? > $@
$(AM_V_GEN)w3mman2html $? > $@
tinc.8.html: tinc.8
w3mman2html $? > $@
$(AM_V_GEN)w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8
w3mman2html $? > $@
$(AM_V_GEN)w3mman2html $? > $@
tinc.conf.5.html: tinc.conf.5
w3mman2html $? > $@
$(AM_V_GEN)w3mman2html $? > $@
substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
@ -38,18 +38,18 @@ substitute = sed \
-e s,'@localstatedir\@',"$(localstatedir)",g
tincd.8: tincd.8.in
$(substitute) $? > $@
$(AM_V_GEN)$(substitute) $? > $@
tinc.8: tinc.8.in
$(substitute) $? > $@
$(AM_V_GEN)$(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in
$(substitute) $? > $@
$(AM_V_GEN)$(substitute) $? > $@
tinc.conf.5: tinc.conf.5.in
$(substitute) $? > $@
$(AM_V_GEN)$(substitute) $? > $@
tincinclude.texi: tincinclude.texi.in
$(substitute) $? > $@
$(AM_V_GEN)$(substitute) $? > $@
tinc.texi: tincinclude.texi

View file

@ -230,6 +230,30 @@ unknown and obsolete configuration variables, wrong public and/or private keys,
When problems are found, this will be printed on a line with WARNING or ERROR in front of it.
Most problems must be corrected by the user itself, however in some cases (like file permissions and missing public keys),
tinc will ask if it should fix the problem.
.It sign Op Ar filename
Sign a file with the local node's private key.
If no
.Ar filename
is given, the file is read from standard input.
The signed file is written to standard output.
.It verify Ar name Op Ar filename
Check the signature of a file against a node's public key.
The
.Ar name
of the node must be given,
or can be
.Li .
to check against the local node's public key, or
.Li *
to allow a signature from any node whose public key is known.
If no
.Ar filename
is given, the file is read from standard input.
If the verification is succesful,
a copy of the input with the signature removed is written to standard output,
and the exit code will be zero.
If the verification failed,
nothing will be written to standard output, and the exit code will be non-zero.
.El
.Sh EXAMPLES
Examples of some commands:

View file

@ -1,4 +1,4 @@
.Dd 2014-01-29
.Dd 2016-04-11
.Dt TINC.CONF 5
.\" Manual page created by:
.\" Ivo Timmermans
@ -42,7 +42,7 @@ the configuration file should be
and the host configuration files are now expected to be in
.Pa @sysconfdir@/tinc/hosts/ .
.Sh NAMES
Each tinc daemon should have a name that is unique in the network which it will be part of.
Each tinc daemon must have a name that is unique in the network which it will be part of.
The name will be used by other tinc daemons for identification.
The name has to be declared in the
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf
@ -266,6 +266,10 @@ Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
.It utun Pq OS X
Set type to utun.
This is only supported on OS X version 10.6.8 and higher, but doesn't require the tuntaposx module.
This mode should support both IPv4 and IPv6 packets.
.It tap Pq BSD and Linux
Set type to tap.
Tinc will expect packets read from the virtual network device
@ -551,7 +555,7 @@ variables can be specified, in which case each address will be tried until a wor
connection has been established.
.It Va Cipher Li = Ar cipher Pq blowfish
The symmetric cipher algorithm used to encrypt UDP packets.
Any cipher supported by OpenSSL is recognised.
Any cipher supported by LibreSSL or OpenSSL is recognised.
Furthermore, specifying
.Qq none
will turn off packet encryption.
@ -568,7 +572,7 @@ Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
10 (fast lzo) and 11 (best lzo).
.It Va Digest Li = Ar digest Pq sha1
The digest algorithm used to authenticate UDP packets.
Any digest supported by OpenSSL is recognised.
Any digest supported by LibreSSL or OpenSSL is recognised.
Furthermore, specifying
.Qq none
will turn off packet authentication.
@ -663,10 +667,18 @@ forwarding packets.
.Sh SCRIPTS
Apart from reading the server and host configuration files,
tinc can also run scripts at certain moments.
Under Windows (not Cygwin), the scripts should have the extension
Below is a list of filenames of scripts and a description of when they are run.
A script is only run if it exists and if it is executable.
.Pp
Scripts are run synchronously;
this means that tinc will temporarily stop processing packets until the called script finishes executing.
This guarantees that scripts will execute in the exact same order as the events that trigger them.
If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background.
.Pp
Under Windows (not Cygwin), the scripts must have the extension
.Pa .bat
or
.Pa cmd .
.Pa .cmd .
.Bl -tag -width indent
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
This is the most important script.
@ -675,6 +687,7 @@ If it is present it will be executed right after the tinc daemon has been starte
is used).
It should be used to set up the corresponding network interface,
but can also be used to start other things.
.Pp
Under Windows you can use the Network Connections control panel instead of creating this script.
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down
This script is started right before the tinc daemon quits (or when the last node becomes unreachable if
@ -772,7 +785,7 @@ its connection to the virtual network device.
.Sh SEE ALSO
.Xr tincd 8 ,
.Xr tinc 8 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa https://www.tinc-vpn.org/ ,
.Pa http://www.tldp.org/LDP/nag2/ .
.Pp
The full documentation for

View file

@ -15,7 +15,7 @@
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
Copyright @copyright{} 1998-2015 Ivo Timmermans,
Copyright @copyright{} 1998-2016 Ivo Timmermans,
Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>.
@ -43,7 +43,7 @@ permission notice identical to this one.
@vskip 0pt plus 1filll
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
Copyright @copyright{} 1998-2015 Ivo Timmermans,
Copyright @copyright{} 1998-2016 Ivo Timmermans,
Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>.
@ -70,6 +70,7 @@ permission notice identical to this one.
* Configuration::
* Running tinc::
* Controlling tinc::
* Invitations::
* Technical information::
* Platform specific information::
* About us::
@ -191,7 +192,7 @@ packets.
@cindex release
For an up to date list of supported platforms, please check the list on
our website:
@uref{http://www.tinc-vpn.org/platforms/}.
@uref{https://www.tinc-vpn.org/platforms/}.
@c
@c
@ -273,12 +274,7 @@ The tap driver can be loaded with @code{kldload if_tap}, or by adding @code{if_t
@node Configuration of OpenBSD kernels
@subsection Configuration of OpenBSD kernels
For OpenBSD version 2.9 and higher,
the tun driver is included in the default kernel configuration.
There is also a kernel patch from @uref{http://diehard.n-r-g.com/stuff/openbsd/}
which adds a tap device to OpenBSD which should work with tinc,
but with recent versions of OpenBSD,
a tun device can act as a tap device by setting the link0 option with ifconfig.
Recent versions of OpenBSD come with both tun and tap devices enabled in the default kernel configuration.
@c ==================================================================
@ -298,7 +294,7 @@ Tunneling IPv6 may not work on NetBSD's tun device.
For Solaris 8 (SunOS 5.8) and higher,
the tun driver may or may not be included in the default kernel configuration.
If it isn't, the source can be downloaded from @uref{http://vtun.sourceforge.net/tun/}.
For x86 and sparc64 architectures, precompiled versions can be found at @uref{http://www.monkey.org/~dugsong/fragroute/}.
For x86 and sparc64 architectures, precompiled versions can be found at @uref{https://www.monkey.org/~dugsong/fragroute/}.
If the @file{net/if_tun.h} header file is missing, install it from the source package.
@ -307,15 +303,14 @@ If the @file{net/if_tun.h} header file is missing, install it from the source pa
@subsection Configuration of Darwin (MacOS/X) kernels
Tinc on Darwin relies on a tunnel driver for its data acquisition from the kernel.
Tinc supports either the driver from @uref{http://tuntaposx.sourceforge.net/},
OS X version 10.6.8 and later have a built-in tun driver called "utun".
Tinc also supports the driver from @uref{http://tuntaposx.sourceforge.net/},
which supports both tun and tap style devices,
and also the driver from from @uref{http://chrisp.de/en/projects/tunnel.html}.
The former driver is recommended.
The tunnel driver must be loaded before starting tinc with the following command:
@example
kmodload tunnel
@end example
By default, tinc expects the tuntaposx driver to be installed.
To use the utun driver, set add @code{Device = utunX} to @file{tinc.conf},
where X is the desired number for the utun interface.
You can also omit the number, in which case the first free number will be chosen.
@c ==================================================================
@ -323,7 +318,7 @@ kmodload tunnel
@subsection Configuration of Windows
You will need to install the latest TAP-Win32 driver from OpenVPN.
You can download it from @uref{http://openvpn.sourceforge.net}.
You can download it from @uref{https://openvpn.net/index.php/open-source/downloads.html}.
Using the Network Connections control panel,
configure the TAP-Win32 network interface in the same way as you would do from the tinc-up script,
as explained in the rest of the documentation.
@ -335,13 +330,13 @@ as explained in the rest of the documentation.
@cindex requirements
@cindex libraries
Before you can configure or build tinc, you need to have the OpenSSL, zlib,
Before you can configure or build tinc, you need to have the LibreSSL or OpenSSL, zlib,
lzo, curses and readline libraries installed on your system. If you try to
configure tinc without having them installed, configure will give you an error
message, and stop.
@menu
* OpenSSL::
* LibreSSL/OpenSSL::
* zlib::
* lzo::
* libcurses::
@ -350,12 +345,13 @@ message, and stop.
@c ==================================================================
@node OpenSSL
@subsection OpenSSL
@node LibreSSL/OpenSSL
@subsection LibreSSL/OpenSSL
@cindex LibreSSL
@cindex OpenSSL
For all cryptography-related functions, tinc uses the functions provided
by the OpenSSL library.
by the LibreSSL or the OpenSSL library.
If this library is not installed, you wil get an error when configuring
tinc for build. Support for running tinc with other cryptographic libraries
@ -365,21 +361,23 @@ You can use your operating system's package manager to install this if
available. Make sure you install the development AND runtime versions
of this package.
If you have to install OpenSSL manually, you can get the source code
from @url{http://www.openssl.org/}. Instructions on how to configure,
build and install this package are included within the package. Please
make sure you build development and runtime libraries (which is the
If your operating system comes neither with LibreSSL or OpenSSL, you have to
install one manually. It is recommended that you get the latest version of
LibreSSL from @url{http://www.libressl.org/}. Instructions on how to
configure, build and install this package are included within the package.
Please make sure you build development and runtime libraries (which is the
default).
If you installed the OpenSSL libraries from source, it may be necessary
If you installed the LibreSSL or OpenSSL libraries from source, it may be necessary
to let configure know where they are, by passing configure one of the
--with-openssl-* parameters.
--with-openssl-* parameters. Note that you even have to use --with-openssl-* if you
are using LibreSSL.
@example
--with-openssl=DIR OpenSSL library and headers prefix
--with-openssl-include=DIR OpenSSL headers directory
--with-openssl=DIR LibreSSL/OpenSSL library and headers prefix
--with-openssl-include=DIR LibreSSL/OpenSSL headers directory
(Default is OPENSSL_DIR/include)
--with-openssl-lib=DIR OpenSSL library directory
--with-openssl-lib=DIR LibreSSL/OpenSSL library directory
(Default is OPENSSL_DIR/lib)
@end example
@ -390,7 +388,7 @@ to let configure know where they are, by passing configure one of the
The complete source code of tinc is covered by the GNU GPL version 2.
Since the license under which OpenSSL is distributed is not directly
compatible with the terms of the GNU GPL
@uref{http://www.openssl.org/support/faq.html#LEGAL2}, we
@uref{https://www.openssl.org/support/faq.html#LEGAL2}, we
include an exemption to the GPL (see also the file COPYING.README) to allow
everyone to create a statically or dynamically linked executable:
@ -406,8 +404,8 @@ we also present the following exemption:
@quotation
Hereby I grant a special exception to the tinc VPN project
(http://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library
(http://www.openssl.org).
(https://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library
(https://www.openssl.org).
Markus F.X.J. Oberhumer
@end quotation
@ -432,7 +430,7 @@ available. Make sure you install the development AND runtime versions
of this package.
If you have to install zlib manually, you can get the source code
from @url{http://www.gzip.org/zlib/}. Instructions on how to configure,
from @url{http://www.zlib.net/}. Instructions on how to configure,
build and install this package are included within the package. Please
make sure you build development and runtime libraries (which is the
default).
@ -456,7 +454,7 @@ available. Make sure you install the development AND runtime versions
of this package.
If you have to install lzo manually, you can get the source code
from @url{http://www.oberhumer.com/opensource/lzo/}. Instructions on how to configure,
from @url{https://www.oberhumer.com/opensource/lzo/}. Instructions on how to configure,
build and install this package are included within the package. Please
make sure you build development and runtime libraries (which is the
default).
@ -527,9 +525,7 @@ system startup scripts and sample configurations.
If you cannot use one of the precompiled packages, or you want to compile tinc
for yourself, you can use the source. The source is distributed under
the GNU General Public License (GPL). Download the source from the
@uref{http://www.tinc-vpn.org/download/, download page}, which has
the checksums of these files listed; you may wish to check these with
md5sum before continuing.
@uref{https://www.tinc-vpn.org/download/, download page}.
Tinc comes in a convenient autoconf/automake package, which you can just
treat the same as any other package. Which is just untar it, type
@ -566,19 +562,18 @@ The documentation that comes along with your distribution will tell you how to d
@node Darwin (MacOS/X) build environment
@subsection Darwin (MacOS/X) build environment
In order to build tinc on Darwin, you need to install the MacOS/X Developer Tools
from @uref{http://developer.apple.com/tools/macosxtools.html} and
a recent version of Fink from @uref{http://www.finkproject.org/}.
In order to build tinc on Darwin, you need to install Xcode from @uref{https://developer.apple.com/xcode/}.
It might also help to install a recent version of Fink from @uref{http://www.finkproject.org/}.
After installation use fink to download and install the following packages:
autoconf25, automake, dlcompat, m4, openssl, zlib and lzo.
You need to download and install LibreSSL (or OpenSSL) and LZO,
either directly from their websites (see @ref{Libraries}) or using Fink.
@c ==================================================================
@node Cygwin (Windows) build environment
@subsection Cygwin (Windows) build environment
If Cygwin hasn't already been installed, install it directly from
@uref{http://www.cygwin.com/}.
@uref{https://www.cygwin.com/}.
When tinc is compiled in a Cygwin environment, it can only be run in this environment,
but all programs, including those started outside the Cygwin environment, will be able to use the VPN.
@ -589,6 +584,7 @@ It will also support all features.
@subsection MinGW (Windows) build environment
You will need to install the MinGW environment from @uref{http://www.mingw.org}.
You also need to download and install LibreSSL (or OpenSSL) and LZO.
When tinc is compiled using MinGW it runs natively under Windows,
it is not necessary to keep MinGW installed.
@ -999,6 +995,12 @@ to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
@cindex utun
@item utun (OS X)
Set type to utun.
This is only supported on OS X version 10.6.8 and higher, but doesn't require the tuntaposx module.
This mode should support both IPv4 and IPv6 packets.
@item tap (BSD and Linux)
Set type to tap.
Tinc will expect packets read from the virtual network device
@ -1139,7 +1141,7 @@ until the burst has passed.
@cindex Name
@item Name = <@var{name}> [required]
This is a symbolic name for this connection.
The name should consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _), and is case sensitive.
The name must consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _), and is case sensitive.
If Name starts with a $, then the contents of the environment variable that follows will be used.
In that case, invalid characters will be converted to underscores.
@ -1307,7 +1309,7 @@ tried until a working connection has been established.
@cindex Cipher
@item Cipher = <@var{cipher}> (blowfish)
The symmetric cipher algorithm used to encrypt UDP packets using the legacy protocol.
Any cipher supported by OpenSSL is recognized.
Any cipher supported by LibreSSL or OpenSSL is recognized.
Furthermore, specifying "none" will turn off packet encryption.
It is best to use only those ciphers which support CBC mode.
This option has no effect for connections using the SPTPS protocol, which always use AES-256-CTR.
@ -1327,7 +1329,7 @@ Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
@cindex Digest
@item Digest = <@var{digest}> (sha1)
The digest algorithm used to authenticate UDP packets using the legacy protocol.
Any digest supported by OpenSSL is recognized.
Any digest supported by LibreSSL or OpenSSL is recognized.
Furthermore, specifying "none" will turn off packet authentication.
This option has no effect for connections using the SPTPS protocol, which always use HMAC-SHA-256.
@ -1402,7 +1404,7 @@ MAC addresses are notated like 0:1a:2b:3c:4d:5e.
Prefixlength is the number of bits set to 1 in the netmask part; for
example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes
/22. This conforms to standard CIDR notation as described in
@uref{http://www.ietf.org/rfc/rfc1519.txt, RFC1519}
@uref{https://www.ietf.org/rfc/rfc1519.txt, RFC1519}
A Subnet can be given a weight to indicate its priority over identical Subnets
owned by different nodes. The default weight is 10. Lower values indicate
@ -1433,6 +1435,14 @@ connection when broadcasting or forwarding packets.
@cindex scripts
Apart from reading the server and host configuration files,
tinc can also run scripts at certain moments.
Below is a list of filenames of scripts and a description of when they are run.
A script is only run if it exists and if it is executable.
Scripts are run synchronously;
this means that tinc will temporarily stop processing packets until the called script finishes executing.
This guarantees that scripts will execute in the exact same order as the events that trigger them.
If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background.
Under Windows (not Cygwin), the scripts should have the extension @file{.bat} or @file{.cmd}.
@table @file
@ -1443,6 +1453,7 @@ If it is present it will be executed right after the tinc daemon has been
started and has connected to the virtual network device.
It should be used to set up the corresponding network interface,
but can also be used to start other things.
Under Windows you can use the Network Connections control panel instead of creating this script.
@cindex tinc-down
@ -2487,6 +2498,23 @@ When problems are found, this will be printed on a line with WARNING or ERROR in
Most problems must be corrected by the user itself, however in some cases (like file permissions and missing public keys),
tinc will ask if it should fix the problem.
@cindex sign
@item sign [@var{filename}]
Sign a file with the local node's private key.
If no @var{filename} is given, the file is read from standard input.
The signed file is written to standard output.
@cindex verify
@item verify @var{name} [@var{filename}]
Check the signature of a file against a node's public key.
The @var{name} of the node must be given,
or can be "." to check against the local node's public key,
or "*" to allow a signature from any node whose public key is known.
If no @var{filename} is given, the file is read from standard input.
If the verification is succesful, a copy of the input with the signature removed is written to standard output, and the exit code will be zero.
If the verification failed, nothing will be written to standard output, and the exit code will be non-zero.
@end table
@c ==================================================================
@ -2573,6 +2601,159 @@ Quit.
@end table
@c ==================================================================
@node Invitations
@chapter Invitations
Invitations are an easy way to add new nodes to an existing VPN. Invitations
can be created on an existing node using the @code{tinc invite} command, which
generates a relatively short URL which can be given to someone else, who uses
the @code{tinc join} command to automatically set up tinc so it can connect to
the inviting node. The next sections describe how invitations actually work,
and how to further automate the invitations.
@menu
* How invitations work::
* Invitation file format::
* Writing an invitation-created script::
@end menu
@c ==================================================================
@node How invitations work
@section How invitations work
When an invitation is created on a node (which from now on we will call the
server) using the @code{tinc invite} command, an invitation file is created
that contains all the information necessary for the invitee (which we will call
the client) to create its configuration files. The invitation file is stays on
the server, but a URL is generated that has enough information for the client
to contact the server and to retrieve the invitation file. The whole URL is
around 80 characters long and looks like this:
@example
server.example.org:12345/cW1NhLHS-1WPFlcFio8ztYHvewTTKYZp8BjEKg3vbMtDz7w4
@end example
It is composed of four parts:
@example
hostname : port / keyhash cookie
@end example
The hostname and port tell the client how to reach the tinc daemon on the server.
The part after the slash looks like one blob, but is composed of two parts.
The keyhash is the hash of the public key of the server.
The cookie is a shared secret that identifies the client to the server.
When the client connects to the server in order to join the VPN, the client and
server will exchange temporary public keys. The client verifies that the hash
of the server's public key matches the keyhash from the invitation URL. If
not, it will immediately exit with an error. Otherwise, an ECDH exchange will
happen so the client and server can communicate privately with each other. The
client will then present the cookie to the server. The server uses this to
look up the corresponding invitation file it generated earlier. If it exists,
it will send the invitation file to the client. The client will also create a
permanent public key, and send it to the server. After the exchange is
completed, the connection is broken. The server creates a host config file for
the client containing the client's permanent public key, and the client creates
tinc.conf, host config files and possibly a tinc-up script based on the
information in the invitation file.
It is important that the invitation URL is kept secret until it is used; if
another person gets a copy of the invitation URL before the real client runs
the @code{tinc join} command, then that other person can try to join the VPN.
@c ==================================================================
@node Invitation file format
@section Invitation file format
The contents of an invitation file that is generated by the @code{tinc invite}
command looks like this:
@example
Name = client
Netname = vpn
ConnectTo = server
#-------------------------------------#
Name = server
Ed25519PublicKey = augbnwegoij123587...
Address = server.example.com
@end example
The file is basically a concatenation of several host config blocks. Each host
config block starts with @code{Name = ...}. Lines that look like @code{#---#}
are not important, it just makes it easier for humans to read the file.
The first host config block is always the one representing the invitee. So the
first Name statement determines the name that the invitee will get. From the
first block, the @file{tinc.conf} and @file{hosts/client} files will be
generated; the @code{tinc join} command on the client will automatically
separate statements based on whether they should be in @file{tinc.conf} or in a
host config file. Some statements are special and are treated differently:
@table @asis
@item Netname = <@var{netname}>
This is a hint to the invitee which netname to use for the VPN. It is used if
the invitee did not already specify a netname, and if there is no pre-existing
configuration with the same netname.
@cindex Ifconfig
@item Ifconfig = <@var{address}[/@var{netmask}] | dhcp | dhcp6 | slaac>
This is a hint for generating a @file{tinc-up} script.
If an address is specified, a command will be added to @file{tinc-up} so the VPN interface will be configured to have the given address.
If it is the word "dhcp", a command will be added to start a DHCP client on the VPN interface.
If it is the word dhcpv6, it will be a DHCPv6 client.
If it is "slaac", then it will add commands to enable IPv6 stateless address autoconfiguration.
It is also possible to specify a MAC address, in which case a command will be added to set the MAC address of the VPN interface.
The exact commands added to the @file{tinc-up} script depends on the operating system the client is using.
Multiple Ifconfig statements can be specified, however one should only use one Ifconfig statement per address family.
@cindex Route
@item Route = <@var{address}[/@var{netmask}]> [<@var{gateway}>]
This is a hint for generating a @file{tinc-up} script.
Route statements are similar to Ifconfig statements, but add routes instead of addresses.
These only allow IPv4 and IPv6 routes.
If no gateway address is specified, the route is directed to the VPN interface.
In general, a gateway is only necessary when running tinc in switch mode.
@end table
Subsequent host config blocks are copied verbatim into their respective files
in @file{hosts/}. The invitation file generated by @code{tinc invite} will
normally only contain two blocks; one for the client and one for the server.
@c ==================================================================
@node Writing an invitation-created script
@section Writing an invitation-created script
When an invitation is generated, the "invitation-created" script is called (if
it exists) right after the invitation file is written, but before the URL has
been written to stdout. This allows one to change the invitation file
automatically before the invitation URL is passed to the invitee. Here is an
example shell script that aproximately recreates the default invitation file:
@example
#!/bin/sh
cat >$INVITATION_FILE <<EOF
Name = $NODE
Netname = $NETNAME
ConnectTo = $NAME
#----------------#
EOF
tinc export >>$INVITATION_FILE
@end example
You can add more ConnectTo statements, and change `tinc export` to `tinc
export-all` for example. But you can also use the script to automatically hand
out a Subnet to the invitee. Note that the script doesn't have to be a shell script,
you can use any language, it just has to be executable.
@c ==================================================================
@node Technical information
@chapter Technical information
@ -3143,7 +3324,7 @@ 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.
encryption algorithm is always the default length used by LibreSSL/OpenSSL.
The SPTPS protocol is described in @ref{Simple Peer-to-Peer Security}.
For comparison, this is how SPTPS UDP packets look:
@ -3170,7 +3351,7 @@ this cannot be changed.
In August 2000, we discovered the existence of a security hole in all versions
of tinc up to and including 1.0pre2. This had to do with the way we exchanged
keys. Since then, we have been working on a new authentication scheme to make
tinc as secure as possible. The current version uses the OpenSSL library and
tinc as secure as possible. The current version uses the LibreSSL or OpenSSL library and
uses strong authentication with RSA keys.
On the 29th of December 2001, Jerome Etienne posted a security analysis of tinc
@ -3345,14 +3526,14 @@ Adding routes to IPv6 subnets:
@section Contact information
@cindex website
Tinc's website is at @url{http://www.tinc-vpn.org/},
Tinc's website is at @url{https://www.tinc-vpn.org/},
this server is located in the Netherlands.
@cindex IRC
We have an IRC channel on the FreeNode and OFTC IRC networks. Connect to
@uref{http://www.freenode.net/, irc.freenode.net}
@uref{https://freenode.net/, irc.freenode.net}
or
@uref{http://www.oftc.net/, irc.oftc.net}
@uref{https://www.oftc.net/, irc.oftc.net}
and join channel #tinc.

View file

@ -191,7 +191,7 @@ A lot, especially security auditing.
.Sh SEE ALSO
.Xr tinc 8 ,
.Xr tinc.conf 5 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa https://www.tinc-vpn.org/ ,
.Pa http://www.cabal.org/ .
.Pp
The full documentation for tinc is maintained as a Texinfo manual.

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
dnl Check to find the OpenSSL headers/libraries
dnl Check to find the LibreSSL/OpenSSL headers/libraries
AC_DEFUN([tinc_OPENSSL],
[
@ -10,47 +10,47 @@ AC_DEFUN([tinc_OPENSSL],
[],
[AC_CHECK_LIB(dl, dlopen,
[LIBS="$LIBS -ldl"],
[AC_MSG_ERROR([OpenSSL depends on libdl.]); break]
[AC_MSG_ERROR([LibreSSL/OpenSSL depends on libdl.]); break]
)]
)
;;
esac
AC_ARG_WITH(openssl,
AS_HELP_STRING([--with-openssl=DIR], [OpenSSL base directory, or:]),
AS_HELP_STRING([--with-openssl=DIR], [LibreSSL/OpenSSL base directory, or:]),
[openssl="$withval"
CPPFLAGS="$CPPFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"]
)
AC_ARG_WITH(openssl-include,
AS_HELP_STRING([--with-openssl-include=DIR], [OpenSSL headers directory (without trailing /openssl)]),
AS_HELP_STRING([--with-openssl-include=DIR], [LibreSSL/OpenSSL headers directory (without trailing /openssl)]),
[openssl_include="$withval"
CPPFLAGS="$CPPFLAGS -I$withval"]
)
AC_ARG_WITH(openssl-lib,
AS_HELP_STRING([--with-openssl-lib=DIR], [OpenSSL library directory]),
AS_HELP_STRING([--with-openssl-lib=DIR], [LibreSSL/OpenSSL library directory]),
[openssl_lib="$withval"
LDFLAGS="$LDFLAGS -L$withval"]
)
AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h],
[],
[AC_MSG_ERROR([OpenSSL header files not found.]); break]
[AC_MSG_ERROR([LibreSSL/OpenSSL header files not found.]); break]
)
AC_CHECK_LIB(crypto, EVP_EncryptInit_ex,
[LIBS="-lcrypto $LIBS"],
[AC_MSG_ERROR([OpenSSL libraries not found.])]
[AC_MSG_ERROR([LibreSSL/OpenSSL libraries not found.])]
)
AC_CHECK_FUNCS([RAND_status EVP_EncryptInit_ex], ,
[AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
[AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break],
)
AC_CHECK_DECLS([OpenSSL_add_all_algorithms], ,
[AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
[AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break],
[#include <openssl/evp.h>]
)
])

View file

@ -2,25 +2,26 @@
sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
## Make sure version.c is always rebuilt with the latest git information
.PHONY: ${srcdir}/version.c version_git.h
version_git.h:
echo >$@
-(cd $(srcdir) && git describe) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@
CLEANFILES = version_git.h
.PHONY: version-stamp
version-stamp:
version_git.h: version-stamp
$(AM_V_GEN)echo >$@
@-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||:
${srcdir}/version.c: version_git.h
## Now a hack to appease some versions of BSD make that don't understand that "./foo" is the same as "foo".
if BSD
version.c: ${srcdir}/version.c
endif
if LINUX
sbin_PROGRAMS += sptps_speed
endif
lib_LTLIBRARIES = libtincd.la libed25519.la libchacha_poly1305.la libtincconf.la
libchacha_poly1305_la_SOURCES = \
chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
libed25519_la_SOURCES = \
ed25519_SOURCES = \
ed25519/add_scalar.c \
ed25519/ed25519.h \
ed25519/fe.c ed25519/fe.h \
@ -31,26 +32,25 @@ libed25519_la_SOURCES = \
ed25519/precomp_data.h \
ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h \
ed25519/ecdsa.c \
ed25519/sign.c \
ed25519/verify.c
libtincconf_la_SOURCES = \
conf.h\
conf.c
chacha_poly1305_SOURCES = \
chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
libtincd_la_SOURCES = \
conf.h \
conf.c \
tincd_SOURCES = \
buffer.c buffer.h \
cipher.h \
conf.c conf.h \
connection.c connection.h \
control.c control.h \
control_common.h \
crypto.h \
device.h \
digest.h \
dropin.c \
dropin.c dropin.h \
dummy_device.c \
ecdh.h \
ecdsa.h \
@ -58,9 +58,6 @@ libtincd_la_SOURCES = \
edge.c edge.h \
ethernet.h \
event.c event.h \
fake-gai-errnos.h \
fake-getaddrinfo.c fake-getaddrinfo.h \
fake-getnameinfo.c fake-getnameinfo.h \
graph.c graph.h \
hash.c hash.h \
have.h \
@ -78,6 +75,7 @@ libtincd_la_SOURCES = \
netutl.c netutl.h \
node.c node.h \
prf.h \
process.c process.h \
protocol.c protocol.h \
protocol_auth.c \
protocol_edge.c \
@ -94,117 +92,189 @@ libtincd_la_SOURCES = \
subnet.c subnet.h \
subnet_parse.c \
system.h \
tincd.c \
utils.c utils.h \
xalloc.h \
version.c version.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
getopt.c getopt.h \
process.h process.c \
getopt1.c
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
tinc_SOURCES = \
dropin.c dropin.h \
fsck.c fsck.h \
ifconfig.c ifconfig.h \
info.c info.h \
invitation.c invitation.h \
list.c list.h \
names.c names.h \
netutl.c netutl.h \
script.c script.h \
sptps.c sptps.h \
subnet_parse.c subnet.h \
tincctl.c tincctl.h \
top.c top.h \
utils.c utils.h \
version.c version.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps_test_SOURCES = \
logger.c logger.h \
sptps.c sptps.h \
sptps_test.c \
utils.c utils.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps_keypair_SOURCES = \
sptps_keypair.c \
utils.c utils.h \
ed25519/ecdsagen.c \
$(ed25519_SOURCES)
sptps_speed_SOURCES = \
logger.c logger.h \
sptps.c sptps.h \
sptps_speed.c \
utils.c utils.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
## Conditionally compile device drivers
if !GETOPT
tincd_SOURCES += \
getopt.c getopt.h \
getopt1.c
tinc_SOURCES += \
getopt.c getopt.h \
getopt1.c
sptps_test_SOURCES += \
getopt.c getopt.h \
getopt1.c
sptps_keypair_SOURCES += \
getopt.c getopt.h \
getopt1.c
endif
if LINUX
libtincd_la_SOURCES += linux/device.c
tincd_SOURCES += linux/device.c
endif
if BSD
libtincd_la_SOURCES += bsd/device.c
tincd_SOURCES += bsd/device.c
if TUNEMU
libtincd_la_SOURCES += bsd/tunemu.c bsd/tunemu.h
tincd_SOURCES += bsd/tunemu.c bsd/tunemu.h
endif
endif
if SOLARIS
libtincd_la_SOURCES += solaris/device.c
tincd_SOURCES += solaris/device.c
endif
if MINGW
libtincd_la_SOURCES += mingw/device.c mingw/common.h
tincd_SOURCES += mingw/device.c mingw/common.h
endif
if CYGWIN
libtincd_la_SOURCES += cygwin/device.c
tincd_SOURCES += cygwin/device.c
endif
if UML
libtincd_la_SOURCES += uml_device.c
tincd_SOURCES += uml_device.c
endif
if VDE
libtincd_la_SOURCES += vde_device.c
tincd_SOURCES += vde_device.c
endif
if OPENSSL
libtincd_la_SOURCES += \
tincd_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
openssl/rsa.c
tinc_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
openssl/rsa.c \
openssl/rsagen.c
sptps_test_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c
sptps_keypair_SOURCES += \
openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c
else
if GCRYPT
libtincd_la_SOURCES += \
tincd_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/prf.c \
gcrypt/rsa.c
tinc_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/prf.c \
gcrypt/rsa.c \
gcrypt/rsagen.c
sptps_test_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/prf.c
sptps_keypair_SOURCES += \
openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c
else
libtincd_la_SOURCES += \
tincd_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
tinc_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
sptps_test_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
sptps_keypair_SOURCES += \
nolegacy/crypto.c
sptps_speed_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
endif
endif
tincd_SOURCES = \
conf.h \
tincd.c
tinc_SOURCES = \
invitation.c invitation.h \
top.c top.h \
fsck.c fsck.h \
info.c info.h \
ed25519/ecdsagen.c \
tincctl.c tincctl.h
sptps_test_SOURCES = \
sptps_test.c
sptps_keypair_SOURCES = \
ed25519/ecdsagen.c \
sptps_keypair.c
sptps_speed_SOURCES = \
ed25519/ecdsagen.c \
sptps_speed.c
tincd_LDADD = libtincd.la libed25519.la libchacha_poly1305.la libtincconf.la
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) libtincd.la libtincconf.la libed25519.la libchacha_poly1305.la
sptps_speed_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
sptps_test_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
sptps_keypair_LDADD = libed25519.la libtincconf.la libchacha_poly1305.la libtincd.la libchacha_poly1305.la
if !DARWIN
if !OPENBSD
sptps_speed_LDADD += -lrt
sptps_test_LDADD += -lrt
sptps_keypair_LDADD += -lrt
endif
endif
if MINIUPNPC
tincd_SOURCES += upnp.h upnp.c
tincd_LDADD += $(MINIUPNPC_LIBS)
tincd_LDFLAGS = ${tincd_LDFLAGS} -pthread
tincd_LDADD = $(MINIUPNPC_LIBS)
tincd_LDFLAGS = -pthread
endif
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
sptps_speed_LDADD = -lrt
LIBS = @LIBS@ -lm
if TUNEMU
@ -212,17 +282,3 @@ LIBS += -lpcap
endif
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote.
if OPENBSD
AM_CFLAGS += -fstack-protector-all
endif
if BSD
tincd_LDADD += -lexecinfo
tinc_LDADD += -lexecinfo
sptps_test_LDADD += -lexecinfo
sptps_keypair_LDADD += -lexecinfo
sptps_speed_LDADD += -lexecinfo
endif
#-fsanitize=address

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify
@ -34,13 +34,15 @@
#include "bsd/tunemu.h"
#endif
#define DEFAULT_TUN_DEVICE "/dev/tun0"
#if defined(HAVE_DARWIN) || defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
#define DEFAULT_TAP_DEVICE "/dev/tap0"
#else
#define DEFAULT_TAP_DEVICE "/dev/tun0"
#ifdef HAVE_NET_IF_UTUN_H
#include <sys/sys_domain.h>
#include <sys/kern_control.h>
#include <net/if_utun.h>
#endif
#define DEFAULT_TUN_DEVICE "/dev/tun0"
#define DEFAULT_TAP_DEVICE "/dev/tap0"
typedef enum device_type {
DEVICE_TYPE_TUN,
DEVICE_TYPE_TUNIFHEAD,
@ -48,6 +50,7 @@ typedef enum device_type {
#ifdef ENABLE_TUNEMU
DEVICE_TYPE_TUNEMU,
#endif
DEVICE_TYPE_UTUN,
} device_type_t;
int device_fd = -1;
@ -62,9 +65,64 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
static device_type_t device_type = DEVICE_TYPE_TUN;
#endif
#ifdef HAVE_NET_IF_UTUN_H
static bool setup_utun(void) {
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if(device_fd == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
return false;
}
struct ctl_info info = {};
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof info.ctl_name);
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
return false;
}
int unit = -1;
char *p = strstr(device, "utun"), *e = NULL;
if(p) {
unit = strtol(p + 4, &e, 10);
if(!e)
unit = -1;
}
struct sockaddr_ctl sc = {
.sc_id = info.ctl_id,
.sc_len = sizeof sc,
.sc_family = AF_SYSTEM,
.ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = unit + 1,
};
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
return false;
}
char name[64] = "";
socklen_t len = sizeof name;
if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) {
iface = xstrdup(device);
} else {
iface = xstrdup(name);
}
device_info = "OS X utun device";
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
}
#endif
static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
// Find out if it's supposed to be a tun or a tap device
char *type;
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "tun"))
@ -72,6 +130,10 @@ static bool setup_device(void) {
#ifdef ENABLE_TUNEMU
else if(!strcasecmp(type, "tunemu"))
device_type = DEVICE_TYPE_TUNEMU;
#endif
#ifdef HAVE_NET_IF_UTUN_H
else if(!strcasecmp(type, "utun"))
device_type = DEVICE_TYPE_UTUN;
#endif
else if(!strcasecmp(type, "tunnohead"))
device_type = DEVICE_TYPE_TUN;
@ -84,10 +146,22 @@ static bool setup_device(void) {
return false;
}
} else {
#ifdef HAVE_NET_IF_UTUN_H
if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0))
device_type = DEVICE_TYPE_UTUN;
else
#endif
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER)
device_type = DEVICE_TYPE_TAP;
}
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
logger(DEBUG_ALWAYS, LOG_ERR, "Only tap devices support switch mode!");
return false;
}
// Find out which device file to open
if(!device) {
if(device_type == DEVICE_TYPE_TAP)
device = xstrdup(DEFAULT_TAP_DEVICE);
@ -95,17 +169,7 @@ static bool setup_device(void) {
device = xstrdup(DEFAULT_TUN_DEVICE);
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = NULL;
#ifndef TAPGIFNAME
if (iface) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring specified interface name '%s' as device rename is not supported on this platform", iface);
free(iface);
iface = NULL;
}
#endif
if (!iface)
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
// Open the device
switch(device_type) {
#ifdef ENABLE_TUNEMU
@ -114,6 +178,10 @@ static bool setup_device(void) {
device_fd = tunemu_open(dynamic_name);
}
break;
#endif
#ifdef HAVE_NET_IF_UTUN_H
case DEVICE_TYPE_UTUN:
return setup_utun();
#endif
default:
device_fd = open(device, O_RDWR | O_NONBLOCK);
@ -128,6 +196,27 @@ static bool setup_device(void) {
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
// Guess what the corresponding interface is called
char *realname;
#if defined(HAVE_FDEVNAME)
realname = fdevname(device_fd) ? : device;
#elif defined(HAVE_DEVNAME)
struct stat buf;
if(!fstat(device_fd, &buf))
realname = devname(buf.st_rdev, S_IFCHR) ? : device;
#else
realname = device;
#endif
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname))
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
// Configure the device as best as we can
switch(device_type) {
default:
device_type = DEVICE_TYPE_TUN;
@ -192,6 +281,11 @@ static bool setup_device(void) {
#endif
}
#ifdef SIOCGIFADDR
if(overwrite_mac)
ioctl(device_fd, SIOCGIFADDR, mymac.x);
#endif
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
@ -253,31 +347,29 @@ static bool read_packet(vpn_packet_t *packet) {
packet->len = inlen + 14;
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}};
if((inlen = readv(device_fd, vector, 2)) <= 0) {
if((inlen = read(device_fd, DATA(packet) + 10, MTU - 10)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
switch (ntohl(type)) {
case AF_INET:
switch (DATA(packet)[14] >> 4) {
case 4:
DATA(packet)[12] = 0x08;
DATA(packet)[13] = 0x00;
break;
case AF_INET6:
case 6:
DATA(packet)[12] = 0x86;
DATA(packet)[13] = 0xDD;
break;
default:
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while reading packet from %s %s",
ntohl(type), device_info, device);
"Unknown IP version %d while reading packet from %s %s",
DATA(packet)[14] >> 4, device_info, device);
return false;
}
@ -319,12 +411,10 @@ static bool write_packet(vpn_packet_t *packet) {
}
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}};
int af;
af = (DATA(packet)[12] << 8) + DATA(packet)[13];
int af = (DATA(packet)[12] << 8) + DATA(packet)[13];
uint32_t type;
switch (af) {
case 0x0800:
@ -340,7 +430,9 @@ static bool write_packet(vpn_packet_t *packet) {
return false;
}
if(writev(device_fd, vector, 2) < 0) {
memcpy(DATA(packet) + 10, &type, sizeof type);
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;

View file

@ -21,8 +21,9 @@
#ifndef __TINC_CONF_H__
#define __TINC_CONF_H__
#include "splay_tree.h"
#include "list.h"
#include "splay_tree.h"
#include "subnet.h"
typedef struct config_t {
char *variable;
@ -31,7 +32,6 @@ typedef struct config_t {
int line;
} config_t;
#include "subnet.h"
extern splay_tree_t *config_tree;
extern bool use_logfile;

View file

@ -19,6 +19,7 @@
*/
#include "../system.h"
#include "../net.h"
#include <w32api/windows.h>
#include <w32api/winioctl.h>
@ -27,7 +28,6 @@
#include "../device.h"
#include "../logger.h"
#include "../names.h"
#include "../net.h"
#include "../route.h"
#include "../utils.h"
#include "../xalloc.h"
@ -59,6 +59,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface)
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {

View file

@ -1,7 +1,7 @@
/*
dropin.c -- a set of drop-in replacements for libc functions
Copyright (C) 2000-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -86,40 +86,6 @@ int daemon(int nochdir, int noclose) {
}
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
/*
Replacement for the GNU get_current_dir_name function:
get_current_dir_name will malloc(3) an array big enough to hold the
current directory name. If the environment variable PWD is set, and
its value is correct, then that value will be returned.
*/
char *get_current_dir_name(void) {
size_t size;
char *buf;
char *r;
/* Start with 100 bytes. If this turns out to be insufficient to
contain the working directory, double the size. */
size = 100;
buf = xmalloc(size);
errno = 0; /* Success */
r = getcwd(buf, size);
/* getcwd returns NULL and sets errno to ERANGE if the bufferspace
is insufficient to contain the entire working directory. */
while(r == NULL && errno == ERANGE) {
free(buf);
size <<= 1; /* double the size */
buf = xmalloc(size);
r = getcwd(buf, size);
}
return buf;
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **buf, const char *fmt, ...) {
int result;
@ -174,10 +140,9 @@ int gettimeofday(struct timeval *tv, void *tz) {
}
#endif
#ifndef HAVE_USLEEP
int usleep(long long usec) {
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
select(0, NULL, NULL, NULL, &tv);
return 0;
#ifndef HAVE_NANOSLEEP
int nanosleep(const struct timespec *req, struct timespec *rem) {
struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
return select(0, NULL, NULL, NULL, &tv);
}
#endif

View file

@ -1,7 +1,7 @@
/*
dropin.h -- header file for dropin.c
Copyright (C) 2000-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,17 +21,10 @@
#ifndef __DROPIN_H__
#define __DROPIN_H__
#include "fake-getaddrinfo.h"
#include "fake-getnameinfo.h"
#ifndef HAVE_DAEMON
extern int daemon(int, int);
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
extern char *get_current_dir_name(void);
#endif
#ifndef HAVE_ASPRINTF
extern int asprintf(char **, const char *, ...);
extern int vasprintf(char **, const char *, va_list ap);
@ -41,8 +34,8 @@ extern int vasprintf(char **, const char *, va_list ap);
extern int gettimeofday(struct timeval *, void *);
#endif
#ifndef HAVE_USLEEP
extern int usleep(long long usec);
#ifndef HAVE_NANOSLEEP
extern int nanosleep(const struct timespec *req, struct timespec *rem);
#endif
#ifndef timeradd
@ -70,4 +63,8 @@ extern int usleep(long long usec);
#endif
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM 0
#endif
#endif /* __DROPIN_H__ */

View file

@ -1,23 +0,0 @@
/*
* fake library for ssh
*
* This file is included in getaddrinfo.c and getnameinfo.c.
* See getaddrinfo.c and getnameinfo.c.
*/
/* for old netdb.h */
#ifndef EAI_NODATA
#define EAI_NODATA 1
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY 2
#endif
#ifndef EAI_FAMILY
#define EAI_FAMILY 3
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM 4
#endif

View file

@ -1,102 +0,0 @@
/*
* fake library for ssh
*
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
* These funtions are defined in rfc2133.
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For exapmle, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include "system.h"
#include "ipv4.h"
#include "ipv6.h"
#include "fake-getaddrinfo.h"
#include "xalloc.h"
#if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode) {
switch (ecode) {
case EAI_NODATA:
return "No address associated with hostname";
case EAI_MEMORY:
return "Memory allocation failure";
case EAI_FAMILY:
return "Address family not supported";
default:
return "Unknown error";
}
}
#endif /* !HAVE_GAI_STRERROR */
#if !HAVE_DECL_FREEADDRINFO
void freeaddrinfo(struct addrinfo *ai) {
struct addrinfo *next;
while(ai) {
next = ai->ai_next;
free(ai);
ai = next;
}
}
#endif /* !HAVE_FREEADDRINFO */
#if !HAVE_DECL_GETADDRINFO
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
struct addrinfo *ai;
ai = xzalloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
ai->ai_addr = (struct sockaddr *)(ai + 1);
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
return ai;
}
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
struct addrinfo *prev = NULL;
struct hostent *hp;
struct in_addr in = {0};
int i;
uint16_t port = 0;
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)
return EAI_FAMILY;
if (servname)
port = htons(atoi(servname));
if (hints && hints->ai_flags & AI_PASSIVE) {
*res = malloc_ai(port, htonl(0x00000000));
return 0;
}
if (!hostname) {
*res = malloc_ai(port, htonl(0x7f000001));
return 0;
}
hp = gethostbyname(hostname);
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
return EAI_NODATA;
for (i = 0; hp->h_addr_list[i]; i++) {
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
if(prev)
prev->ai_next = *res;
prev = *res;
}
return 0;
}
#endif /* !HAVE_GETADDRINFO */

View file

@ -1,46 +0,0 @@
#ifndef _FAKE_GETADDRINFO_H
#define _FAKE_GETADDRINFO_H
#include "fake-gai-errnos.h"
#ifndef AI_PASSIVE
# define AI_PASSIVE 1
# define AI_CANONNAME 2
#endif
#ifndef NI_NUMERICHOST
# define NI_NUMERICHOST 2
# define NI_NAMEREQD 4
# define NI_NUMERICSERV 8
#endif
#ifndef AI_NUMERICHOST
#define AI_NUMERICHOST 4
#endif
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
#endif /* !HAVE_STRUCT_ADDRINFO */
#if !HAVE_DECL_GETADDRINFO
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
#endif /* !HAVE_GETADDRINFO */
#if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode);
#endif /* !HAVE_GAI_STRERROR */
#if !HAVE_DECL_FREEADDRINFO
void freeaddrinfo(struct addrinfo *ai);
#endif /* !HAVE_FREEADDRINFO */
#endif /* _FAKE_GETADDRINFO_H */

View file

@ -1,54 +0,0 @@
/*
* fake library for ssh
*
* This file includes getnameinfo().
* These funtions are defined in rfc2133.
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For exapmle, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include "system.h"
#include "fake-getnameinfo.h"
#include "fake-getaddrinfo.h"
#if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct hostent *hp;
int len;
if(sa->sa_family != AF_INET)
return EAI_FAMILY;
if(serv && servlen) {
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
if(len < 0 || len >= servlen)
return EAI_MEMORY;
}
if(!host || !hostlen)
return 0;
if(flags & NI_NUMERICHOST) {
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
if(len < 0 || len >= hostlen)
return EAI_MEMORY;
return 0;
}
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
if(!hp || !hp->h_name || !hp->h_name[0])
return EAI_NODATA;
len = snprintf(host, hostlen, "%s", hp->h_name);
if(len < 0 || len >= hostlen)
return EAI_MEMORY;
return 0;
}
#endif /* !HAVE_GETNAMEINFO */

View file

@ -1,15 +0,0 @@
#ifndef _FAKE_GETNAMEINFO_H
#define _FAKE_GETNAMEINFO_H
#if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
#endif /* !HAVE_GETNAMEINFO */
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif /* !NI_MAXSERV */
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif /* !NI_MAXHOST */
#endif /* _FAKE_GETNAMEINFO_H */

View file

@ -217,6 +217,7 @@ int fsck(const char *argv0) {
return 1;
}
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
if(st.st_mode & 077) {
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
if(st.st_uid != uid) {
@ -228,6 +229,7 @@ int fsck(const char *argv0) {
fprintf(stderr, "Fixed permissions of %s.\n", fname);
}
}
#endif
}
#endif
@ -256,6 +258,7 @@ int fsck(const char *argv0) {
return 1;
}
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
if(st.st_mode & 077) {
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
if(st.st_uid != uid) {
@ -267,6 +270,7 @@ int fsck(const char *argv0) {
fprintf(stderr, "Fixed permissions of %s.\n", fname);
}
}
#endif
}
#ifdef DISABLE_LEGACY
@ -282,7 +286,7 @@ int fsck(const char *argv0) {
}
// Check for public keys.
// TODO: use RSAPublicKeyFile and Ed25519PublicKeyFile variables if present.
// TODO: use RSAPublicKeyFile variable if present.
snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, name);
if(access(fname, R_OK))
@ -343,13 +347,17 @@ int fsck(const char *argv0) {
fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
}
#endif
//
// TODO: this should read the Ed25519PublicKey config variable instead.
ecdsa_t *ecdsa_pub = NULL;
f = fopen(fname, "r");
if(f)
ecdsa_pub = ecdsa_read_pem_public_key(f);
if(f) {
ecdsa_pub = get_pubkey(f);
if(!f) {
rewind(f);
ecdsa_pub = ecdsa_read_pem_public_key(f);
}
}
fclose(f);
if(ecdsa_priv) {

View file

@ -1,67 +0,0 @@
/*
ecdsa.c -- ECDSA key handling
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../logger.h"
#include "../ecdsa.h"
#include "../utils.h"
#include "../xalloc.h"
// Get and set ECDSA keys
//
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
return NULL;
}
// Read PEM ECDSA keys
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
size_t ecdsa_size(ecdsa_t *ecdsa) {
return 0;
}
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
return false;
}
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
return false;
}
bool ecdsa_active(ecdsa_t *ecdsa) {
return false;
}
void ecdsa_free(ecdsa_t *ecdsa) {
}

View file

@ -1,41 +0,0 @@
/*
ecdsagen.c -- ECDSA key generation and export
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../ecdsagen.h"
#include "../utils.h"
#include "../xalloc.h"
// Generate ECDSA key
ecdsa_t *ecdsa_generate(void) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
// Write PEM ECDSA keys
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}

View file

@ -19,11 +19,88 @@
#include "../system.h"
#include "digest.h"
#include "../digest.h"
#include "../prf.h"
#include "../ed25519/sha512.h"
static void memxor(char *buf, char c, size_t len) {
for(size_t i = 0; i < len; i++)
buf[i] ^= c;
}
static const size_t mdlen = 64;
static const size_t blklen = 128;
static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) {
char tmp[blklen + mdlen];
sha512_context md;
if(keylen <= blklen) {
memcpy(tmp, key, keylen);
memset(tmp + keylen, 0, blklen - keylen);
} else {
if(sha512(key, keylen, tmp) != 0)
return false;
memset(tmp + mdlen, 0, blklen - mdlen);
}
if(sha512_init(&md) != 0)
return false;
// ipad
memxor(tmp, 0x36, blklen);
if(sha512_update(&md, tmp, blklen) != 0)
return false;
// message
if(sha512_update(&md, msg, msglen) != 0)
return false;
if(sha512_final(&md, tmp + blklen) != 0)
return false;
// opad
memxor(tmp, 0x36 ^ 0x5c, blklen);
if(sha512(tmp, sizeof tmp, out) != 0)
return false;
return true;
}
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
We use SHA512 instead of MD5 and SHA1.
*/
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
logger(DEBUG_ALWAYS, LOG_ERR, "PRF support using libgcrypt not implemented");
return false;
/* Data is what the "inner" HMAC function processes.
It consists of the previous HMAC result plus the seed.
*/
char data[mdlen + seedlen];
memset(data, 0, mdlen);
memcpy(data + mdlen, seed, seedlen);
char hash[mdlen];
while(outlen > 0) {
/* Inner HMAC */
if(!hmac_sha512(secret, secretlen, data, sizeof data, data))
return false;
/* Outer HMAC */
if(outlen >= mdlen) {
if(!hmac_sha512(secret, secretlen, data, sizeof data, out))
return false;
out += mdlen;
outlen -= mdlen;
} else {
if(!hmac_sha512(secret, secretlen, data, sizeof data, hash))
return false;
memcpy(out, hash, outlen);
out += outlen;
outlen = 0;
}
}
return true;
}

View file

@ -1,7 +1,7 @@
/*
have.h -- include headers which are known to exist
Copyright (C) 1998-2005 Ivo Timmermans
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,17 +22,14 @@
#define __TINC_HAVE_H__
#ifdef HAVE_MINGW
#ifdef WITH_WINDOWS2000
#define WINVER Windows2000
#else
#define WINVER WindowsXP
#endif
#define WIN32_LEAN_AND_MEAN
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
@ -41,6 +38,7 @@
#include <unistd.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#ifdef HAVE_MINGW
#include <w32api.h>
@ -49,10 +47,6 @@
#include <ws2tcpip.h>
#endif
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
@ -71,9 +65,6 @@
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -103,10 +94,6 @@
#include <sys/resource.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
@ -210,6 +197,12 @@
#include <linux/if_tun.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "getopt.h"
#endif
#ifdef STATUS
#undef STATUS
#endif

198
src/ifconfig.c Normal file
View file

@ -0,0 +1,198 @@
/*
ifconfig.c -- Generate platform specific interface configuration commands
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include "conf.h"
#include "ifconfig.h"
#include "subnet.h"
static long start;
#ifndef HAVE_MINGW
void ifconfig_header(FILE *out) {
fprintf(out, "#!/bin/sh\n");
start = ftell(out);
}
void ifconfig_dhcp(FILE *out) {
fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
}
void ifconfig_dhcp6(FILE *out) {
fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
}
void ifconfig_slaac(FILE *out) {
#ifdef HAVE_LINUX
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
#else
fprintf(out, "rtsol \"$INTERFACE\" &\n");
#endif
}
bool ifconfig_footer(FILE *out) {
if(ftell(out) == start) {
fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
return false;
} else {
#ifdef HAVE_LINUX
fprintf(out, "ip link set \"$INTERFACE\" up\n");
#else
fprintf(out, "ifconfig \"$INTERFACE\" up\n");
#endif
return true;
}
}
#else
void ifconfig_header(FILE *out) {
start = ftell(out);
}
void ifconfig_dhcp(FILE *out) {
fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n");
}
void ifconfig_dhcp6(FILE *out) {
fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
}
void ifconfig_slaac(FILE *out) {
// It's the default?
}
bool ifconfig_footer(FILE *out) {
return ftell(out) != start;
}
#endif
static subnet_t ipv4, ipv6;
void ifconfig_address(FILE *out, const char *value) {
subnet_t address = {};
char address_str[MAXNETSTR];
if(!str2net(&address, value) || !net2str(address_str, sizeof address_str, &address)) {
fprintf(stderr, "Could not parse address in Ifconfig statement\n");
return;
}
switch(address.type) {
case SUBNET_IPV4: ipv4 = address; break;
case SUBNET_IPV6: ipv6 = address; break;
default: return;
}
#if defined(HAVE_LINUX)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
default: return;
}
#elif defined(HAVE_BSD)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str); break;
default: return;
}
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", address_str); break;
default: return;
}
#endif
}
void ifconfig_route(FILE *out, const char *value) {
subnet_t subnet = {}, gateway = {};
char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
char *sep = strchr(value, ' ');
if(sep)
*sep++ = 0;
if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof subnet_str, &subnet) || subnet.type == SUBNET_MAC) {
fprintf(stderr, "Could not parse subnet in Route statement\n");
return;
}
if(sep) {
if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof gateway_str, &gateway) || gateway.type != subnet.type) {
fprintf(stderr, "Could not parse gateway in Route statement\n");
return;
}
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
}
#if defined(HAVE_LINUX)
if(*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
default: return;
}
} else {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
case SUBNET_IPV6: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
default: return;
}
}
#elif defined(HAVE_BSD)
// BSD route command is silly and doesn't accept an interface name as a destination.
if(!*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4:
if(!ipv4.type) {
fprintf(stderr, "Route requested but no Ifconfig\n");
return;
}
net2str(gateway_str, sizeof gateway_str, &ipv4);
break;
case SUBNET_IPV6:
if(!ipv6.type) {
fprintf(stderr, "Route requested but no Ifconfig\n");
return;
}
net2str(gateway_str, sizeof gateway_str, &ipv6);
break;
default: return;
}
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
}
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "route add %s %s\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str); break;
default: return;
}
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
if(*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
default: return;
}
} else {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
default: return;
}
}
#endif
}

View file

@ -1,6 +1,6 @@
/*
ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
ifconfig.h -- header for ifconfig.c.
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,21 +17,15 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#ifndef __TINC_IFCONFIG_H__
#define __TINC_IFCONFIG_H__
#include "../ecdh.h"
#include "../logger.h"
#include "../utils.h"
#include "../xalloc.h"
extern void ifconfig_dhcp(FILE *out);
extern void ifconfig_dhcp6(FILE *out);
extern void ifconfig_slaac(FILE *out);
extern void ifconfig_address(FILE *out, const char *value);
extern void ifconfig_route(FILE *out, const char *value);
extern void ifconfig_header(FILE *out);
extern bool ifconfig_footer(FILE *out);
ecdh_t *ecdh_generate_public(void *pubkey) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
return false
}
void ecdh_free(ecdh_t *ecdh) {
}
#endif

View file

@ -23,12 +23,14 @@
#include "crypto.h"
#include "ecdsa.h"
#include "ecdsagen.h"
#include "ifconfig.h"
#include "invitation.h"
#include "names.h"
#include "netutl.h"
#include "rsagen.h"
#include "script.h"
#include "sptps.h"
#include "subnet.h"
#include "tincctl.h"
#include "utils.h"
#include "xalloc.h"
@ -390,7 +392,7 @@ int cmd_invite(int argc, char *argv[]) {
// Fill in the details.
fprintf(f, "Name = %s\n", argv[1]);
if(netname)
if(check_netname(netname, true))
fprintf(f, "NetName = %s\n", netname);
fprintf(f, "ConnectTo = %s\n", myname);
@ -539,12 +541,17 @@ static bool finalize_join(void) {
}
if(!check_id(name)) {
fprintf(stderr, "Invalid Name found in invitation: %s!\n", name);
fprintf(stderr, "Invalid Name found in invitation!\n");
return false;
}
if(!netname)
if(!netname) {
netname = grep(data, "NetName");
if(netname && !check_netname(netname, true)) {
fprintf(stderr, "Unsafe NetName found in invitation!\n");
return false;
}
}
bool ask_netname = false;
char temp_netname[32];
@ -602,7 +609,19 @@ make_names:
return false;
}
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
FILE *fup = fopen(filename, "w");
if(!fup) {
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
fclose(f);
fclose(fh);
return false;
}
ifconfig_header(fup);
// Filter first chunk on approved keywords, split between tinc.conf and hosts/Name
// Generate a tinc-up script from Ifconfig and Route keywords.
// Other chunks go unfiltered to their respective host config files
const char *p = data;
char *l, *value = NULL;
@ -641,6 +660,24 @@ make_names:
break;
}
// Handle Ifconfig and Route statements
if(!found) {
if(!strcasecmp(l, "Ifconfig")) {
if(!strcasecmp(value, "dhcp"))
ifconfig_dhcp(fup);
else if(!strcasecmp(value, "dhcp6"))
ifconfig_dhcp6(fup);
else if(!strcasecmp(value, "slaac"))
ifconfig_slaac(fup);
else
ifconfig_address(fup, value);
continue;
} else if(!strcasecmp(l, "Route")) {
ifconfig_route(fup, value);
continue;
}
}
// Ignore unknown and unsafe variables
if(!found) {
fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l);
@ -655,6 +692,8 @@ make_names:
}
fclose(f);
bool valid_tinc_up = ifconfig_footer(fup);
fclose(fup);
while(l && !strcasecmp(l, "Name")) {
if(!check_id(value)) {
@ -769,6 +808,60 @@ ask_netname:
make_names(false);
}
char filename2[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
snprintf(filename2, sizeof filename2, "%s" SLASH "tinc-up", confbase);
if(valid_tinc_up) {
if(tty) {
FILE *fup = fopen(filename, "r");
if(fup) {
fprintf(stderr, "\nPlease review the following tinc-up script:\n\n");
char buf[MAXSIZE];
while(fgets(buf, sizeof buf, fup))
fputs(buf, stderr);
fclose(fup);
int response = 0;
do {
fprintf(stderr, "\nDo you want to use this script [y]es/[n]o/[e]dit? ");
response = tolower(getchar());
} while(!strchr("yne", response));
fprintf(stderr, "\n");
if(response == 'e') {
char *command;
#ifndef HAVE_MINGW
xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
#else
xasprintf(&command, "edit \"%s\"", filename);
#endif
if(system(command))
response = 'n';
else
response = 'y';
free(command);
}
if(response == 'y') {
rename(filename, filename2);
chmod(filename2, 0755);
fprintf(stderr, "tinc-up enabled.\n");
} else {
fprintf(stderr, "tinc-up has been left disabled.\n");
}
}
} else {
fprintf(stderr, "A tinc-up script was generated, but has been left disabled.\n");
}
} else {
// A placeholder was generated.
rename(filename, filename2);
chmod(filename2, 0755);
}
fprintf(stderr, "Configuration stored in: %s\n", confbase);
return true;

View file

@ -1,7 +1,7 @@
/*
ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
2006-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -29,29 +29,6 @@
#define IPPROTO_ICMPV6 58
#endif
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} in6_u;
} __attribute__ ((__gcc_struct__, __packed__));
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
#endif
#ifndef HAVE_STRUCT_SOCKADDR_IN6
struct sockaddr_in6 {
uint16_t sin6_family;
uint16_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
} __attribute__ ((__gcc_struct__, __packed__));
#endif
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \
((((__const uint32_t *) (a))[0] == 0) \

View file

@ -101,6 +101,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface)
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {

View file

@ -162,7 +162,7 @@ static void close_device(void) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) {
if((lenin = recv(device_fd, (void *)DATA(packet), MTU, 0)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, sockstrerror(sockerrno));
return false;
@ -185,7 +185,7 @@ static bool write_packet(vpn_packet_t *packet) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(sendto(device_fd, DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
if(sendto(device_fd, (void *)DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
sockstrerror(sockerrno));
return false;

View file

@ -57,14 +57,14 @@ void make_names(bool daemon) {
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) {
confdir = xstrdup(installdir);
if(!logfilename)
xasprintf(&logfilename, "%s" SLASH "log" SLASH "%s.log", installdir, identname);
if(!confbase) {
if(netname)
xasprintf(&confbase, "%s" SLASH "%s", installdir, netname);
else
xasprintf(&confbase, "%s", installdir);
}
if(!logfilename)
xasprintf(&logfilename, "%s" SLASH "tinc.log", confbase);
}
RegCloseKey(key);
}
@ -121,11 +121,11 @@ void make_names(bool daemon) {
if(!unixsocketname) {
int len = strlen(pidfilename);
unixsocketname = xmalloc(len + 8);
strcpy(unixsocketname, pidfilename);
memcpy(unixsocketname, pidfilename, len);
if(len > 4 && !strcmp(pidfilename + len - 4, ".pid"))
strcpy(unixsocketname + len - 4, ".socket");
strncpy(unixsocketname + len - 4, ".socket", 8);
else
strcpy(unixsocketname + len, ".socket");
strncpy(unixsocketname + len, ".socket", 8);
}
}
@ -137,4 +137,12 @@ void free_names(void) {
free(logfilename);
free(confbase);
free(confdir);
identname = NULL;
netname = NULL;
unixsocketname = NULL;
pidfilename = NULL;
logfilename = NULL;
confbase = NULL;
confdir = NULL;
}

View file

@ -180,7 +180,7 @@ static void periodic_handler(void *data) {
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
usleep(sleeptime * 1000000LL);
nanosleep(&(struct timespec){sleeptime, 0}, NULL);
sleeptime *= 2;
if(sleeptime < 0)
sleeptime = 3600;
@ -209,13 +209,25 @@ static void periodic_handler(void *data) {
and we are not already trying to make one, create an
outgoing connection to this node.
*/
splay_tree_t *tmp_node_tree;
int count = 0;
for splay_each(node_t, n, node_tree) {
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable))
continue;
count++;
}
tmp_node_tree = splay_alloc_tree((splay_compare_t) node_compare, NULL);
if(!count) {
logger(DEBUG_ALWAYS, LOG_INFO, "No more nodes available for autoconnect!");
goto end;
}
int r = rand() % count;
for splay_each(node_t, n, node_tree) {
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable))
continue;
if ((!n->status.has_known_address && !n->status.has_cfg_address) || n->connection)
if(r--)
continue;
bool found = false;
@ -226,29 +238,8 @@ static void periodic_handler(void *data) {
break;
}
}
if (!found)
splay_insert(tmp_node_tree, n);
}
if (tmp_node_tree->count) {
int r = rand() % tmp_node_tree->count;
int i = 0;
for splay_each(node_t, n, tmp_node_tree) {
if(i++ != r)
continue;
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
outgoing_t *outgoing = xzalloc(sizeof *outgoing);
outgoing->name = xstrdup(n->name);
list_insert_tail(outgoing_list, outgoing);
setup_outgoing_connection(outgoing);
}
} else {
logger(DEBUG_ALWAYS, LOG_INFO, "No more nodes available for autoconnect!");
break;
}
splay_delete_tree(tmp_node_tree);
} else if(nc > 3) {
/* Too many active connections, try to remove one.
Choose a random outgoing connection to a node
@ -295,6 +286,7 @@ static void periodic_handler(void *data) {
}
}
end:
timeout_set(data, &(struct timeval){5, rand() % 100000});
}
@ -352,9 +344,14 @@ int reload_configuration(void) {
for splay_each(subnet_t, subnet, subnet_tree)
if (subnet->owner)
subnet->expires = 1;
}
load_all_nodes();
for splay_each(node_t, n, node_tree)
n->status.has_address = false;
load_all_nodes();
if(strictsubnets) {
for splay_each(subnet_t, subnet, subnet_tree) {
if (!subnet->owner)
continue;
@ -455,7 +452,7 @@ void retry(void) {
*/
int main_loop(void) {
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000});
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){0, 0});
#ifndef HAVE_MINGW
signal_t sighup;

View file

@ -1,7 +1,7 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -115,6 +115,7 @@ typedef struct listen_socket_t {
io_t udp;
sockaddr_t sa;
bool bindto;
int priority;
} listen_socket_t;
#include "conf.h"

View file

@ -1,7 +1,7 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2010 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com>
@ -622,10 +622,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
vpn_packet_t *outpkt;
int origlen = origpkt->len;
size_t outlen;
#if defined(SOL_IP) && defined(IP_TOS)
static int priority = 0;
int origpriority = origpkt->priority;
#endif
pkt1.offset = DEFAULT_PACKET_OFFSET;
pkt2.offset = DEFAULT_PACKET_OFFSET;
@ -720,17 +717,29 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(!sa)
choose_udp_address(n, &sa, &sock);
#if defined(SOL_IP) && defined(IP_TOS)
if(priorityinheritance && origpriority != priority
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
}
if(priorityinheritance && origpriority != listen_socket[sock].priority) {
listen_socket[sock].priority = origpriority;
switch(sa->sa.sa_family) {
#if defined(IPPROTO_IP) && defined(IP_TOS)
case AF_INET:
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
break;
#endif
#if defined(IPPROTO_IPV6) & defined(IPV6_TCLASS)
case AF_INET6:
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
break;
#endif
default:
break;
}
}
if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sendto(listen_socket[sock].udp.fd, (void *)SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
@ -1557,7 +1566,7 @@ void handle_incoming_vpn_data(void *data, int flags) {
socklen_t addrlen = sizeof addr;
pkt.offset = 0;
int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
int len = recvfrom(ls->udp.fd, (void *)DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))

View file

@ -1,7 +1,7 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com>
@ -370,18 +370,18 @@ void load_all_nodes(void) {
continue;
node_t *n = lookup_node(ent->d_name);
splay_tree_t *config_tree;
init_configuration(&config_tree);
read_config_options(config_tree, ent->d_name);
read_host_config(config_tree, ent->d_name);
if(!n) {
n = new_node();
n->name = xstrdup(ent->d_name);
node_add(n);
}
splay_tree_t *config_tree;
init_configuration(&config_tree);
read_config_options(config_tree, ent->d_name);
read_host_config(config_tree, ent->d_name);
if (strictsubnets) {
if(strictsubnets) {
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
subnet_t *s, *s2;
@ -397,10 +397,8 @@ void load_all_nodes(void) {
}
}
if (lookup_config(config_tree, "Address")) {
n->status.has_known_address = true;
n->status.has_cfg_address = true;
}
if(lookup_config(config_tree, "Address"))
n->status.has_address = true;
exit_configuration(&config_tree);
}
@ -601,16 +599,14 @@ bool setup_myself_reloadable(void) {
subnet_add(NULL, s);
}
for (config_t* cfg = lookup_config(config_tree, "MulticastSubnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
subnet_t *s;
if (!get_config_subnet(cfg, &s))
continue;
subnet_add(NULL, s);
}
#if !defined(SOL_IP) || !defined(IP_TOS)
#if !defined(IPPROTO_IP) || !defined(IP_TOS)
if(priorityinheritance)
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv4 connections", "PriorityInheritance");
#endif
#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS)
if(priorityinheritance)
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv6 connections", "PriorityInheritance");
#endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
@ -1172,8 +1168,7 @@ void close_network_connections(void) {
if(myself && myself->connection) {
subnet_update(myself, NULL, false);
terminate_connection(myself->connection, false);
free_connection(myself->connection);
connection_del(myself->connection);
}
for(int i = 0; i < listen_sockets; i++) {

View file

@ -1,7 +1,7 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
@ -35,11 +35,6 @@
#include "utils.h"
#include "xalloc.h"
/* Needed on Mac OS/X */
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
#endif
int addressfamily = AF_UNSPEC;
int maxtimeout = 900;
int seconds_till_retry = 5;
@ -73,14 +68,19 @@ static void configure_tcp(connection_t *c) {
}
#endif
#if defined(SOL_TCP) && defined(TCP_NODELAY)
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
option = 1;
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_TCP, TCP_NODELAY, (void *)&option, sizeof option);
#endif
#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY;
setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_IP, IP_TOS, (void *)&option, sizeof option);
#endif
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY;
setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof option);
#endif
}
@ -163,9 +163,9 @@ int setup_listen_socket(const sockaddr_t *sa) {
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
if(get_config_string
@ -261,10 +261,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
#define IP_DONTFRAGMENT IP_DONTFRAG
#endif
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
#if defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
if(myself->options & OPTION_PMTU_DISCOVERY) {
@ -273,10 +273,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
}
#endif
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
if(myself->options & OPTION_PMTU_DISCOVERY) {
@ -517,10 +517,10 @@ begin:
#endif
if(proxytype != PROXY_EXEC) {
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
if(c->address.sa.sa_family == AF_INET6)
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
bind_to_interface(c->socket);
@ -547,6 +547,7 @@ begin:
/* Now that there is a working socket, fill in the rest and register this connection. */
c->last_ping_time = time(NULL);
c->status.connecting = true;
c->name = xstrdup(outgoing->name);
#ifndef DISABLE_LEGACY

View file

@ -190,7 +190,7 @@ bool dump_nodes(connection_t *c) {
for splay_each(node_t, n, node_tree) {
char id[2 * sizeof n->id + 1];
for (size_t c = 0; c < sizeof n->id; ++c)
sprintf(id + 2 * c, "%02hhx", n->id.x[c]);
snprintf(id + 2 * c, 3, "%02hhx", n->id.x[c]);
id[sizeof id - 1] = 0;
send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
n->name, id, n->hostname ?: "unknown port unknown",

View file

@ -40,9 +40,8 @@ typedef struct node_status_t {
unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */
unsigned int udppacket:1; /* 1 if the most recently received packet was UDP */
unsigned int validkey_in:1; /* 1 if we have sent a valid key to him */
unsigned int has_known_address; /* 1 if this node has UDP Address */
unsigned int has_cfg_address; /* 1 if this node has Address in node's config */
unsigned int unused:21;
unsigned int has_address:1; /* 1 if we know an external address for this node */
unsigned int unused:20;
} node_status_t;
typedef struct node_t {

View file

@ -62,12 +62,9 @@ static bool install_service(void) {
return false;
}
if(!strchr(program_name, '\\')) {
GetCurrentDirectory(sizeof command - 1, command + 1);
strncat(command, "\\", sizeof command - strlen(command));
}
strncat(command, program_name, sizeof command - strlen(command));
HMODULE module = GetModuleHandle(NULL);
GetModuleFileName(module, command + 1, sizeof command - 1);
command[sizeof command - 1] = 0;
strncat(command, "\"", sizeof command - strlen(command));
@ -203,7 +200,7 @@ bool detach(void) {
if(do_detach) {
#ifndef HAVE_MINGW
if(daemon(0, 0)) {
if(daemon(1, 0)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno));
return false;
}

View file

@ -117,7 +117,7 @@ static bool send_proxyrequest(connection_t *c) {
i += 2;
c->tcplen += 22;
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
return false;
}
if(i > len)

View file

@ -159,7 +159,7 @@ bool add_edge_h(connection_t *c, const char *request) {
"ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name);
e->address = address;
}
goto exit_with_graph;
goto done;
}
} else if(sockaddrcmp(&e->local_address, &local_address)) {
if(from == myself) {
@ -221,8 +221,8 @@ bool add_edge_h(connection_t *c, const char *request) {
e->avg_rtt = weight/10;
edge_add(e);
done:
/* Tell the rest about the new edge */
exit_with_graph:
if(!tunnelserver)
forward_request(c, request);

View file

@ -412,7 +412,7 @@ bool ans_key_h(connection_t *c, const char *request) {
return true;
}
if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) {
char *address, *port;
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
sockaddr2str(&from->address, &address, &port);

View file

@ -105,6 +105,260 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
return true;
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
/* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip = {0};
struct icmp icmp = {0};
struct in_addr ip_src;
struct in_addr ip_dst;
uint32_t oldlen;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
ip_src = ip.ip_src;
ip_dst = ip.ip_dst;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = ip.ip_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
ip_dst = addr.sin_addr;
}
}
close(sockfd);
}
}
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
ip.ip_v = 4;
ip.ip_hl = ip_size / 4;
ip.ip_tos = 0;
ip.ip_len = htons(ip_size + icmp_size + oldlen);
ip.ip_id = 0;
ip.ip_off = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_sum = 0;
ip.ip_src = ip_dst;
ip.ip_dst = ip_src;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
/* Fill in ICMP header */
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip, ip_size);
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet);
}
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
uint16_t checksum;
struct {
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
uint32_t length;
uint32_t next;
} pseudo;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
pseudo.ip6_src = ip6.ip6_dst;
pseudo.ip6_dst = ip6.ip6_src;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) {
int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = ip6.ip6_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
pseudo.ip6_src = addr.sin6_addr;
}
}
close(sockfd);
}
}
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
ip6.ip6_flow = htonl(0x60000000UL);
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_hlim = 255;
ip6.ip6_src = pseudo.ip6_src;
ip6.ip6_dst = pseudo.ip6_dst;
/* Fill in ICMP header */
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
/* Create pseudo header */
pseudo.length = htonl(icmp6_size + pseudo.length);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
send_packet(source, packet);
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
switch (type) {
case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size))
return false;
if(DATA(packet)[ethlen + 8] <= 1) {
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
DATA(packet)[ethlen + 8]--;
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
DATA(packet)[ethlen + 10] = checksum >> 8;
DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size))
return false;
if(DATA(packet)[ethlen + 7] <= 1) {
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
DATA(packet)[ethlen + 7]--;
return true;
default:
return true;
}
}
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
return;
@ -186,13 +440,6 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
}
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
static void age_subnets(void *data) {
bool left = false;
UNUSED(data);
@ -251,80 +498,12 @@ static void learn_mac(mac_t *address) {
}
}
/* RFC 792 */
static void route_broadcast(node_t *source, vpn_packet_t *packet) {
if(decrement_ttl && source != myself)
if(!do_decrement_ttl(source, packet))
return;
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip;
struct icmp icmp;
struct in_addr ip_src;
struct in_addr ip_dst;
uint32_t oldlen;
memset(&ip, 0x0, sizeof(ip));
memset(&icmp, 0x0, sizeof(icmp));
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
ip_src = ip.ip_src;
ip_dst = ip.ip_dst;
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
ip.ip_v = 4;
ip.ip_hl = ip_size / 4;
ip.ip_tos = 0;
ip.ip_len = htons(ip_size + icmp_size + oldlen);
ip.ip_id = 0;
ip.ip_off = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_sum = 0;
ip.ip_src = ip_dst;
ip.ip_dst = ip_src;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
/* Fill in ICMP header */
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip, ip_size);
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet);
broadcast_packet(source, packet);
}
/* RFC 791 */
@ -411,7 +590,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
}
if (!subnet->owner) {
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -426,6 +605,10 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
if(priorityinheritance)
packet->priority = DATA(packet)[15];
@ -456,90 +639,6 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
send_packet(subnet->owner, packet);
}
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6;
uint16_t checksum;
struct {
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
uint32_t length;
uint32_t next;
} pseudo;
memset(&ip6, 0x0, sizeof(struct ip6_hdr));
memset(&icmp6, 0x0, sizeof(struct icmp6_hdr));
memset(&pseudo, 0x0, sizeof(pseudo));
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
pseudo.ip6_src = ip6.ip6_dst;
pseudo.ip6_dst = ip6.ip6_src;
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
ip6.ip6_flow = htonl(0x60000000UL);
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_hlim = 255;
ip6.ip6_src = pseudo.ip6_src;
ip6.ip6_dst = pseudo.ip6_dst;
/* Fill in ICMP header */
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
/* Create pseudo header */
pseudo.length = htonl(icmp6_size + pseudo.length);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
send_packet(source, packet);
}
static void route_neighborsol(node_t *source, vpn_packet_t *packet);
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
@ -611,7 +710,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
return;
}
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -626,6 +725,10 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via == source) {
@ -742,6 +845,10 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
if(subnet->owner == myself)
return; /* silently ignore */
if(decrement_ttl)
if(!do_decrement_ttl(source, packet))
return;
/* Create neighbor advertation reply */
memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
@ -837,6 +944,10 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
if(subnet->owner == myself)
return; /* silently ignore */
if(decrement_ttl)
if(!do_decrement_ttl(source, packet))
return;
memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */
memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */
memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */
@ -871,7 +982,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet || !subnet->owner) {
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -883,6 +994,10 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return;
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
@ -941,58 +1056,6 @@ static void send_pcap(vpn_packet_t *packet) {
}
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
switch (type) {
case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size))
return false;
if(DATA(packet)[ethlen + 8] < 1) {
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
DATA(packet)[ethlen + 8]--;
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
DATA(packet)[ethlen + 10] = checksum >> 8;
DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size))
return false;
if(DATA(packet)[ethlen + 7] < 1) {
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
DATA(packet)[ethlen + 7]--;
return true;
default:
return true;
}
}
void route(node_t *source, vpn_packet_t *packet) {
if(pcap)
send_pcap(packet);
@ -1005,10 +1068,6 @@ void route(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size))
return;
if(decrement_ttl && source != myself)
if(!do_decrement_ttl(source, packet))
return;
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
switch (routing_mode) {
@ -1037,7 +1096,7 @@ void route(node_t *source, vpn_packet_t *packet) {
break;
case RMODE_HUB:
broadcast_packet(source, packet);
route_broadcast(source, packet);
break;
}
}

View file

@ -26,8 +26,44 @@
#include "script.h"
#include "xalloc.h"
#ifdef HAVE_PUTENV
static void unputenv(const char *p) {
const char *e = strchr(p, '=');
if(!e)
return;
int len = e - p;
#ifndef HAVE_UNSETENV
#ifdef HAVE_MINGW
// Windows requires putenv("FOO=") to unset %FOO%
len++;
#endif
#endif
char var[len + 1];
strncpy(var, p, len);
var[len] = 0;
#ifdef HAVE_UNSETENV
unsetenv(var);
#else
// We must keep what we putenv() around in memory.
// To do this without memory leaks, keep things in a list and reuse if possible.
static list_t list = {};
for list_each(char, data, &list) {
if(!strcmp(data, var)) {
putenv(data);
return;
}
}
char *data = xstrdup(var);
list_insert_tail(&list, data);
putenv(data);
#endif
}
#else
static void putenv(const char *p) {}
static void unputenv(const char *p) {}
#endif
bool execute_script(const char *name, char **envp) {
#ifdef HAVE_SYSTEM
char scriptname[PATH_MAX];
char *command;
@ -38,9 +74,11 @@ bool execute_script(const char *name, char **envp) {
#ifdef HAVE_MINGW
if(!*scriptextension) {
const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD";
char fullname[strlen(scriptname) + strlen(pathext)];
char *ext = fullname + strlen(scriptname);
strcpy(fullname, scriptname);
size_t pathlen = strlen(pathext);
size_t scriptlen = strlen(scriptname);
char fullname[scriptlen + pathlen + 1];
char *ext = fullname + scriptlen;
strncpy(fullname, scriptname, sizeof fullname);
const char *p = pathext;
bool found = false;
@ -51,7 +89,7 @@ bool execute_script(const char *name, char **envp) {
ext[q - p] = 0;
q++;
} else {
strcpy(ext, p);
strncpy(ext, p, pathlen + 1);
}
if((found = !access(fullname, F_OK)))
break;
@ -67,12 +105,10 @@ bool execute_script(const char *name, char **envp) {
logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name);
#ifdef HAVE_PUTENV
/* Set environment */
for(int i = 0; envp[i]; i++)
putenv(envp[i]);
#endif
if(scriptinterpreter)
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
@ -85,15 +121,8 @@ bool execute_script(const char *name, char **envp) {
/* Unset environment */
for(int i = 0; envp[i]; i++) {
char *e = strchr(envp[i], '=');
if(e) {
char p[e - envp[i] + 1];
strncpy(p, envp[i], e - envp[i]);
p[e - envp[i]] = '\0';
putenv(p);
}
}
for(int i = 0; envp[i]; i++)
unputenv(envp[i]);
if(status != -1) {
#ifdef WEXITSTATUS
@ -116,6 +145,6 @@ bool execute_script(const char *name, char **envp) {
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
return false;
}
#endif
return true;
}

View file

@ -222,7 +222,7 @@ static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
// Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
char seed[s->labellen + 64 + 13];
strcpy(seed, "key expansion");
memcpy(seed, "key expansion", 13);
if(s->initiator) {
memcpy(seed + 13, s->mykex + 1, 32);
memcpy(seed + 45, s->hiskex + 1, 32);

View file

@ -30,6 +30,15 @@
#include "sptps.h"
#include "utils.h"
// Symbols necessary to link with logger.o
bool send_request(void *c, const char *msg, ...) { return false; }
struct list_t *connection_list = NULL;
bool send_meta(void *c, const char *msg , int len) { return false; }
char *logfilename = NULL;
bool do_detach = false;
struct timeval now;
static bool special;
static bool verbose;
static bool readonly;
static bool writeonly;
@ -64,6 +73,7 @@ static struct option const long_options[] = {
{"writeonly", no_argument, NULL, 'w'},
{"packet-loss", required_argument, NULL, 'L'},
{"replay-window", required_argument, NULL, 'W'},
{"special", no_argument, NULL, 's'},
{"verbose", required_argument, NULL, 'v'},
{"help", no_argument, NULL, 1},
{NULL, 0, NULL, 0}
@ -83,6 +93,7 @@ static void usage() {
" -w, --writeonly Only send data from stdin to the socket.\n"
" -L, --packet-loss RATE Fake packet loss of RATE percent.\n"
" -R, --replay-window N Set replay window to N bytes.\n"
" -s, --special Enable special handling of lines starting with #, ^ and $.\n"
" -v, --verbose Display debug messages.\n"
"\n");
fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
@ -101,7 +112,7 @@ int main(int argc, char *argv[]) {
ecdsa_t *mykey = NULL, *hiskey = NULL;
bool quit = false;
while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) {
while((r = getopt_long(argc, argv, "dqrstwL:W:v", long_options, &option_index)) != EOF) {
switch (r) {
case 0: /* long option */
break;
@ -144,6 +155,10 @@ int main(int argc, char *argv[]) {
verbose = true;
break;
case 's': /* special character handling */
special = true;
break;
case '?': /* wrong options */
usage();
return 1;
@ -318,11 +333,11 @@ int main(int argc, char *argv[]) {
readonly = true;
continue;
}
if(buf[0] == '#')
if(special && buf[0] == '#')
s.outseqno = atoi(buf + 1);
if(buf[0] == '^')
if(special && buf[0] == '^')
sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0);
else if(buf[0] == '$') {
else if(special && buf[0] == '$') {
sptps_force_kex(&s);
if(len > 1)
sptps_send_record(&s, 0, buf, len);

View file

@ -22,7 +22,7 @@
#define __TINC_SUBNET_H__
#include "net.h"
#include "hash.h"
#include "node.h"
typedef enum subnet_type_t {
SUBNET_MAC = 0,
@ -45,8 +45,6 @@ typedef struct subnet_ipv6_t {
int prefixlength;
} subnet_ipv6_t;
#include "node.h"
typedef struct subnet_t {
struct node_t *owner; /* the owner of this subnet */

View file

@ -1,7 +1,7 @@
/*
system.h -- system headers
Copyright (C) 1998-2005 Ivo Timmermans
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,12 +25,6 @@
#include "have.h"
#ifndef HAVE_STDBOOL_H
typedef int bool;
#define true 1
#define false 0
#endif
#ifndef HAVE_STRSIGNAL
# define strsignal(p) ""
#endif
@ -39,10 +33,6 @@ typedef int bool;
#include "dropin.h"
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
#define UNUSED(n) (void)(n);
#endif /* __TINC_SYSTEM_H__ */

View file

@ -1,6 +1,6 @@
/*
tincctl.c -- Controlling a running tincd
Copyright (C) 2007-2015 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -88,7 +88,7 @@ static struct option const long_options[] = {
static void version(void) {
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
"See the AUTHORS file for a complete list.\n\n"
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to redistribute it under certain conditions;\n"
@ -153,6 +153,8 @@ static void usage(bool status) {
" join INVITATION Join a VPN using an INVITATION\n"
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
" fsck Check the configuration files for problems.\n"
" sign [FILE] Generate a signed version of a file.\n"
" verify NODE [FILE] Verify that a file was signed by the given NODE.\n"
"\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
@ -327,7 +329,7 @@ static void disable_old_keys(const char *filename, const char *what) {
static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
FILE *r;
char *directory;
char directory[PATH_MAX] = ".";
char buf[PATH_MAX];
char buf2[PATH_MAX];
@ -355,7 +357,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
if(filename[0] != '/') {
#endif
/* The directory is a relative path or a filename. */
directory = get_current_dir_name();
getcwd(directory, sizeof directory);
snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename);
filename = buf2;
}
@ -1437,6 +1439,29 @@ char *get_my_name(bool verbose) {
return NULL;
}
ecdsa_t *get_pubkey(FILE *f) {
char buf[4096];
char *value;
while(fgets(buf, sizeof buf, f)) {
int len = strcspn(buf, "\t =");
value = buf + len;
value += strspn(value, "\t ");
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
if(!rstrip(value))
continue;
buf[len] = 0;
if(strcasecmp(buf, "Ed25519PublicKey"))
continue;
if(*value)
return ecdsa_set_base64_public_key(value);
}
return NULL;
}
const var_t variables[] = {
/* Server configuration */
{"AddressFamily", VAR_SERVER},
@ -2272,26 +2297,29 @@ static int cmd_exchange_all(int argc, char *argv[]) {
}
static int switch_network(char *name) {
if(strcmp(name, ".")) {
if(!check_netname(name, false)) {
fprintf(stderr, "Invalid character in netname!\n");
return 1;
}
if(!check_netname(name, true))
fprintf(stderr, "Warning: unsafe character in netname!\n");
}
if(fd >= 0) {
close(fd);
fd = -1;
}
free(confbase);
confbase = NULL;
free(pidfilename);
pidfilename = NULL;
free(logfilename);
logfilename = NULL;
free(unixsocketname);
unixsocketname = NULL;
free_names();
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
make_names(false);
free(tinc_conf);
free(hosts_dir);
free(prompt);
free(netname);
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
xasprintf(&prompt, "%s> ", identname);
@ -2345,6 +2373,231 @@ static int cmd_fsck(int argc, char *argv[]) {
return fsck(orig_argv[0]);
}
static void *readfile(FILE *in, size_t *len) {
size_t count = 0;
size_t alloced = 4096;
char *buf = xmalloc(alloced);
while(!feof(in)) {
size_t read = fread(buf + count, 1, alloced - count, in);
if(!read)
break;
count += read;
if(count >= alloced) {
alloced *= 2;
buf = xrealloc(buf, alloced);
}
}
if(len)
*len = count;
return buf;
}
static int cmd_sign(int argc, char *argv[]) {
if(argc > 2) {
fprintf(stderr, "Too many arguments!\n");
return 1;
}
if(!name) {
name = get_my_name(true);
if(!name)
return 1;
}
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
FILE *fp = fopen(fname, "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
return 1;
}
ecdsa_t *key = ecdsa_read_pem_private_key(fp);
if(!key) {
fprintf(stderr, "Could not read private key from %s\n", fname);
fclose(fp);
return 1;
}
fclose(fp);
FILE *in;
if(argc == 2) {
in = fopen(argv[1], "rb");
if(!in) {
fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
ecdsa_free(key);
return 1;
}
} else {
in = stdin;
}
size_t len;
char *data = readfile(in, &len);
if(in != stdin)
fclose(in);
if(!data) {
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
ecdsa_free(key);
return 1;
}
// Ensure we sign our name and current time as well
long t = time(NULL);
char *trailer;
xasprintf(&trailer, " %s %ld", name, t);
int trailer_len = strlen(trailer);
data = xrealloc(data, len + trailer_len);
memcpy(data + len, trailer, trailer_len);
free(trailer);
char sig[87];
if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
fprintf(stderr, "Error generating signature\n");
free(data);
ecdsa_free(key);
return 1;
}
b64encode(sig, sig, 64);
ecdsa_free(key);
fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
fwrite(data, len, 1, stdout);
free(data);
return 0;
}
static int cmd_verify(int argc, char *argv[]) {
if(argc < 2) {
fprintf(stderr, "Not enough arguments!\n");
return 1;
}
if(argc > 3) {
fprintf(stderr, "Too many arguments!\n");
return 1;
}
char *node = argv[1];
if(!strcmp(node, ".")) {
if(!name) {
name = get_my_name(true);
if(!name)
return 1;
}
node = name;
} else if(!strcmp(node, "*")) {
node = NULL;
} else {
if(!check_id(node)) {
fprintf(stderr, "Invalid node name\n");
return 1;
}
}
FILE *in;
if(argc == 3) {
in = fopen(argv[2], "rb");
if(!in) {
fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
return 1;
}
} else {
in = stdin;
}
size_t len;
char *data = readfile(in, &len);
if(in != stdin)
fclose(in);
if(!data) {
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
return 1;
}
char *newline = memchr(data, '\n', len);
if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
fprintf(stderr, "Invalid input\n");
return 1;
}
*newline++ = '\0';
size_t skip = newline - data;
char signer[MAX_STRING_SIZE] = "";
char sig[MAX_STRING_SIZE] = "";
long t = 0;
if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
fprintf(stderr, "Invalid input\n");
return 1;
}
if(node && strcmp(node, signer)) {
fprintf(stderr, "Signature is not made by %s\n", node);
return 1;
}
if(!node)
node = signer;
char *trailer;
xasprintf(&trailer, " %s %ld", signer, t);
int trailer_len = strlen(trailer);
data = xrealloc(data, len + trailer_len);
memcpy(data + len, trailer, trailer_len);
free(trailer);
newline = data + skip;
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node);
FILE *fp = fopen(fname, "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
free(data);
return 1;
}
ecdsa_t *key = get_pubkey(fp);
if(!key) {
rewind(fp);
key = ecdsa_read_pem_public_key(fp);
}
if(!key) {
fprintf(stderr, "Could not read public key from %s\n", fname);
fclose(fp);
free(data);
return 1;
}
fclose(fp);
if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
fprintf(stderr, "Invalid signature\n");
free(data);
ecdsa_free(key);
return 1;
}
ecdsa_free(key);
fwrite(newline, len - (newline - data), 1, stdout);
free(data);
return 0;
}
static const struct {
const char *command;
int (*function)(int argc, char *argv[]);
@ -2389,6 +2642,8 @@ static const struct {
{"join", cmd_join, false},
{"network", cmd_network, false},
{"fsck", cmd_fsck, false},
{"sign", cmd_sign, false},
{"verify", cmd_verify, false},
{NULL, NULL, NULL},
};

View file

@ -1,6 +1,6 @@
/*
tincctl.h -- header for tincctl.c.
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -50,6 +50,7 @@ extern bool sendline(int fd, char *format, ...);
extern bool recvline(int fd, char *line, size_t len);
extern int check_port(char *name);
extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
extern ecdsa_t *get_pubkey(FILE *f);
#endif

View file

@ -1,7 +1,7 @@
/*
tincd.c -- the main file for tincd
Copyright (C) 1998-2005 Ivo Timmermans
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2008 Max Rijevski <maksuf@gmail.com>
2009 Michael Tokarev <mjt@tls.msk.ru>
2010 Julien Muchembled <jm@jmuchemb.eu>
@ -43,8 +43,6 @@
#include <time.h>
#endif
#include <getopt.h>
#include "conf.h"
#include "control.h"
#include "crypto.h"
@ -254,11 +252,14 @@ static bool parse_options(int argc, char **argv) {
netname = NULL;
}
if(netname && (strpbrk(netname, "\\/") || *netname == '.')) {
if(netname && !check_netname(netname, false)) {
fprintf(stderr, "Invalid character in netname!\n");
return false;
}
if(netname && !check_netname(netname, true))
fprintf(stderr, "Warning: unsafe character in netname!\n");
return true;
}
@ -331,11 +332,12 @@ int main(int argc, char **argv) {
return 1;
make_names(true);
chdir(confbase);
if(show_version) {
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
"See the AUTHORS file for a complete list.\n\n"
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to redistribute it under certain conditions;\n"

View file

@ -158,7 +158,7 @@ int b64encode_urlsafe(const void *src, char *dst, int length) {
const char *winerror(int err) {
static char buf[1024], *ptr;
ptr = buf + sprintf(buf, "(%d) ", err);
ptr = buf + snprintf(buf, sizeof buf, "(%d) ", err);
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) {
@ -191,6 +191,22 @@ bool check_id(const char *id) {
return true;
}
bool check_netname(const char *netname, bool strict) {
if(!netname || !*netname || *netname == '.')
return false;
for(const char *c = netname; *c; c++) {
if(iscntrl(*c))
return false;
if(*c == '/' || *c == '\\')
return false;
if(strict && strchr(" $%<>:`\"|?*", *c))
return false;
}
return true;
}
/* Windows doesn't define HOST_NAME_MAX. */
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255

View file

@ -51,6 +51,7 @@ extern const char *winerror(int);
extern unsigned int bitfield_to_int(const void *bitfield, size_t size);
extern bool check_id(const char *);
extern bool check_netname(const char *, bool strict);
char *replace_name(const char *name);
#endif /* __TINC_UTILS_H__ */

View file

@ -11,12 +11,18 @@ test_scripts = \
variables.test
TESTS = \
simple \
$(test_scripts)
basic.test \
commandline.test \
executables.test \
import-export.test \
invite-join.test \
invite-tinc-up.test \
ns-ping.test \
ping.test \
sptps-basic.test \
variables.test
CC=clang
dist_check_SCRIPTS = $(test_scripts)
dist_check_SCRIPTS = $(TESTS)
EXTRA_DIST = testlib.sh

51
test/invite-tinc-up.test Executable file
View file

@ -0,0 +1,51 @@
#!/bin/sh
. ./testlib.sh
# Initialize one node
$tinc $c1 <<EOF
init foo
set DeviceType dummy
set Address localhost
set Port 32751
start $r1
EOF
# Generate an invitation and let another node join the VPN
sleep 1
cat >$d1/invitation-created <<EOF
#!/bin/sh
echo Name = \$NODE >\$INVITATION_FILE
echo Ifconfig = 93.184.216.34/24 >>\$INVITATION_FILE
echo Route = 2606:2800:220:1::/64 2606:2800:220:1:248:1893:25c8:1946 >>\$INVITATION_FILE
echo Route = 1.2.3.4 1234:: >>\$INVITATION_FILE
$tinc $c1 export >>\$INVITATION_FILE
EOF
chmod u+x $d1/invitation-created
$tinc $c1 invite bar | $tinc $c2 --batch join
# Test equivalence of host config files
cmp $d1/hosts/foo $d2/hosts/foo
test "`grep ^Ed25519PublicKey $d1/hosts/bar`" = "`grep ^Ed25519PublicKey $d2/hosts/bar`"
# Check if the tinc-up.invitation file is created and contains the right commands
test -f $d2/tinc-up.invitation
fgrep -q "93.184.216.34/24" $d2/tinc-up.invitation
fgrep -q "2606:2800:220:1::/64" $d2/tinc-up.invitation
fgrep -q "2606:2800:220:1:248:1893:25c8:1946" $d2/tinc-up.invitation
fgrep -q "1234::" $d2/tinc-up.invitation && exit 1
# Check that no tinc-up is created and that tinc-up.invitation is not executable
test -x $d2/tinc-up.invitation && exit 1
test -f $d2/tinc-up && exit 1
$tinc $c1 stop