New upstream version 1.0.36
This commit is contained in:
parent
b511a112e6
commit
10b8518c22
214 changed files with 12416 additions and 59622 deletions
20
AUTHORS
20
AUTHORS
|
@ -1,25 +1,20 @@
|
||||||
Main tinc authors:
|
Main tinc authors:
|
||||||
|
|
||||||
- Guus Sliepen <guus@tinc-vpn.org>
|
- Guus Sliepen <guus@tinc-vpn.org>
|
||||||
- Ivo Timmermans (inactive)
|
- Ivo Timmermans (inactive)
|
||||||
|
|
||||||
Significant code contributions from:
|
Significant contributions from:
|
||||||
|
- Michael Tokarev <mjt@tls.msk.ru>
|
||||||
- Brandon Black <blblack@gmail.com>
|
|
||||||
- Etienne Dechamps <etienne@edechamps.fr>
|
|
||||||
- Florian Forster <octo@verplant.org>
|
- Florian Forster <octo@verplant.org>
|
||||||
- Grzegorz Dymarek <gregd72002@googlemail.com>
|
- Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||||
- Julien Muchembled <jm@jmuchemb.eu>
|
|
||||||
- Loïc Grenié <loic.grenie@gmail.com>
|
|
||||||
- Max Rijevski <maksuf@gmail.com>
|
- Max Rijevski <maksuf@gmail.com>
|
||||||
- Michael Tokarev <mjt@tls.msk.ru>
|
|
||||||
- Scott Lamb <slamb@slamb.org>
|
- Scott Lamb <slamb@slamb.org>
|
||||||
- Sven-Haegar Koch <haegar@sdinet.de>
|
- Julien Muchembled <jm@jmuchemb.eu>
|
||||||
- Timothy Redaelli <timothy@redaelli.eu>
|
- Timothy Redaelli <timothy@redaelli.eu>
|
||||||
|
- Brandon Black <blblack@gmail.com>
|
||||||
|
- Loïc Grenié <loic.grenie@gmail.com>
|
||||||
|
|
||||||
These files are from other sources:
|
These files are from other sources:
|
||||||
|
* lib/pidfile.h and lib/pidfile.c are by Martin Schulze, taken from
|
||||||
* lib/pidfile.h and lib/pidfile.c are by Martin Schulze, taken from
|
|
||||||
the syslog 1.3 sources.
|
the syslog 1.3 sources.
|
||||||
|
|
||||||
* src/bsd/tunemu.c and tunemu.h are by Friedrich Schöller
|
* src/bsd/tunemu.c and tunemu.h are by Friedrich Schöller
|
||||||
|
@ -28,4 +23,5 @@ These files are from other sources:
|
||||||
Also some of the macro files in the directory m4, and their
|
Also some of the macro files in the directory m4, and their
|
||||||
accompanying files in lib, were taken from GNU fileutils.
|
accompanying files in lib, were taken from GNU fileutils.
|
||||||
|
|
||||||
Please see the file THANKS for a list of all contributors to tinc.
|
Please see the file THANKS for more information on contributions from
|
||||||
|
users.
|
||||||
|
|
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
||||||
Copyright (C) 1998-2018 Ivo Timmermans, Guus Sliepen and others.
|
Copyright (C) 1998-2019 Ivo Timmermans, Guus Sliepen and others.
|
||||||
See the AUTHORS file for a complete list.
|
See the AUTHORS file for a complete list.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
The following applies to tinc:
|
The following applies to tinc:
|
||||||
|
|
||||||
> This program is released under the GPL with the additional exemption that
|
This program is released under the GPL with the additional exemption that
|
||||||
> compiling, linking, and/or using OpenSSL is allowed. You may provide binary
|
compiling, linking, and/or using OpenSSL is allowed. You may provide binary
|
||||||
> packages linked to the OpenSSL libraries, provided that all other requirements
|
packages linked to the OpenSSL libraries, provided that all other requirements
|
||||||
> of the GPL are met.
|
of the GPL are met.
|
||||||
|
|
||||||
The following applies to the LZO library:
|
The following applies to the LZO library:
|
||||||
|
|
||||||
> Hereby I grant a special exception to the tinc VPN project
|
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
|
(http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library
|
||||||
> (https://openssl.org).
|
(http://www.openssl.org).
|
||||||
>
|
|
||||||
> Markus F.X.J. Oberhumer
|
Markus F.X.J. Oberhumer
|
||||||
|
|
||||||
When tinc is compiled with the --enable-tunemu option, the resulting binary
|
When tinc is compiled with the --enable-tunemu option, the resulting binary
|
||||||
falls under the GPL version 3 or later.
|
falls under the GPL version 3 or later.
|
||||||
|
|
||||||
|
|
||||||
|
|
31
Makefile.am
31
Makefile.am
|
@ -2,39 +2,14 @@
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = gnu
|
AUTOMAKE_OPTIONS = gnu
|
||||||
|
|
||||||
SUBDIRS = src doc test systemd
|
SUBDIRS = src doc systemd
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
EXTRA_DIST = COPYING.README README.android
|
EXTRA_DIST = COPYING.README README.android
|
||||||
|
|
||||||
@CODE_COVERAGE_RULES@
|
|
||||||
|
|
||||||
# If git describe works, force autoconf to run in order to make sure we have the
|
|
||||||
# current version number from git in the resulting configure script.
|
|
||||||
configure-version:
|
|
||||||
-cd $(srcdir) && git describe && autoconf --force
|
|
||||||
|
|
||||||
# Triggering the README target means we are building a distribution (make dist).
|
|
||||||
README: configure-version
|
|
||||||
|
|
||||||
ChangeLog:
|
ChangeLog:
|
||||||
(cd $(srcdir) && git log) > ChangeLog
|
git log > ChangeLog
|
||||||
|
|
||||||
deb:
|
|
||||||
dpkg-buildpackage -rfakeroot
|
|
||||||
|
|
||||||
rpm: dist
|
|
||||||
cp $(distdir).tar.gz /usr/src/redhat/SOURCES/
|
|
||||||
cp redhat/tinc.spec /usr/src/redhat/SOURCES/
|
|
||||||
cd /usr/src/redhat/SOURCES/ && rpm -bb tinc.spec
|
|
||||||
|
|
||||||
release:
|
|
||||||
rm -f ChangeLog
|
|
||||||
$(MAKE) ChangeLog
|
|
||||||
echo "Please edit the NEWS file now..."
|
|
||||||
/usr/bin/editor $(srcdir)/NEWS
|
|
||||||
$(MAKE) dist
|
|
||||||
|
|
||||||
astyle:
|
astyle:
|
||||||
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
||||||
|
|
59
Makefile.in
59
Makefile.in
|
@ -94,12 +94,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||||
$(top_srcdir)/m4/ax_code_coverage.m4 \
|
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||||
$(top_srcdir)/m4/ax_require_defined.m4 \
|
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \
|
$(top_srcdir)/configure.ac
|
||||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \
|
|
||||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \
|
|
||||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac
|
|
||||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
$(ACLOCAL_M4)
|
$(ACLOCAL_M4)
|
||||||
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
|
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
|
||||||
|
@ -222,15 +219,8 @@ AWK = @AWK@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CCDEPMODE = @CCDEPMODE@
|
CCDEPMODE = @CCDEPMODE@
|
||||||
CFLAGS = @CFLAGS@
|
CFLAGS = @CFLAGS@
|
||||||
CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
|
|
||||||
CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
|
|
||||||
CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
|
|
||||||
CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
|
|
||||||
CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
|
|
||||||
CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
|
|
||||||
CPP = @CPP@
|
CPP = @CPP@
|
||||||
CPPFLAGS = @CPPFLAGS@
|
CPPFLAGS = @CPPFLAGS@
|
||||||
CURSES_LIBS = @CURSES_LIBS@
|
|
||||||
CYGPATH_W = @CYGPATH_W@
|
CYGPATH_W = @CYGPATH_W@
|
||||||
DEFS = @DEFS@
|
DEFS = @DEFS@
|
||||||
DEPDIR = @DEPDIR@
|
DEPDIR = @DEPDIR@
|
||||||
|
@ -239,21 +229,17 @@ ECHO_N = @ECHO_N@
|
||||||
ECHO_T = @ECHO_T@
|
ECHO_T = @ECHO_T@
|
||||||
EGREP = @EGREP@
|
EGREP = @EGREP@
|
||||||
EXEEXT = @EXEEXT@
|
EXEEXT = @EXEEXT@
|
||||||
GCOV = @GCOV@
|
|
||||||
GENHTML = @GENHTML@
|
|
||||||
GREP = @GREP@
|
GREP = @GREP@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||||
LCOV = @LCOV@
|
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBOBJS = @LIBOBJS@
|
LIBOBJS = @LIBOBJS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
LTLIBOBJS = @LTLIBOBJS@
|
LTLIBOBJS = @LTLIBOBJS@
|
||||||
MAKEINFO = @MAKEINFO@
|
MAKEINFO = @MAKEINFO@
|
||||||
MINIUPNPC_LIBS = @MINIUPNPC_LIBS@
|
|
||||||
MKDIR_P = @MKDIR_P@
|
MKDIR_P = @MKDIR_P@
|
||||||
OBJEXT = @OBJEXT@
|
OBJEXT = @OBJEXT@
|
||||||
PACKAGE = @PACKAGE@
|
PACKAGE = @PACKAGE@
|
||||||
|
@ -264,8 +250,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||||
PACKAGE_URL = @PACKAGE_URL@
|
PACKAGE_URL = @PACKAGE_URL@
|
||||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||||
READLINE_LIBS = @READLINE_LIBS@
|
|
||||||
SED = @SED@
|
|
||||||
SET_MAKE = @SET_MAKE@
|
SET_MAKE = @SET_MAKE@
|
||||||
SHELL = @SHELL@
|
SHELL = @SHELL@
|
||||||
STRIP = @STRIP@
|
STRIP = @STRIP@
|
||||||
|
@ -323,8 +307,8 @@ top_build_prefix = @top_build_prefix@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
AUTOMAKE_OPTIONS = gnu
|
AUTOMAKE_OPTIONS = gnu
|
||||||
SUBDIRS = src doc test systemd
|
SUBDIRS = src doc systemd
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
EXTRA_DIST = COPYING.README README.android
|
EXTRA_DIST = COPYING.README README.android
|
||||||
all: config.h
|
all: config.h
|
||||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||||
|
@ -489,6 +473,12 @@ distdir: $(BUILT_SOURCES)
|
||||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||||
|
|
||||||
distdir-am: $(DISTFILES)
|
distdir-am: $(DISTFILES)
|
||||||
|
@case `sed 15q $(srcdir)/NEWS` in \
|
||||||
|
*"$(VERSION)"*) : ;; \
|
||||||
|
*) \
|
||||||
|
echo "NEWS not updated; not releasing" 1>&2; \
|
||||||
|
exit 1;; \
|
||||||
|
esac
|
||||||
$(am__remove_distdir)
|
$(am__remove_distdir)
|
||||||
test -d "$(distdir)" || mkdir "$(distdir)"
|
test -d "$(distdir)" || mkdir "$(distdir)"
|
||||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||||
|
@ -801,33 +791,8 @@ uninstall-am:
|
||||||
.PRECIOUS: Makefile
|
.PRECIOUS: Makefile
|
||||||
|
|
||||||
|
|
||||||
@CODE_COVERAGE_RULES@
|
|
||||||
|
|
||||||
# If git describe works, force autoconf to run in order to make sure we have the
|
|
||||||
# current version number from git in the resulting configure script.
|
|
||||||
configure-version:
|
|
||||||
-cd $(srcdir) && git describe && autoconf --force
|
|
||||||
|
|
||||||
# Triggering the README target means we are building a distribution (make dist).
|
|
||||||
README: configure-version
|
|
||||||
|
|
||||||
ChangeLog:
|
ChangeLog:
|
||||||
(cd $(srcdir) && git log) > ChangeLog
|
git log > ChangeLog
|
||||||
|
|
||||||
deb:
|
|
||||||
dpkg-buildpackage -rfakeroot
|
|
||||||
|
|
||||||
rpm: dist
|
|
||||||
cp $(distdir).tar.gz /usr/src/redhat/SOURCES/
|
|
||||||
cp redhat/tinc.spec /usr/src/redhat/SOURCES/
|
|
||||||
cd /usr/src/redhat/SOURCES/ && rpm -bb tinc.spec
|
|
||||||
|
|
||||||
release:
|
|
||||||
rm -f ChangeLog
|
|
||||||
$(MAKE) ChangeLog
|
|
||||||
echo "Please edit the NEWS file now..."
|
|
||||||
/usr/bin/editor $(srcdir)/NEWS
|
|
||||||
$(MAKE) dist
|
|
||||||
|
|
||||||
astyle:
|
astyle:
|
||||||
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
||||||
|
|
149
README
149
README
|
@ -1,7 +1,11 @@
|
||||||
This is the README file for tinc version 1.1pre17. Installation
|
This is the README file for tinc version 1.0.36. Installation
|
||||||
instructions may be found in the INSTALL file.
|
instructions may be found in the INSTALL file.
|
||||||
|
|
||||||
tinc is Copyright © 1998-2018 Ivo Timmermans, Guus Sliepen <guus@tinc-vpn.org>, and others.
|
tinc is Copyright (C) 1998-2019 by:
|
||||||
|
|
||||||
|
Ivo Timmermans,
|
||||||
|
Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
|
and others.
|
||||||
|
|
||||||
For a complete list of authors see the AUTHORS file.
|
For a complete list of authors see the AUTHORS file.
|
||||||
|
|
||||||
|
@ -11,94 +15,119 @@ the Free Software Foundation; either version 2 of the License, or (at
|
||||||
your option) any later version. See the file COPYING for more details.
|
your option) any later version. See the file COPYING for more details.
|
||||||
|
|
||||||
|
|
||||||
This is a pre-release
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
Please note that this is NOT a stable release. Until version 1.1.0 is released,
|
|
||||||
please use one of the 1.0.x versions if you need a stable version of tinc.
|
|
||||||
|
|
||||||
Although tinc 1.1 will be protocol compatible with tinc 1.0.x, the
|
|
||||||
functionality of the tinc program may still change, and the control socket
|
|
||||||
protocol is not fixed yet.
|
|
||||||
|
|
||||||
|
|
||||||
Security statement
|
Security statement
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
This version uses an experimental and unfinished cryptographic protocol. Use it
|
In August 2000, we discovered the existence of a security hole in all versions
|
||||||
at your own risk.
|
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
|
||||||
|
uses strong authentication with RSA keys.
|
||||||
|
|
||||||
When connecting to nodes that use the legacy protocol used in tinc 1.0, be
|
On the 29th of December 2001, Jerome Etienne posted a security analysis of tinc
|
||||||
aware that any security issues in tinc 1.0 will apply to tinc 1.1 as well. On
|
1.0pre4. Due to a lack of sequence numbers and a message authentication code
|
||||||
September 6th, 2018, Michael Yonly contacted us and provided proof-of-concept
|
for each packet, an attacker could possibly disrupt certain network services or
|
||||||
code that allowed a remote attacker to create an authenticated, one-way
|
launch a denial of service attack by replaying intercepted packets. The current
|
||||||
connection with a node using the legacy protocol, and also that there was a
|
version adds sequence numbers and message authentication codes to prevent such
|
||||||
|
attacks.
|
||||||
|
|
||||||
|
On September the 15th of 2003, Peter Gutmann contacted us and showed us a
|
||||||
|
writeup describing various security issues in several VPN daemons. He showed
|
||||||
|
that tinc lacks perfect forward security, the connection authentication could
|
||||||
|
be done more properly, that the sequence number we use as an IV is not the best
|
||||||
|
practice and that the default length of the HMAC for packets is too short in
|
||||||
|
his opinion. We do not know of a way to exploit these weaknesses, but these
|
||||||
|
issues are being addressed in the tinc 1.1 branch.
|
||||||
|
|
||||||
|
The Sweet32 attack affects versions of tinc prior to 1.0.30.
|
||||||
|
|
||||||
|
On September 6th, 2018, Michael Yonly contacted us and provided
|
||||||
|
proof-of-concept code that allowed a remote attacker to create an
|
||||||
|
authenticated, one-way connection with a node, and also that there was a
|
||||||
possibility for a man-in-the-middle to force UDP packets from a node to be sent
|
possibility for a man-in-the-middle to force UDP packets from a node to be sent
|
||||||
in plaintext. The first issue was trivial to exploit on tinc versions prior to
|
in plaintext. The first issue was trivial to exploit on tinc versions prior to
|
||||||
1.0.30, but the changes in 1.0.30 to mitigate the Sweet32 attack made this
|
1.0.30, but the changes in 1.0.30 to mitigate the Sweet32 attack made this
|
||||||
weakness much harder to exploit. These issues have been fixed in tinc 1.0.35
|
weakness much harder to exploit. These issues have been fixed in tinc 1.0.35.
|
||||||
and tinc 1.1pre17. The new protocol in the tinc 1.1 branch is not susceptible
|
The new protocol in the tinc 1.1 branch is not susceptible to these issues.
|
||||||
to these issues. However, be aware that SPTPS is only used between nodes
|
|
||||||
running tinc 1.1pre* or later, and in a VPN with nodes running different
|
Cryptography is a hard thing to get right. We cannot make any
|
||||||
versions, the security might only be as good as that of the oldest version.
|
guarantees. Time, review and feedback are the only things that can
|
||||||
|
prove the security of any cryptographic product. If you wish to review
|
||||||
|
tinc or give us feedback, you are strongly encouraged to do so.
|
||||||
|
|
||||||
|
|
||||||
Compatibility
|
Compatibility
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Version 1.1pre17 is compatible with 1.0pre8, 1.0 and later, but not with older
|
Version 1.0.35 is compatible with 1.0pre8, 1.0 and later, but not with older
|
||||||
versions of tinc.
|
versions of tinc. Note that since version 1.0.30, tinc requires all nodes in
|
||||||
|
the VPN to be compiled with a version of LibreSSL or OpenSSL that supports the
|
||||||
When the ExperimentalProtocol option is used, tinc is still compatible with
|
AES256 and SHA256 algorithms.
|
||||||
1.0.X, 1.1pre11 and later, but not with any version between 1.1pre1 and
|
|
||||||
1.1pre10.
|
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
In order to compile tinc, you will need a GNU C compiler environment. Please
|
The OpenSSL library is used for all cryptographic functions. You can find it at
|
||||||
ensure you have the latest stable versions of all the required libraries:
|
https://www.openssl.org/. You will need version 1.0.1 or later with support for
|
||||||
|
AES256 and SHA256 enabled. If this library is not installed on your system, the
|
||||||
|
configure script will fail. The manual in doc/tinc.texi contains more detailed
|
||||||
|
information on how to install this library. Alternatively, you may also use the
|
||||||
|
LibreSSL library.
|
||||||
|
|
||||||
- LibreSSL (http://www.libressl.org/) or OpenSSL (https://openssl.org/) version 1.0.0 or later.
|
The zlib library is used for optional compression. You can
|
||||||
|
find it at https://zlib.net/. Because of a possible exploit in
|
||||||
|
earlier versions we recommend that you download version 1.1.4 or later.
|
||||||
|
|
||||||
The following libraries are used by default, but can be disabled if necessary:
|
The LZO library is also used for optional compression. You can
|
||||||
|
find it at https://www.oberhumer.com/opensource/lzo/.
|
||||||
|
|
||||||
- zlib (https://zlib.net/)
|
In order to compile tinc, you will need a C99 compliant compiler.
|
||||||
- LZO (https://www.oberhumer.com/opensource/lzo/)
|
|
||||||
- ncurses (https://invisible-island.net/ncurses/)
|
|
||||||
- readline (https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html)
|
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Tinc is a peer-to-peer VPN daemon that supports VPNs with an arbitrary number
|
This version of tinc supports multiple virtual networks at once. To
|
||||||
of nodes. Instead of configuring tunnels, you give tinc the location and
|
use this feature, you may supply a netname via the -n or --net
|
||||||
public key of a few nodes in the VPN. After making the initial connections to
|
options. The standard locations for the config files will then be
|
||||||
those nodes, tinc will learn about all other nodes on the VPN, and will make
|
/etc/tinc/<net>/.
|
||||||
connections automatically. When direct connections are not possible, data will
|
|
||||||
be forwarded by intermediate nodes.
|
|
||||||
|
|
||||||
Tinc 1.1 support two protocols. The first is a legacy protocol that provides
|
tincd regenerates its encryption key pairs. It does this on the first
|
||||||
backwards compatibility with tinc 1.0 nodes, and which by default uses 2048 bit
|
activity after the keys have expired. This period is adjustable in the
|
||||||
RSA keys for authentication, and encrypts traffic using AES256 in CBC mode
|
configuration file, and the default time is 3600 seconds (one hour).
|
||||||
and HMAC-SHA256. 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.
|
This version supports multiple subnets at once. They are also sorted
|
||||||
|
on subnet mask size. This means that it is possible to have
|
||||||
|
overlapping subnets on the VPN, as long as their subnet mask sizes
|
||||||
|
differ.
|
||||||
|
|
||||||
Tinc can operate in several routing modes. In the default mode, "router", every
|
Since pre5, tinc can operate in several routing modes. The default mode,
|
||||||
node is associated with one or more IPv4 and/or IPv6 Subnets. The other two
|
"router", works exactly like the older version, and uses Subnet lines to
|
||||||
modes, "switch" and "hub", let the tinc daemons work together to form a virtual
|
determine the destination of packets. The other two modes, "switch" and "hub",
|
||||||
Ethernet network switch or hub.
|
allow the tinc daemons to work together like a single network switch or hub.
|
||||||
|
This is useful for bridging networks. The latter modes only work properly on
|
||||||
|
Linux, FreeBSD and Windows.
|
||||||
|
|
||||||
|
The algorithms used for encryption and generating message authentication codes
|
||||||
|
can now be changed in the configuration files. All cipher and digest algorithms
|
||||||
|
supported by OpenSSL can be used. Useful ciphers are "blowfish" (default),
|
||||||
|
"bf-ofb", "des", "des3", et cetera. Useful digests are "sha1" (default), "md5",
|
||||||
|
et cetera.
|
||||||
|
|
||||||
|
Support for routing IPv6 packets has been added. Just add Subnet lines with
|
||||||
|
IPv6 addresses (without using :: abbreviations) and use ifconfig or ip (from
|
||||||
|
the iproute package) to give the virtual network interface corresponding IPv6
|
||||||
|
addresses. tinc does not provide autoconfiguration for IPv6 hosts. Consider
|
||||||
|
using radvd or zebra if you need it.
|
||||||
|
|
||||||
|
It is also possible to make tunnels to other tinc daemons over IPv6 networks,
|
||||||
|
if the operating system supports IPv6. tinc will automatically use both IPv6
|
||||||
|
and IPv4 when available, but this can be changed by adding the option
|
||||||
|
"AddressFamily = ipv4" or "AddressFamily = ipv6" to the tinc.conf file.
|
||||||
|
|
||||||
Normally, when started tinc will detach and run in the background. In a native
|
Normally, when started tinc will detach and run in the background. In a native
|
||||||
Windows environment this means tinc will install 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,
|
restart after reboots. To prevent tinc from detaching or running as a service,
|
||||||
use the -D option.
|
use the -D option.
|
||||||
|
|
||||||
The status of the VPN can be queried using the "tinc" command, which connects
|
|
||||||
to a running tinc daemon via a control connection. The same tool also makes it
|
|
||||||
easy to start and stop tinc, and to change its configuration.
|
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
Quick how-to 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:
|
- Download android NDK and setup local ARM toolchain:
|
||||||
|
wget http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2
|
||||||
|
tar xfj android-ndk-r9d-linux-x86.tar.bz2
|
||||||
|
./android-ndk-r9d/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain
|
||||||
|
|
||||||
wget http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
|
- Download and cross-compile openSSL for ARM:
|
||||||
tar xfj android-ndk-r8b-linux-x86.tar.bz2
|
wget http://www.openssl.org/source/openssl-1.0.1h.tar.gz
|
||||||
./android-ndk-r8b/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain
|
tar xfz openssl-1.0.1h.tar.gz
|
||||||
|
cd openssl-1.0.1h
|
||||||
- Download and cross-compile OpenSSL for ARM:
|
./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://www.openssl.org/source/openssl-1.0.1c.tar.gz
|
cd -
|
||||||
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:
|
- 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.1g --with-openssl-include=$HOME/android/openssl-1.0.1g/include/ --disable-hardening
|
||||||
|
make -j5
|
||||||
|
|
||||||
|
- Strip tincd binary to make it smaller
|
||||||
|
/tmp/my-android-toolchain/bin/arm-linux-androideabi-strip src/tincd
|
||||||
|
|
||||||
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
|
|
||||||
|
|
12
THANKS
12
THANKS
|
@ -22,6 +22,7 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Delf Eldkraft
|
* Delf Eldkraft
|
||||||
* Dennis Joachimsthaler
|
* Dennis Joachimsthaler
|
||||||
* dnk
|
* dnk
|
||||||
|
* Егор Палкин
|
||||||
* Élie Bouttier
|
* Élie Bouttier
|
||||||
* Enrique Zanardi
|
* Enrique Zanardi
|
||||||
* Erik Tews
|
* Erik Tews
|
||||||
|
@ -37,11 +38,12 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Gusariev Oleksandr
|
* Gusariev Oleksandr
|
||||||
* Hans Bayle
|
* Hans Bayle
|
||||||
* Harvest
|
* Harvest
|
||||||
* Ivo Smits
|
|
||||||
* Ivo van Dong
|
* Ivo van Dong
|
||||||
|
* Ivo Smits
|
||||||
* James Cook
|
* James Cook
|
||||||
* James MacLean
|
* James MacLean
|
||||||
* Jamie Briggs
|
* Jamie Briggs
|
||||||
|
* Jan Štembera
|
||||||
* Jason Harper
|
* Jason Harper
|
||||||
* Jason Livesay
|
* Jason Livesay
|
||||||
* Jasper Krijgsman
|
* Jasper Krijgsman
|
||||||
|
@ -49,8 +51,8 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Jeroen Domburg
|
* Jeroen Domburg
|
||||||
* Jeroen Ubbink
|
* Jeroen Ubbink
|
||||||
* Jerome Etienne
|
* Jerome Etienne
|
||||||
* Jochen Voss
|
|
||||||
* Jo-Philipp Wich
|
* Jo-Philipp Wich
|
||||||
|
* Jochen Voss
|
||||||
* Julien Muchembled
|
* Julien Muchembled
|
||||||
* Lavrans Laading
|
* Lavrans Laading
|
||||||
* Loïc Dachary
|
* Loïc Dachary
|
||||||
|
@ -71,21 +73,24 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Max Rijevski
|
* Max Rijevski
|
||||||
* Menno Smits
|
* Menno Smits
|
||||||
* Mesar Hameed
|
* Mesar Hameed
|
||||||
|
* Michael Taylor
|
||||||
* Michael Tokarev
|
* Michael Tokarev
|
||||||
* Michael Yonli
|
* Michael Yonli
|
||||||
* Miles Nordin
|
* Miles Nordin
|
||||||
* Murat Donmez
|
|
||||||
* Nathan Stratton Treadway
|
* Nathan Stratton Treadway
|
||||||
|
* Murat Donmez
|
||||||
* Nick Hibma
|
* Nick Hibma
|
||||||
* Nick Patavalis
|
* Nick Patavalis
|
||||||
* Paul Littlefield
|
* Paul Littlefield
|
||||||
* Philipp Babel
|
* Philipp Babel
|
||||||
* Pierre Emeriaud
|
* Pierre Emeriaud
|
||||||
* Pierre-Olivier Mercier
|
* Pierre-Olivier Mercier
|
||||||
|
* Rafael Wolf
|
||||||
* Rafael Sadowski
|
* Rafael Sadowski
|
||||||
* Rafał Leśniak
|
* Rafał Leśniak
|
||||||
* Rhosyn Celyn
|
* Rhosyn Celyn
|
||||||
* Robert van der Meulen
|
* Robert van der Meulen
|
||||||
|
* Robert Waniek
|
||||||
* Rumko
|
* Rumko
|
||||||
* Ryan Miller
|
* Ryan Miller
|
||||||
* Sam Bryan
|
* Sam Bryan
|
||||||
|
@ -104,6 +109,7 @@ We would like to thank the following people for their contributions to tinc:
|
||||||
* Tonnerre Lombard
|
* Tonnerre Lombard
|
||||||
* Ulrich Seifert
|
* Ulrich Seifert
|
||||||
* Vil Brekin
|
* Vil Brekin
|
||||||
|
* Vincent Laurent
|
||||||
* Vittorio Gambaletta
|
* Vittorio Gambaletta
|
||||||
* Wendy Willard
|
* Wendy Willard
|
||||||
* Wessel Dankers
|
* Wessel Dankers
|
||||||
|
|
5
aclocal.m4
vendored
5
aclocal.m4
vendored
|
@ -1138,12 +1138,7 @@ m4_include([m4/ax_append_flag.m4])
|
||||||
m4_include([m4/ax_cflags_warn_all.m4])
|
m4_include([m4/ax_cflags_warn_all.m4])
|
||||||
m4_include([m4/ax_check_compile_flag.m4])
|
m4_include([m4/ax_check_compile_flag.m4])
|
||||||
m4_include([m4/ax_check_link_flag.m4])
|
m4_include([m4/ax_check_link_flag.m4])
|
||||||
m4_include([m4/ax_code_coverage.m4])
|
|
||||||
m4_include([m4/ax_require_defined.m4])
|
m4_include([m4/ax_require_defined.m4])
|
||||||
m4_include([m4/curses.m4])
|
|
||||||
m4_include([m4/libgcrypt.m4])
|
|
||||||
m4_include([m4/lzo.m4])
|
m4_include([m4/lzo.m4])
|
||||||
m4_include([m4/miniupnpc.m4])
|
|
||||||
m4_include([m4/openssl.m4])
|
m4_include([m4/openssl.m4])
|
||||||
m4_include([m4/readline.m4])
|
|
||||||
m4_include([m4/zlib.m4])
|
m4_include([m4/zlib.m4])
|
||||||
|
|
99
config.h.in
99
config.h.in
|
@ -1,8 +1,5 @@
|
||||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
/* Disable support for the legacy (tinc 1.0) protocol */
|
|
||||||
#undef DISABLE_LEGACY
|
|
||||||
|
|
||||||
/* Support for jumbograms (packets up to 9000 bytes) */
|
/* Support for jumbograms (packets up to 9000 bytes) */
|
||||||
#undef ENABLE_JUMBOGRAMS
|
#undef ENABLE_JUMBOGRAMS
|
||||||
|
|
||||||
|
@ -18,6 +15,9 @@
|
||||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||||
#undef HAVE_ARPA_INET_H
|
#undef HAVE_ARPA_INET_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||||
|
#undef HAVE_ARPA_NAMESER_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `asprintf' function. */
|
/* Define to 1 if you have the `asprintf' function. */
|
||||||
#undef HAVE_ASPRINTF
|
#undef HAVE_ASPRINTF
|
||||||
|
|
||||||
|
@ -27,12 +27,6 @@
|
||||||
/* Unknown BSD variant */
|
/* Unknown BSD variant */
|
||||||
#undef HAVE_BSD
|
#undef HAVE_BSD
|
||||||
|
|
||||||
/* have curses support */
|
|
||||||
#undef HAVE_CURSES
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <curses.h> header file. */
|
|
||||||
#undef HAVE_CURSES_H
|
|
||||||
|
|
||||||
/* Cygwin */
|
/* Cygwin */
|
||||||
#undef HAVE_CYGWIN
|
#undef HAVE_CYGWIN
|
||||||
|
|
||||||
|
@ -46,6 +40,22 @@
|
||||||
you don't. */
|
you don't. */
|
||||||
#undef HAVE_DECL_EVP_AES_256_CFB
|
#undef HAVE_DECL_EVP_AES_256_CFB
|
||||||
|
|
||||||
|
/* Define to 1 if you have the declaration of `freeaddrinfo', and to 0 if you
|
||||||
|
don't. */
|
||||||
|
#undef HAVE_DECL_FREEADDRINFO
|
||||||
|
|
||||||
|
/* Define to 1 if you have the declaration of `gai_strerror', and to 0 if you
|
||||||
|
don't. */
|
||||||
|
#undef HAVE_DECL_GAI_STRERROR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the declaration of `getaddrinfo', and to 0 if you
|
||||||
|
don't. */
|
||||||
|
#undef HAVE_DECL_GETADDRINFO
|
||||||
|
|
||||||
|
/* Define to 1 if you have the declaration of `getnameinfo', and to 0 if you
|
||||||
|
don't. */
|
||||||
|
#undef HAVE_DECL_GETNAMEINFO
|
||||||
|
|
||||||
/* Define to 1 if you have the declaration of `OpenSSL_add_all_algorithms',
|
/* Define to 1 if you have the declaration of `OpenSSL_add_all_algorithms',
|
||||||
and to 0 if you don't. */
|
and to 0 if you don't. */
|
||||||
#undef HAVE_DECL_OPENSSL_ADD_ALL_ALGORITHMS
|
#undef HAVE_DECL_OPENSSL_ADD_ALL_ALGORITHMS
|
||||||
|
@ -63,9 +73,6 @@
|
||||||
/* DragonFly */
|
/* DragonFly */
|
||||||
#undef HAVE_DRAGONFLY
|
#undef HAVE_DRAGONFLY
|
||||||
|
|
||||||
/* Define to 1 if you have the `ERR_remove_state' function. */
|
|
||||||
#undef HAVE_ERR_REMOVE_STATE
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
|
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
|
||||||
#undef HAVE_EVP_CIPHER_CTX_NEW
|
#undef HAVE_EVP_CIPHER_CTX_NEW
|
||||||
|
|
||||||
|
@ -87,9 +94,6 @@
|
||||||
/* FreeBSD */
|
/* FreeBSD */
|
||||||
#undef HAVE_FREEBSD
|
#undef HAVE_FREEBSD
|
||||||
|
|
||||||
/* Define to 1 if you have the <gcrypt.h> header file. */
|
|
||||||
#undef HAVE_GCRYPT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <getopt.h> header file. */
|
/* Define to 1 if you have the <getopt.h> header file. */
|
||||||
#undef HAVE_GETOPT_H
|
#undef HAVE_GETOPT_H
|
||||||
|
|
||||||
|
@ -99,12 +103,12 @@
|
||||||
/* Define to 1 if you have the `gettimeofday' function. */
|
/* Define to 1 if you have the `gettimeofday' function. */
|
||||||
#undef HAVE_GETTIMEOFDAY
|
#undef HAVE_GETTIMEOFDAY
|
||||||
|
|
||||||
/* Define to 1 if you have the `HMAC_CTX_new' function. */
|
|
||||||
#undef HAVE_HMAC_CTX_NEW
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
#undef HAVE_INTTYPES_H
|
#undef HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||||
|
#undef HAVE_LIBNSL
|
||||||
|
|
||||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||||
#undef HAVE_LIBRESOLV
|
#undef HAVE_LIBRESOLV
|
||||||
|
|
||||||
|
@ -138,18 +142,9 @@
|
||||||
/* MinGW */
|
/* MinGW */
|
||||||
#undef HAVE_MINGW
|
#undef HAVE_MINGW
|
||||||
|
|
||||||
/* have miniupnpc support */
|
|
||||||
#undef HAVE_MINIUPNPC
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <miniupnpc/miniupnpc.h> header file. */
|
|
||||||
#undef HAVE_MINIUPNPC_MINIUPNPC_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `mlockall' function. */
|
/* Define to 1 if you have the `mlockall' function. */
|
||||||
#undef HAVE_MLOCKALL
|
#undef HAVE_MLOCKALL
|
||||||
|
|
||||||
/* Define to 1 if you have the `nanosleep' function. */
|
|
||||||
#undef HAVE_NANOSLEEP
|
|
||||||
|
|
||||||
/* NetBSD */
|
/* NetBSD */
|
||||||
#undef HAVE_NETBSD
|
#undef HAVE_NETBSD
|
||||||
|
|
||||||
|
@ -237,30 +232,24 @@
|
||||||
/* Define to 1 if you have the <openssl/sha.h> header file. */
|
/* Define to 1 if you have the <openssl/sha.h> header file. */
|
||||||
#undef HAVE_OPENSSL_SHA_H
|
#undef HAVE_OPENSSL_SHA_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `pselect' function. */
|
||||||
|
#undef HAVE_PSELECT
|
||||||
|
|
||||||
/* Define to 1 if you have the `putenv' function. */
|
/* Define to 1 if you have the `putenv' function. */
|
||||||
#undef HAVE_PUTENV
|
#undef HAVE_PUTENV
|
||||||
|
|
||||||
/* Define to 1 if you have the `RAND_bytes' function. */
|
/* Define to 1 if you have the `RAND_bytes' function. */
|
||||||
#undef HAVE_RAND_BYTES
|
#undef HAVE_RAND_BYTES
|
||||||
|
|
||||||
/* have readline support */
|
|
||||||
#undef HAVE_READLINE
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
|
||||||
#undef HAVE_READLINE_HISTORY_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <readline/readline.h> header file. */
|
|
||||||
#undef HAVE_READLINE_READLINE_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `recvmmsg' function. */
|
|
||||||
#undef HAVE_RECVMMSG
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <resolv.h> header file. */
|
/* Define to 1 if you have the <resolv.h> header file. */
|
||||||
#undef HAVE_RESOLV_H
|
#undef HAVE_RESOLV_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `RSA_set0_key' function. */
|
/* Define to 1 if you have the `RSA_set0_key' function. */
|
||||||
#undef HAVE_RSA_SET0_KEY
|
#undef HAVE_RSA_SET0_KEY
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `socklen_t'. */
|
||||||
|
#undef HAVE_SOCKLEN_T
|
||||||
|
|
||||||
/* Solaris/SunOS */
|
/* Solaris/SunOS */
|
||||||
#undef HAVE_SOLARIS
|
#undef HAVE_SOLARIS
|
||||||
|
|
||||||
|
@ -279,6 +268,9 @@
|
||||||
/* Define to 1 if you have the `strsignal' function. */
|
/* Define to 1 if you have the `strsignal' function. */
|
||||||
#undef HAVE_STRSIGNAL
|
#undef HAVE_STRSIGNAL
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `struct addrinfo'. */
|
||||||
|
#undef HAVE_STRUCT_ADDRINFO
|
||||||
|
|
||||||
/* Define to 1 if the system has the type `struct arphdr'. */
|
/* Define to 1 if the system has the type `struct arphdr'. */
|
||||||
#undef HAVE_STRUCT_ARPHDR
|
#undef HAVE_STRUCT_ARPHDR
|
||||||
|
|
||||||
|
@ -294,6 +286,12 @@
|
||||||
/* Define to 1 if the system has the type `struct icmp6_hdr'. */
|
/* Define to 1 if the system has the type `struct icmp6_hdr'. */
|
||||||
#undef HAVE_STRUCT_ICMP6_HDR
|
#undef HAVE_STRUCT_ICMP6_HDR
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `struct in6_addr'. */
|
||||||
|
#undef HAVE_STRUCT_IN6_ADDR
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `struct in_addr'. */
|
||||||
|
#undef HAVE_STRUCT_IN_ADDR
|
||||||
|
|
||||||
/* Define to 1 if the system has the type `struct ip'. */
|
/* Define to 1 if the system has the type `struct ip'. */
|
||||||
#undef HAVE_STRUCT_IP
|
#undef HAVE_STRUCT_IP
|
||||||
|
|
||||||
|
@ -306,9 +304,15 @@
|
||||||
/* Define to 1 if the system has the type `struct nd_opt_hdr'. */
|
/* Define to 1 if the system has the type `struct nd_opt_hdr'. */
|
||||||
#undef HAVE_STRUCT_ND_OPT_HDR
|
#undef HAVE_STRUCT_ND_OPT_HDR
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `struct sockaddr_in6'. */
|
||||||
|
#undef HAVE_STRUCT_SOCKADDR_IN6
|
||||||
|
|
||||||
/* Define to 1 if you have the <syslog.h> header file. */
|
/* Define to 1 if you have the <syslog.h> header file. */
|
||||||
#undef HAVE_SYSLOG_H
|
#undef HAVE_SYSLOG_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `system' function. */
|
||||||
|
#undef HAVE_SYSTEM
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/file.h> header file. */
|
/* Define to 1 if you have the <sys/file.h> header file. */
|
||||||
#undef HAVE_SYS_FILE_H
|
#undef HAVE_SYS_FILE_H
|
||||||
|
|
||||||
|
@ -336,8 +340,8 @@
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
#undef HAVE_SYS_TYPES_H
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/un.h> header file. */
|
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||||
#undef HAVE_SYS_UN_H
|
#undef HAVE_SYS_UIO_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||||
#undef HAVE_SYS_WAIT_H
|
#undef HAVE_SYS_WAIT_H
|
||||||
|
@ -348,6 +352,9 @@
|
||||||
/* Define to 1 if you have the `unsetenv' function. */
|
/* Define to 1 if you have the `unsetenv' function. */
|
||||||
#undef HAVE_UNSETENV
|
#undef HAVE_UNSETENV
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `usleep' function. */
|
||||||
|
#undef HAVE_USLEEP
|
||||||
|
|
||||||
/* Define to 1 if you have the `vsyslog' function. */
|
/* Define to 1 if you have the `vsyslog' function. */
|
||||||
#undef HAVE_VSYSLOG
|
#undef HAVE_VSYSLOG
|
||||||
|
|
||||||
|
@ -412,6 +419,9 @@
|
||||||
/* Version number of package */
|
/* Version number of package */
|
||||||
#undef VERSION
|
#undef VERSION
|
||||||
|
|
||||||
|
/* Compile with support for Windows 2000 */
|
||||||
|
#undef WITH_WINDOWS2000
|
||||||
|
|
||||||
/* Define to 1 if on MINIX. */
|
/* Define to 1 if on MINIX. */
|
||||||
#undef _MINIX
|
#undef _MINIX
|
||||||
|
|
||||||
|
@ -428,8 +438,5 @@
|
||||||
/* Defined if the __malloc__ attribute is not supported. */
|
/* Defined if the __malloc__ attribute is not supported. */
|
||||||
#undef __malloc__
|
#undef __malloc__
|
||||||
|
|
||||||
/* Defined if the __nonnull__ attribute is not supported. */
|
/* Define to `int' if <sys/types.h> does not define. */
|
||||||
#undef __nonnull__
|
#undef pid_t
|
||||||
|
|
||||||
/* Defined if the __warn_unused_result__ attribute is not supported. */
|
|
||||||
#undef __warn_unused_result__
|
|
||||||
|
|
106
configure.ac
106
configure.ac
|
@ -1,11 +1,9 @@
|
||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
origcflags="$CFLAGS"
|
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([tinc], m4_esyscmd_s((git describe || echo UNKNOWN) | sed 's/release-//'))
|
AC_INIT([tinc], [1.0.36])
|
||||||
AC_CONFIG_SRCDIR([src/tincd.c])
|
AC_CONFIG_SRCDIR([src/tincd.c])
|
||||||
AM_INIT_AUTOMAKE([std-options subdir-objects nostdinc silent-rules -Wall])
|
AM_INIT_AUTOMAKE([1.11 check-news std-options subdir-objects nostdinc silent-rules -Wall])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
@ -20,11 +18,8 @@ dnl Checks for programs.
|
||||||
AC_PROG_CC_C99
|
AC_PROG_CC_C99
|
||||||
AC_PROG_CPP
|
AC_PROG_CPP
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AM_PROG_CC_C_O
|
|
||||||
|
|
||||||
dnl Check whether to enable code coverage testing, and if so, clear the default CFLAGS.
|
AM_PROG_CC_C_O
|
||||||
AX_CODE_COVERAGE
|
|
||||||
AS_IF([test "x$enable_code_coverage" = "xyes" -a "x$origcflags" = "x"], [CFLAGS=""])
|
|
||||||
|
|
||||||
dnl Check and set OS
|
dnl Check and set OS
|
||||||
|
|
||||||
|
@ -71,9 +66,7 @@ case $host_os in
|
||||||
*mingw*)
|
*mingw*)
|
||||||
mingw=true
|
mingw=true
|
||||||
AC_DEFINE(HAVE_MINGW, 1, [MinGW])
|
AC_DEFINE(HAVE_MINGW, 1, [MinGW])
|
||||||
LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi"
|
LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32"
|
||||||
LDFLAGS="$LDFLAGS -static"
|
|
||||||
CPPFLAGS="$CPPFLAGS -DMINIUPNP_STATICLIB"
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
AC_MSG_ERROR("Unknown operating system.")
|
AC_MSG_ERROR("Unknown operating system.")
|
||||||
|
@ -114,6 +107,13 @@ AC_ARG_ENABLE(tunemu,
|
||||||
[tunemu=false]
|
[tunemu=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,
|
AC_ARG_WITH(systemd,
|
||||||
AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd service files @<:@to DIR if specified@:>@]),
|
AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd service files @<:@to DIR if specified@:>@]),
|
||||||
[ systemd=true; systemd_path="$with_systemd" ],
|
[ systemd=true; systemd_path="$with_systemd" ],
|
||||||
|
@ -137,8 +137,12 @@ AM_CONDITIONAL(WITH_SYSTEMD, test "$systemd" = true)
|
||||||
|
|
||||||
AC_CACHE_SAVE
|
AC_CACHE_SAVE
|
||||||
|
|
||||||
AS_IF([test -d /sw/include], [CPPFLAGS="$CPPFLAGS -I/sw/include"])
|
if test -d /sw/include ; then
|
||||||
AS_IF([test -d /sw/lib], [LIBS="$LIBS -L/sw/lib"])
|
CPPFLAGS="$CPPFLAGS -I/sw/include"
|
||||||
|
fi
|
||||||
|
if test -d /sw/lib ; then
|
||||||
|
LIBS="$LIBS -L/sw/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Compiler hardening flags
|
dnl Compiler hardening flags
|
||||||
dnl No -fstack-protector-all because it doesn't work on all platforms or architectures.
|
dnl No -fstack-protector-all because it doesn't work on all platforms or architectures.
|
||||||
|
@ -165,11 +169,13 @@ AS_IF([test "x$enable_hardening" != "xno"],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
dnl Checks for libraries.
|
||||||
|
|
||||||
dnl Checks for header files.
|
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.
|
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_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([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/wait.h netdb.h arpa/inet.h arpa/nameser.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],
|
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.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 netpacket/packet.h],
|
||||||
[], [], [#include "$srcdir/src/have.h"]
|
[], [], [#include "$srcdir/src/have.h"]
|
||||||
)
|
)
|
||||||
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
|
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
|
||||||
|
@ -180,78 +186,48 @@ AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
|
||||||
)
|
)
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
tinc_ATTRIBUTE(__malloc__)
|
AC_TYPE_PID_T
|
||||||
tinc_ATTRIBUTE(__nonnull__)
|
|
||||||
tinc_ATTRIBUTE(__warn_unused_result__)
|
|
||||||
|
|
||||||
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], , ,
|
tinc_ATTRIBUTE(__malloc__)
|
||||||
|
|
||||||
|
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], , ,
|
||||||
[#include "$srcdir/src/have.h"]
|
[#include "$srcdir/src/have.h"]
|
||||||
)
|
)
|
||||||
|
|
||||||
dnl Checks for library functions.
|
dnl Checks for library functions.
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
AC_CHECK_FUNCS([asprintf daemon fchmod flock fork gettimeofday mlockall putenv recvmmsg strsignal nanosleep unsetenv vsyslog devname fdevname],
|
AC_CHECK_FUNCS([asprintf daemon fchmod flock fork gettimeofday mlockall pselect putenv strsignal system unsetenv usleep vsyslog devname fdevname],
|
||||||
[], [], [#include "$srcdir/src/have.h"]
|
[], [], [#include "$srcdir/src/have.h"]
|
||||||
)
|
)
|
||||||
|
|
||||||
AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false])
|
AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false])
|
||||||
AM_CONDITIONAL(GETOPT, test "$getopt" = true)
|
AM_CONDITIONAL(GETOPT, test "$getopt" = true)
|
||||||
|
|
||||||
|
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_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
|
AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <resolv.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_CACHE_SAVE
|
||||||
|
|
||||||
AC_ARG_ENABLE(legacy-protocol,
|
|
||||||
AS_HELP_STRING([--disable-legacy-protocol], [disable support for the legacy (tinc 1.0) protocol]),
|
|
||||||
[ AS_IF([test "x$enable_legacy_protocol" = "xno"],
|
|
||||||
[ AC_DEFINE(DISABLE_LEGACY, 1, [Disable support for the legacy (tinc 1.0) protocol]) ])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
dnl These are defined in files in m4/
|
dnl These are defined in files in m4/
|
||||||
|
|
||||||
dnl AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
|
|
||||||
dnl AC_ARG_WITH(openssl, AC_HELP_STRING([--without-openssl], [disable support for OpenSSL])], [])
|
|
||||||
|
|
||||||
tinc_CURSES
|
|
||||||
tinc_READLINE
|
|
||||||
tinc_ZLIB
|
tinc_ZLIB
|
||||||
tinc_LZO
|
tinc_LZO
|
||||||
|
tinc_OPENSSL
|
||||||
AS_IF([test "x$enable_legacy_protocol" != "xno"],
|
|
||||||
[AS_IF([test -n "$with_libgcrypt"],
|
|
||||||
[gcrypt=true; tinc_LIBGCRYPT],
|
|
||||||
[openssl=true; tinc_OPENSSL])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
AM_CONDITIONAL(OPENSSL, test -n "$openssl")
|
|
||||||
AM_CONDITIONAL(GCRYPT, test -n "$gcrypt")
|
|
||||||
|
|
||||||
tinc_MINIUPNPC
|
|
||||||
AM_CONDITIONAL(MINIUPNPC, test "x$enable_miniupnpc" = "xyes")
|
|
||||||
|
|
||||||
dnl Check if support for jumbograms is requested
|
dnl Check if support for jumbograms is requested
|
||||||
AC_ARG_ENABLE(jumbograms,
|
AC_ARG_ENABLE(jumbograms,
|
||||||
|
@ -266,6 +242,6 @@ if test "x$runstatedir" = "x"; then
|
||||||
AC_SUBST([runstatedir], ['${localstatedir}/run'])
|
AC_SUBST([runstatedir], ['${localstatedir}/run'])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile test/Makefile systemd/Makefile])
|
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile systemd/Makefile])
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
|
@ -3,23 +3,20 @@
|
||||||
info_TEXINFOS = tinc.texi
|
info_TEXINFOS = tinc.texi
|
||||||
tinc_TEXINFOS = tincinclude.texi
|
tinc_TEXINFOS = tincinclude.texi
|
||||||
|
|
||||||
man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8
|
man_MANS = tincd.8 tinc.conf.5
|
||||||
|
|
||||||
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config
|
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
|
||||||
|
|
||||||
CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
|
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
|
||||||
|
|
||||||
|
texi2html: tinc.texi
|
||||||
|
$(AM_V_GEN)texi2html -split=chapter $<
|
||||||
|
|
||||||
tincd.8.html: tincd.8
|
tincd.8.html: tincd.8
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
$(AM_V_GEN)w3mman2html $< > $@
|
||||||
|
|
||||||
tinc.8.html: tinc.8
|
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
|
||||||
|
|
||||||
tinc-gui.8.html: tinc-gui.8
|
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
|
||||||
|
|
||||||
tinc.conf.5.html: tinc.conf.5
|
tinc.conf.5.html: tinc.conf.5
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
$(AM_V_GEN)w3mman2html $< > $@
|
||||||
|
|
||||||
substitute = sed \
|
substitute = sed \
|
||||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||||
|
@ -31,12 +28,6 @@ substitute = sed \
|
||||||
tincd.8: $(srcdir)/tincd.8.in
|
tincd.8: $(srcdir)/tincd.8.in
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
||||||
|
|
||||||
tinc.8: $(srcdir)/tinc.8.in
|
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.8.in > $@
|
|
||||||
|
|
||||||
tinc-gui.8: $(srcdir)/tinc-gui.8.in
|
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc-gui.8.in > $@
|
|
||||||
|
|
||||||
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
||||||
|
|
||||||
|
|
|
@ -94,12 +94,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||||
$(top_srcdir)/m4/ax_code_coverage.m4 \
|
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||||
$(top_srcdir)/m4/ax_require_defined.m4 \
|
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \
|
$(top_srcdir)/configure.ac
|
||||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \
|
|
||||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \
|
|
||||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac
|
|
||||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
$(ACLOCAL_M4)
|
$(ACLOCAL_M4)
|
||||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||||
|
@ -212,15 +209,8 @@ AWK = @AWK@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CCDEPMODE = @CCDEPMODE@
|
CCDEPMODE = @CCDEPMODE@
|
||||||
CFLAGS = @CFLAGS@
|
CFLAGS = @CFLAGS@
|
||||||
CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
|
|
||||||
CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@
|
|
||||||
CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@
|
|
||||||
CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
|
|
||||||
CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
|
|
||||||
CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@
|
|
||||||
CPP = @CPP@
|
CPP = @CPP@
|
||||||
CPPFLAGS = @CPPFLAGS@
|
CPPFLAGS = @CPPFLAGS@
|
||||||
CURSES_LIBS = @CURSES_LIBS@
|
|
||||||
CYGPATH_W = @CYGPATH_W@
|
CYGPATH_W = @CYGPATH_W@
|
||||||
DEFS = @DEFS@
|
DEFS = @DEFS@
|
||||||
DEPDIR = @DEPDIR@
|
DEPDIR = @DEPDIR@
|
||||||
|
@ -229,21 +219,17 @@ ECHO_N = @ECHO_N@
|
||||||
ECHO_T = @ECHO_T@
|
ECHO_T = @ECHO_T@
|
||||||
EGREP = @EGREP@
|
EGREP = @EGREP@
|
||||||
EXEEXT = @EXEEXT@
|
EXEEXT = @EXEEXT@
|
||||||
GCOV = @GCOV@
|
|
||||||
GENHTML = @GENHTML@
|
|
||||||
GREP = @GREP@
|
GREP = @GREP@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||||
LCOV = @LCOV@
|
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBOBJS = @LIBOBJS@
|
LIBOBJS = @LIBOBJS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
LTLIBOBJS = @LTLIBOBJS@
|
LTLIBOBJS = @LTLIBOBJS@
|
||||||
MAKEINFO = @MAKEINFO@
|
MAKEINFO = @MAKEINFO@
|
||||||
MINIUPNPC_LIBS = @MINIUPNPC_LIBS@
|
|
||||||
MKDIR_P = @MKDIR_P@
|
MKDIR_P = @MKDIR_P@
|
||||||
OBJEXT = @OBJEXT@
|
OBJEXT = @OBJEXT@
|
||||||
PACKAGE = @PACKAGE@
|
PACKAGE = @PACKAGE@
|
||||||
|
@ -254,8 +240,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||||
PACKAGE_URL = @PACKAGE_URL@
|
PACKAGE_URL = @PACKAGE_URL@
|
||||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||||
READLINE_LIBS = @READLINE_LIBS@
|
|
||||||
SED = @SED@
|
|
||||||
SET_MAKE = @SET_MAKE@
|
SET_MAKE = @SET_MAKE@
|
||||||
SHELL = @SHELL@
|
SHELL = @SHELL@
|
||||||
STRIP = @STRIP@
|
STRIP = @STRIP@
|
||||||
|
@ -314,9 +298,9 @@ top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
info_TEXINFOS = tinc.texi
|
info_TEXINFOS = tinc.texi
|
||||||
tinc_TEXINFOS = tincinclude.texi
|
tinc_TEXINFOS = tincinclude.texi
|
||||||
man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8
|
man_MANS = tincd.8 tinc.conf.5
|
||||||
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config
|
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
|
||||||
CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi
|
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
|
||||||
substitute = sed \
|
substitute = sed \
|
||||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||||
-e s,'@VERSION\@',"$(VERSION)",g \
|
-e s,'@VERSION\@',"$(VERSION)",g \
|
||||||
|
@ -846,27 +830,18 @@ uninstall-man: uninstall-man5 uninstall-man8
|
||||||
.PRECIOUS: Makefile
|
.PRECIOUS: Makefile
|
||||||
|
|
||||||
|
|
||||||
|
texi2html: tinc.texi
|
||||||
|
$(AM_V_GEN)texi2html -split=chapter $<
|
||||||
|
|
||||||
tincd.8.html: tincd.8
|
tincd.8.html: tincd.8
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
$(AM_V_GEN)w3mman2html $< > $@
|
||||||
|
|
||||||
tinc.8.html: tinc.8
|
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
|
||||||
|
|
||||||
tinc-gui.8.html: tinc-gui.8
|
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
|
||||||
|
|
||||||
tinc.conf.5.html: tinc.conf.5
|
tinc.conf.5.html: tinc.conf.5
|
||||||
$(AM_V_GEN)w3mman2html $? > $@
|
$(AM_V_GEN)w3mman2html $< > $@
|
||||||
|
|
||||||
tincd.8: $(srcdir)/tincd.8.in
|
tincd.8: $(srcdir)/tincd.8.in
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
||||||
|
|
||||||
tinc.8: $(srcdir)/tinc.8.in
|
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.8.in > $@
|
|
||||||
|
|
||||||
tinc-gui.8: $(srcdir)/tinc-gui.8.in
|
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc-gui.8.in > $@
|
|
||||||
|
|
||||||
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
||||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ Name = alpha
|
||||||
ConnectTo = beta
|
ConnectTo = beta
|
||||||
|
|
||||||
# The tap device tinc will use.
|
# The tap device tinc will use.
|
||||||
# Default is /dev/tap0 for ethertap or FreeBSD,
|
# /dev/tap0 for ethertap, FreeBSD or OpenBSD
|
||||||
# /dev/tun0 for Solaris and OpenBSD,
|
# /dev/tun0 for Solaris
|
||||||
# and /dev/net/tun for Linux tun/tap device.
|
# /dev/net/tun for Linux tun/tap
|
||||||
Device = /dev/net/tun
|
Device = /dev/net/tun
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
.Dd 2011-06-26
|
|
||||||
.Dt TINC-GUI 8
|
|
||||||
.\" Manual page created by:
|
|
||||||
.\" Guus Sliepen <guus@tinc-vpn.org>
|
|
||||||
.Sh NAME
|
|
||||||
.Nm tinc-gui
|
|
||||||
.Nd tinc GUI
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op Fl n
|
|
||||||
.Op Fl -net Ns = Ns Ar NETNAME
|
|
||||||
.Op Fl -pidfile Ns = Ns Ar FILENAME
|
|
||||||
.Op Fl -help
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
This is a Python/wxWidgets based graphical user interface for tinc, a secure virtual private network (VPN) project.
|
|
||||||
.Nm
|
|
||||||
communicates with
|
|
||||||
.Xr tincd 8
|
|
||||||
to alter and inspect the running VPN's state.
|
|
||||||
It can show the current settings, the list of connections, nodes, subnets, and edges.
|
|
||||||
For now, the debug level can be changed from the GUI, and by right-clicking on a node in the list of connections,
|
|
||||||
a pop-up menu will appear that allows one to disconnect that node.
|
|
||||||
.Sh OPTIONS
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Fl n, -net Ns = Ns Ar NETNAME
|
|
||||||
Communicate with tincd(8) connected with
|
|
||||||
.Ar NETNAME .
|
|
||||||
.It Fl -pidfile Ns = Ns Ar FILENAME
|
|
||||||
Use the cookie from
|
|
||||||
.Ar FILENAME
|
|
||||||
to authenticate with a running tinc daemon.
|
|
||||||
If unspecified, the default is
|
|
||||||
.Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
|
|
||||||
.It Fl -help
|
|
||||||
Display short list of options.
|
|
||||||
.El
|
|
||||||
.Sh BUGS
|
|
||||||
The GUI is not finished yet, the final version will have much more functionality.
|
|
||||||
If you find any bugs, report them to tinc@tinc-vpn.org.
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr tincd 8 ,
|
|
||||||
.Pa http://www.tinc-vpn.org/ .
|
|
||||||
.Pp
|
|
||||||
The full documentation for tinc is maintained as a Texinfo manual.
|
|
||||||
If the info and tinc programs are properly installed at your site,
|
|
||||||
the command
|
|
||||||
.Ic info tinc
|
|
||||||
should give you access to the complete manual.
|
|
||||||
.Pp
|
|
||||||
tinc comes with ABSOLUTELY NO WARRANTY.
|
|
||||||
This is free software, and you are welcome to redistribute it under certain conditions;
|
|
||||||
see the file COPYING for details.
|
|
||||||
.Sh AUTHORS
|
|
||||||
.An "Ivo Timmermans"
|
|
||||||
.An "Guus Sliepen" Aq guus@tinc-vpn.org
|
|
||||||
.Pp
|
|
||||||
And thanks to many others for their contributions to tinc!
|
|
345
doc/tinc.8.in
345
doc/tinc.8.in
|
@ -1,345 +0,0 @@
|
||||||
.Dd 2014-01-16
|
|
||||||
.Dt TINCCTL 8
|
|
||||||
.\" Manual page created by:
|
|
||||||
.\" Scott Lamb
|
|
||||||
.Sh NAME
|
|
||||||
.Nm tinc
|
|
||||||
.Nd tinc VPN control
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op Fl bcn
|
|
||||||
.Op Fl -config Ns = Ns Ar DIR
|
|
||||||
.Op Fl -net Ns = Ns Ar NETNAME
|
|
||||||
.Op Fl -pidfile Ns = Ns Ar FILENAME
|
|
||||||
.Op Fl -batch
|
|
||||||
.Op Fl -force
|
|
||||||
.Op Fl -help
|
|
||||||
.Op Fl -version
|
|
||||||
.Op Ar COMMAND
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
This is the control program of tinc, a secure virtual private network (VPN)
|
|
||||||
project.
|
|
||||||
.Nm
|
|
||||||
can start and stop
|
|
||||||
.Xr tincd 8 ,
|
|
||||||
and can to alter and inspect the state of a running VPN.
|
|
||||||
It can also be used to change the configuration,
|
|
||||||
or to import or export host configuration files from other nodes.
|
|
||||||
|
|
||||||
If
|
|
||||||
.Nm
|
|
||||||
is started with a
|
|
||||||
.Ar COMMAND ,
|
|
||||||
this command is immediately executed, after which
|
|
||||||
.Nm
|
|
||||||
exits.
|
|
||||||
If no
|
|
||||||
.Ar COMMAND
|
|
||||||
is given,
|
|
||||||
.Nm
|
|
||||||
will act as a shell;
|
|
||||||
it will display a prompt, and commands can be entered on the prompt.
|
|
||||||
If
|
|
||||||
.Nm
|
|
||||||
is compiled with libreadline, history and command completion are available on the prompt.
|
|
||||||
One can also pipe a script containing commands through
|
|
||||||
.Nm .
|
|
||||||
In that case, lines starting with a # symbol will be ignored.
|
|
||||||
.Sh OPTIONS
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Fl n, -net Ns = Ns Ar NETNAME
|
|
||||||
Communicate with tincd(8) connected with
|
|
||||||
.Ar NETNAME .
|
|
||||||
.It Fl -pidfile Ns = Ns Ar FILENAME
|
|
||||||
Use the cookie from
|
|
||||||
.Ar FILENAME
|
|
||||||
to authenticate with a running tinc daemon.
|
|
||||||
If unspecified, the default is
|
|
||||||
.Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
|
|
||||||
.It Fl b, -batch
|
|
||||||
Don't ask for anything (non-interactive mode).
|
|
||||||
.It Fl -force
|
|
||||||
Force some commands to work despite warnings.
|
|
||||||
.It Fl -help
|
|
||||||
Display short list of options.
|
|
||||||
.It Fl -version
|
|
||||||
Output version information and exit.
|
|
||||||
.El
|
|
||||||
.Sh ENVIRONMENT VARIABLES
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It Ev NETNAME
|
|
||||||
If no netname is specified on the command line with the
|
|
||||||
.Fl n
|
|
||||||
option, the value of this environment variable is used.
|
|
||||||
.El
|
|
||||||
.Sh COMMANDS
|
|
||||||
.Bl -tag -width indent
|
|
||||||
.It init Op Ar name
|
|
||||||
Create initial configuration files and RSA and Ed25519 keypairs with default length.
|
|
||||||
If no
|
|
||||||
.Ar name
|
|
||||||
for this node is given, it will be asked for.
|
|
||||||
.It get Ar variable
|
|
||||||
Print the current value of configuration variable
|
|
||||||
.Ar variable .
|
|
||||||
If more than one variable with the same name exists,
|
|
||||||
the value of each of them will be printed on a separate line.
|
|
||||||
.It set Ar variable Ar value
|
|
||||||
Set configuration variable
|
|
||||||
.Ar variable
|
|
||||||
to the given
|
|
||||||
.Ar value .
|
|
||||||
All previously existing configuration variables with the same name are removed.
|
|
||||||
To set a variable for a specific host, use the notation
|
|
||||||
.Ar host Ns Li . Ns Ar variable .
|
|
||||||
.It add Ar variable Ar value
|
|
||||||
As above, but without removing any previously existing configuration variables.
|
|
||||||
If the variable already exists with the given value, nothing happens.
|
|
||||||
.It del Ar variable Op Ar value
|
|
||||||
Remove configuration variables with the same name and
|
|
||||||
.Ar value .
|
|
||||||
If no
|
|
||||||
.Ar value
|
|
||||||
is given, all configuration variables with the same name will be removed.
|
|
||||||
.It edit Ar filename
|
|
||||||
Start an editor for the given configuration file.
|
|
||||||
You do not need to specify the full path to the file.
|
|
||||||
.It export
|
|
||||||
Export the host configuration file of the local node to standard output.
|
|
||||||
.It export-all
|
|
||||||
Export all host configuration files to standard output.
|
|
||||||
.It import
|
|
||||||
Import host configuration data generated by the
|
|
||||||
.Nm
|
|
||||||
export command from standard input.
|
|
||||||
Already existing host configuration files are not overwritten unless the option
|
|
||||||
.Fl -force
|
|
||||||
is used.
|
|
||||||
.It exchange
|
|
||||||
The same as export followed by import.
|
|
||||||
.It exchange-all
|
|
||||||
The same as export-all followed by import.
|
|
||||||
.It invite Ar name
|
|
||||||
Prepares an invitation for a new node with the given
|
|
||||||
.Ar name ,
|
|
||||||
and prints a short invitation URL that can be used with the join command.
|
|
||||||
.It join Op Ar URL
|
|
||||||
Join an existing VPN using an invitation URL created using the invite command.
|
|
||||||
If no
|
|
||||||
.Ar URL
|
|
||||||
is given, it will be read from standard input.
|
|
||||||
.It start Op tincd options
|
|
||||||
Start
|
|
||||||
.Xr tincd 8 ,
|
|
||||||
optionally with the given extra options.
|
|
||||||
.It stop
|
|
||||||
Stop
|
|
||||||
.Xr tincd 8 .
|
|
||||||
.It restart Op tincd options
|
|
||||||
Restart
|
|
||||||
.Xr tincd 8 ,
|
|
||||||
optionally with the given extra options.
|
|
||||||
.It reload
|
|
||||||
Partially rereads configuration files. Connections to hosts whose host
|
|
||||||
config files are removed are closed. New outgoing connections specified
|
|
||||||
in
|
|
||||||
.Xr tinc.conf 5
|
|
||||||
will be made.
|
|
||||||
.It pid
|
|
||||||
Shows the PID of the currently running
|
|
||||||
.Xr tincd 8 .
|
|
||||||
.It generate-keys Op bits
|
|
||||||
Generate both RSA and Ed25519 keypairs (see below) and exit.
|
|
||||||
.It generate-ed25519-keys
|
|
||||||
Generate public/private Ed25519 keypair and exit.
|
|
||||||
.It generate-rsa-keys Op bits
|
|
||||||
Generate public/private RSA keypair and exit.
|
|
||||||
If
|
|
||||||
.Ar bits
|
|
||||||
is omitted, the default length will be 2048 bits.
|
|
||||||
When saving keys to existing files, tinc will not delete the old keys;
|
|
||||||
you have to remove them manually.
|
|
||||||
.It dump [reachable] nodes
|
|
||||||
Dump a list of all known nodes in the VPN.
|
|
||||||
If the keyword reachable is used, only lists reachable nodes.
|
|
||||||
.It dump edges
|
|
||||||
Dump a list of all known connections in the VPN.
|
|
||||||
.It dump subnets
|
|
||||||
Dump a list of all known subnets in the VPN.
|
|
||||||
.It dump connections
|
|
||||||
Dump a list of all meta connections with ourself.
|
|
||||||
.It dump graph | digraph
|
|
||||||
Dump a graph of the VPN in
|
|
||||||
.Xr dotty 1
|
|
||||||
format.
|
|
||||||
Nodes are colored according to their reachability:
|
|
||||||
red nodes are unreachable, orange nodes are indirectly reachable, green nodes are directly reachable.
|
|
||||||
Black nodes are either directly or indirectly reachable, but direct reachability has not been tried yet.
|
|
||||||
.It dump invitations
|
|
||||||
Dump a list of outstanding invitations.
|
|
||||||
The filename of the invitation, as well as the name of the node that is being invited is shown for each invitation.
|
|
||||||
.It info Ar node | subnet | address
|
|
||||||
Show information about a particular node, subnet or address.
|
|
||||||
If an address is given, any matching subnet will be shown.
|
|
||||||
.It purge
|
|
||||||
Purges all information remembered about unreachable nodes.
|
|
||||||
.It debug Ar N
|
|
||||||
Sets debug level to
|
|
||||||
.Ar N .
|
|
||||||
.It log Op Ar N
|
|
||||||
Capture log messages from a running tinc daemon.
|
|
||||||
An optional debug level can be given that will be applied only for log messages sent to
|
|
||||||
.Nm tinc .
|
|
||||||
.It retry
|
|
||||||
Forces
|
|
||||||
.Xr tincd 8
|
|
||||||
to try to connect to all uplinks immediately.
|
|
||||||
Usually
|
|
||||||
.Xr tincd 8
|
|
||||||
attempts to do this itself,
|
|
||||||
but increases the time it waits between the attempts each time it failed,
|
|
||||||
and if
|
|
||||||
.Xr tincd 8
|
|
||||||
didn't succeed to connect to an uplink the first time after it started,
|
|
||||||
it defaults to the maximum time of 15 minutes.
|
|
||||||
.It disconnect Ar NODE
|
|
||||||
Closes the meta connection with the given
|
|
||||||
.Ar NODE .
|
|
||||||
.It top
|
|
||||||
If
|
|
||||||
.Nm
|
|
||||||
is compiled with libcurses support, this will display live traffic statistics
|
|
||||||
for all the known nodes, similar to the UNIX
|
|
||||||
.Xr top 1
|
|
||||||
command.
|
|
||||||
See below for more information.
|
|
||||||
.It pcap
|
|
||||||
Dump VPN traffic going through the local tinc node in
|
|
||||||
.Xr pcap-savefile 5
|
|
||||||
format to standard output,
|
|
||||||
from where it can be redirected to a file or piped through a program that can parse it directly,
|
|
||||||
such as
|
|
||||||
.Xr tcpdump 8 .
|
|
||||||
.It network Op Ar netname
|
|
||||||
If
|
|
||||||
.Ar netname
|
|
||||||
is given, switch to that network.
|
|
||||||
Otherwise, display a list of all networks for which configuration files exist.
|
|
||||||
.It fsck
|
|
||||||
This will check the configuration files for possible problems,
|
|
||||||
such as unsafe file permissions, missing executable bit on script,
|
|
||||||
unknown and obsolete configuration variables, wrong public and/or private keys, and so on.
|
|
||||||
.Pp
|
|
||||||
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 successful,
|
|
||||||
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:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
tinc -n vpn dump graph | circo -Txlib
|
|
||||||
tinc -n vpn pcap | tcpdump -r -
|
|
||||||
tinc -n vpn top
|
|
||||||
.Pp
|
|
||||||
.Ed
|
|
||||||
Examples of changing the configuration using
|
|
||||||
.Nm :
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
tinc -n vpn init foo
|
|
||||||
tinc -n vpn add Subnet 192.168.1.0/24
|
|
||||||
tinc -n vpn add bar.Address bar.example.com
|
|
||||||
tinc -n vpn add ConnectTo bar
|
|
||||||
tinc -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
|
|
||||||
.Ed
|
|
||||||
.Sh TOP
|
|
||||||
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
|
|
||||||
It displays a list of all the known nodes in the left-most column,
|
|
||||||
and the amount of bytes and packets read from and sent to each node in the other columns.
|
|
||||||
By default, the information is updated every second.
|
|
||||||
The behaviour of the top command can be changed using the following keys:
|
|
||||||
.Bl -tag
|
|
||||||
.It Ic s
|
|
||||||
Change the interval between updates.
|
|
||||||
After pressing the
|
|
||||||
.Ic s
|
|
||||||
key, enter the desired interval in seconds, followed by enter.
|
|
||||||
Fractional seconds are honored.
|
|
||||||
Intervals lower than 0.1 seconds are not allowed.
|
|
||||||
.It Ic c
|
|
||||||
Toggle between displaying current traffic rates (in packets and bytes per second)
|
|
||||||
and cumulative traffic (total packets and bytes since the tinc daemon started).
|
|
||||||
.It Ic n
|
|
||||||
Sort the list of nodes by name.
|
|
||||||
.It Ic i
|
|
||||||
Sort the list of nodes by incoming amount of bytes.
|
|
||||||
.It Ic I
|
|
||||||
Sort the list of nodes by incoming amount of packets.
|
|
||||||
.It Ic o
|
|
||||||
Sort the list of nodes by outgoing amount of bytes.
|
|
||||||
.It Ic O
|
|
||||||
Sort the list of nodes by outgoing amount of packets.
|
|
||||||
.It Ic t
|
|
||||||
Sort the list of nodes by sum of incoming and outgoing amount of bytes.
|
|
||||||
.It Ic T
|
|
||||||
Sort the list of nodes by sum of incoming and outgoing amount of packets.
|
|
||||||
.It Ic b
|
|
||||||
Show amount of traffic in bytes.
|
|
||||||
.It Ic k
|
|
||||||
Show amount of traffic in kilobytes.
|
|
||||||
.It Ic M
|
|
||||||
Show amount of traffic in megabytes.
|
|
||||||
.It Ic G
|
|
||||||
Show amount of traffic in gigabytes.
|
|
||||||
.It Ic q
|
|
||||||
Quit.
|
|
||||||
.El
|
|
||||||
.Sh BUGS
|
|
||||||
If you find any bugs, report them to tinc@tinc-vpn.org.
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr tincd 8 ,
|
|
||||||
.Xr tinc.conf 5 ,
|
|
||||||
.Xr dotty 1 ,
|
|
||||||
.Xr pcap-savefile 5 ,
|
|
||||||
.Xr tcpdump 8 ,
|
|
||||||
.Xr top 1 ,
|
|
||||||
.Pa http://www.tinc-vpn.org/ ,
|
|
||||||
.Pa http://www.cabal.org/ .
|
|
||||||
.Pp
|
|
||||||
The full documentation for tinc is maintained as a Texinfo manual.
|
|
||||||
If the info and tinc programs are properly installed at your site,
|
|
||||||
the command
|
|
||||||
.Ic info tinc
|
|
||||||
should give you access to the complete manual.
|
|
||||||
.Pp
|
|
||||||
tinc comes with ABSOLUTELY NO WARRANTY.
|
|
||||||
This is free software, and you are welcome to redistribute it under certain conditions;
|
|
||||||
see the file COPYING for details.
|
|
||||||
.Sh AUTHORS
|
|
||||||
.An "Ivo Timmermans"
|
|
||||||
.An "Guus Sliepen" Aq guus@tinc-vpn.org
|
|
||||||
.Pp
|
|
||||||
And thanks to many others for their contributions to tinc!
|
|
|
@ -1,4 +1,4 @@
|
||||||
.Dd 2017-09-02
|
.Dd 2016-10-29
|
||||||
.Dt TINC.CONF 5
|
.Dt TINC.CONF 5
|
||||||
.\" Manual page created by:
|
.\" Manual page created by:
|
||||||
.\" Ivo Timmermans
|
.\" Ivo Timmermans
|
||||||
|
@ -11,12 +11,20 @@ The files in the
|
||||||
.Pa @sysconfdir@/tinc/
|
.Pa @sysconfdir@/tinc/
|
||||||
directory contain runtime and security information for the tinc daemon.
|
directory contain runtime and security information for the tinc daemon.
|
||||||
.Sh NETWORKS
|
.Sh NETWORKS
|
||||||
To distinguish multiple instances of tinc running on one computer,
|
It is perfectly ok for you to run more than one tinc daemon.
|
||||||
you can use the
|
However, in its default form,
|
||||||
.Fl n
|
you will soon notice that you can't use two different configuration files without the
|
||||||
option to assign a network name to each tinc daemon.
|
.Fl c
|
||||||
|
option.
|
||||||
.Pp
|
.Pp
|
||||||
The effect of this option is that the daemon will set its configuration root to
|
We have thought of another way of dealing with this: network names.
|
||||||
|
This means that you call
|
||||||
|
.Nm
|
||||||
|
with the
|
||||||
|
.Fl n
|
||||||
|
option, which will assign a name to this daemon.
|
||||||
|
.Pp
|
||||||
|
The effect of this is that the daemon will set its configuration root to
|
||||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
|
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
|
||||||
where
|
where
|
||||||
.Ar NETNAME
|
.Ar NETNAME
|
||||||
|
@ -24,14 +32,13 @@ is your argument to the
|
||||||
.Fl n
|
.Fl n
|
||||||
option.
|
option.
|
||||||
You'll notice that messages appear in syslog as coming from
|
You'll notice that messages appear in syslog as coming from
|
||||||
.Nm tincd. Ns Ar NETNAME ,
|
.Nm tincd. Ns Ar NETNAME .
|
||||||
and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name.
|
|
||||||
.Pp
|
.Pp
|
||||||
It is recommended that you use network names even if you run only one instance of tinc.
|
However, it is not strictly necessary that you call tinc with the
|
||||||
However, you can choose not to use the
|
|
||||||
.Fl n
|
.Fl n
|
||||||
option.
|
option.
|
||||||
In this case, the network name would just be empty, and
|
In this case, the network name would just be empty,
|
||||||
|
and it will be used as such.
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
now looks for files in
|
now looks for files in
|
||||||
.Pa @sysconfdir@/tinc/ ,
|
.Pa @sysconfdir@/tinc/ ,
|
||||||
|
@ -41,6 +48,11 @@ the configuration file should be
|
||||||
.Pa @sysconfdir@/tinc/tinc.conf ,
|
.Pa @sysconfdir@/tinc/tinc.conf ,
|
||||||
and the host configuration files are now expected to be in
|
and the host configuration files are now expected to be in
|
||||||
.Pa @sysconfdir@/tinc/hosts/ .
|
.Pa @sysconfdir@/tinc/hosts/ .
|
||||||
|
.Pp
|
||||||
|
But it is highly recommended that you use this feature of
|
||||||
|
.Nm tinc ,
|
||||||
|
because it will be so much clearer whom your daemon talks to.
|
||||||
|
Hence, we will assume that you use it.
|
||||||
.Sh NAMES
|
.Sh NAMES
|
||||||
Each tinc daemon must 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 will be used by other tinc daemons for identification.
|
||||||
|
@ -51,34 +63,24 @@ file.
|
||||||
To make things easy,
|
To make things easy,
|
||||||
choose something that will give unique and easy to remember names to your tinc daemon(s).
|
choose something that will give unique and easy to remember names to your tinc daemon(s).
|
||||||
You could try things like hostnames, owner surnames or location names.
|
You could try things like hostnames, owner surnames or location names.
|
||||||
However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-9) and underscores (_) in the name.
|
|
||||||
.Sh INITIAL CONFIGURATION
|
|
||||||
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
.Nm tinc Fl n Ar NETNAME Li init Ar NAME
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
You can further change the configuration as needed either by manually editing the configuration files,
|
|
||||||
or by using
|
|
||||||
.Xr tinc 8 .
|
|
||||||
.Sh PUBLIC/PRIVATE KEYS
|
.Sh PUBLIC/PRIVATE KEYS
|
||||||
The
|
You should use
|
||||||
.Nm tinc Li init
|
.Ic tincd -K
|
||||||
command will have generated both RSA and Ed25519 public/private keypairs.
|
to generate public/private keypairs.
|
||||||
The private keys should be stored in files named
|
It will generate two keys.
|
||||||
.Pa rsa_key.priv
|
The private key should be stored in a separate file
|
||||||
and
|
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv
|
||||||
.Pa ed25519_key.priv
|
\-\- where
|
||||||
in the directory
|
.Ar NETNAME
|
||||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /
|
stands for the network (see
|
||||||
The public keys should be stored in the host configuration file
|
.Sx NETWORKS )
|
||||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME .
|
above.
|
||||||
The RSA keys are used for backwards compatibility with tinc version 1.0.
|
The public key should be stored in the host configuration file
|
||||||
If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files,
|
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME
|
||||||
but you will need to create Ed25519 keys using the following command:
|
\-\- where
|
||||||
.Bd -literal -offset indent
|
.Va NAME
|
||||||
.Nm tinc Fl n Ar NETNAME Li generate-ed25519-keys
|
stands for the name of the local tinc daemon (see
|
||||||
.Ed
|
.Sx NAMES ) .
|
||||||
.Sh SERVER CONFIGURATION
|
.Sh SERVER CONFIGURATION
|
||||||
The server configuration of the daemon is done in the file
|
The server configuration of the daemon is done in the file
|
||||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf .
|
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf .
|
||||||
|
@ -101,10 +103,6 @@ Although all configuration options for the local host listed in this document ca
|
||||||
it is recommended to put host specific configuration options in the host configuration file,
|
it is recommended to put host specific configuration options in the host configuration file,
|
||||||
as this makes it easy to exchange with other nodes.
|
as this makes it easy to exchange with other nodes.
|
||||||
.Pp
|
.Pp
|
||||||
You can edit the config file manually, but it is recommended that you use
|
|
||||||
.Xr tinc 8
|
|
||||||
to change configuration variables for you.
|
|
||||||
.Pp
|
|
||||||
Here are all valid variables, listed in alphabetical order.
|
Here are all valid variables, listed in alphabetical order.
|
||||||
The default value is given between parentheses.
|
The default value is given between parentheses.
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
|
@ -114,24 +112,26 @@ If
|
||||||
.Qq any
|
.Qq any
|
||||||
is selected, then depending on the operating system both IPv4 and IPv6 or just
|
is selected, then depending on the operating system both IPv4 and IPv6 or just
|
||||||
IPv6 listening sockets will be created.
|
IPv6 listening sockets will be created.
|
||||||
.It Va AutoConnect Li = yes | no Po yes
|
.It Va BindToAddress Li = Ar address Oo Ar port Oc Bq experimental
|
||||||
If set to yes,
|
If your computer has more than one IPv4 or IPv6 address,
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
will automatically set up meta connections to other nodes,
|
will by default listen on all of them for incoming connections.
|
||||||
without requiring
|
Multiple
|
||||||
.Va ConnectTo
|
|
||||||
variables.
|
|
||||||
.Pp
|
|
||||||
Note: it is not possible to connect to nodes using zero (system-assigned) ports in this way.
|
|
||||||
.It Va BindToAddress Li = Ar address Op Ar port
|
|
||||||
This is the same as
|
|
||||||
.Va ListenAddress ,
|
|
||||||
however the address given with the
|
|
||||||
.Va BindToAddress
|
.Va BindToAddress
|
||||||
option will also be used for outgoing connections. This is useful if your
|
variables may be specified,
|
||||||
computer has more than one IPv4 or IPv6 address, and you want
|
in which case listening sockets for each specified address are made.
|
||||||
.Nm tinc
|
.Pp
|
||||||
to only use a specific one for outgoing packets.
|
If no
|
||||||
|
.Ar port
|
||||||
|
is specified, the socket will be bound to the port specified by the
|
||||||
|
.Va Port
|
||||||
|
option, or to port 655 if neither is given.
|
||||||
|
To only bind to a specific port but not to a specific address, use
|
||||||
|
.Li *
|
||||||
|
for the
|
||||||
|
.Ar address .
|
||||||
|
.Pp
|
||||||
|
This option may not work on all platforms.
|
||||||
.It Va BindToInterface Li = Ar interface Bq experimental
|
.It Va BindToInterface Li = Ar interface Bq experimental
|
||||||
If your computer has more than one network interface,
|
If your computer has more than one network interface,
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
|
@ -157,13 +157,6 @@ Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||||
Broadcast packets received from other nodes are never forwarded.
|
Broadcast packets received from other nodes are never forwarded.
|
||||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||||
.El
|
.El
|
||||||
.It Va BroadcastSubnet Li = Ar address Ns Op Li / Ns Ar prefixlength
|
|
||||||
Declares a broadcast subnet. Any packet with a destination address falling into such a subnet will be routed as a broadcast (provided all nodes have it declared).
|
|
||||||
This is most useful to declare subnet broadcast addresses (e.g. 10.42.255.255), otherwise
|
|
||||||
.Nm tinc
|
|
||||||
won't know what to do with them.
|
|
||||||
.Pp
|
|
||||||
Note that global broadcast addresses (MAC ff:ff:ff:ff:ff:ff, IPv4 255.255.255.255), as well as multicast space (IPv4 224.0.0.0/4, IPv6 ff00::/8) are always considered broadcast addresses and don't need to be declared.
|
|
||||||
.It Va ConnectTo Li = Ar name
|
.It Va ConnectTo Li = Ar name
|
||||||
Specifies which other tinc daemon to connect to on startup.
|
Specifies which other tinc daemon to connect to on startup.
|
||||||
Multiple
|
Multiple
|
||||||
|
@ -176,9 +169,7 @@ The names should be known to this tinc daemon
|
||||||
line).
|
line).
|
||||||
.Pp
|
.Pp
|
||||||
If you don't specify a host with
|
If you don't specify a host with
|
||||||
.Va ConnectTo
|
.Va ConnectTo ,
|
||||||
and have disabled
|
|
||||||
.Va AutoConnect ,
|
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
won't try to connect to other daemons at all,
|
won't try to connect to other daemons at all,
|
||||||
and will instead just listen for incoming connections.
|
and will instead just listen for incoming connections.
|
||||||
|
@ -202,13 +193,6 @@ instead of
|
||||||
.Va Device .
|
.Va Device .
|
||||||
The info pages of the tinc package contain more information
|
The info pages of the tinc package contain more information
|
||||||
about configuring the virtual network device.
|
about configuring the virtual network device.
|
||||||
.It Va DeviceStandby Li = yes | no Po no Pc
|
|
||||||
When disabled,
|
|
||||||
.Nm tinc
|
|
||||||
calls tinc-up on startup, and tinc-down on shutdown. When enabled,
|
|
||||||
.Nm tinc
|
|
||||||
will only call tinc-up when at least one node is reachable, and will call tinc-down as soon as no nodes are reachable.
|
|
||||||
On Windows, this also determines when the virtual network interface "cable" is "plugged".
|
|
||||||
.It Va DeviceType Li = Ar type Pq platform dependent
|
.It Va DeviceType Li = Ar type Pq platform dependent
|
||||||
The type of the virtual network device.
|
The type of the virtual network device.
|
||||||
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
|
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
|
||||||
|
@ -234,10 +218,6 @@ Do NOT connect multiple
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
daemons to the same multicast address, this will very likely cause routing loops.
|
daemons to the same multicast address, this will very likely cause routing loops.
|
||||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||||
.It fd
|
|
||||||
Use a file descriptor.
|
|
||||||
All packets are read from this interface.
|
|
||||||
Packets received for the local node are written to it.
|
|
||||||
.It uml Pq not compiled in by default
|
.It uml Pq not compiled in by default
|
||||||
Create a UNIX socket with the filename specified by
|
Create a UNIX socket with the filename specified by
|
||||||
.Va Device ,
|
.Va Device ,
|
||||||
|
@ -284,17 +264,6 @@ When this option is enabled, packets that cannot be sent directly to the destina
|
||||||
but which would have to be forwarded by an intermediate node, are dropped instead.
|
but which would have to be forwarded by an intermediate node, are dropped instead.
|
||||||
When combined with the IndirectData option,
|
When combined with the IndirectData option,
|
||||||
packets for nodes for which we do not have a meta connection with are also dropped.
|
packets for nodes for which we do not have a meta connection with are also dropped.
|
||||||
.It Va Ed25519PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /ed25519_key.priv Pc
|
|
||||||
The file in which the private Ed25519 key of this tinc daemon resides.
|
|
||||||
This is only used if
|
|
||||||
.Va ExperimentalProtocol
|
|
||||||
is enabled.
|
|
||||||
.It Va ExperimentalProtocol Li = yes | no Pq yes
|
|
||||||
When this option is enabled, the SPTPS protocol will be used when connecting to nodes that also support it.
|
|
||||||
Ephemeral ECDH will be used for key exchanges,
|
|
||||||
and Ed25519 will be used instead of RSA for authentication.
|
|
||||||
When enabled, an Ed25519 key must have been generated before with
|
|
||||||
.Nm tinc generate-ed25519-keys .
|
|
||||||
.It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
|
.It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
|
||||||
This option selects the way indirect packets are forwarded.
|
This option selects the way indirect packets are forwarded.
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
|
@ -306,16 +275,22 @@ Incoming packets that are meant for another node are forwarded by tinc internall
|
||||||
.Pp
|
.Pp
|
||||||
This is the default mode, and unless you really know you need another forwarding mode, don't change it.
|
This is the default mode, and unless you really know you need another forwarding mode, don't change it.
|
||||||
.It kernel
|
.It kernel
|
||||||
Incoming packets using the legacy protocol are always sent to the TUN/TAP device,
|
Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node.
|
||||||
even if the packets are not for the local node.
|
|
||||||
This is less efficient, but allows the kernel to apply its routing and firewall rules on them,
|
This is less efficient, but allows the kernel to apply its routing and firewall rules on them,
|
||||||
and can also help debugging.
|
and can also help debugging.
|
||||||
Incoming packets using the SPTPS protocol are dropped, since they are end-to-end encrypted.
|
|
||||||
.El
|
.El
|
||||||
.It Va FWMark Li = Ar value Po 0 Pc Bq experimental
|
.It Va GraphDumpFile Li = Ar filename Bq experimental
|
||||||
When set to a non-zero value, all TCP and UDP sockets created by tinc will use the given value as the firewall mark.
|
If this option is present,
|
||||||
This can be used for mark-based routing or for packet filtering.
|
.Nm tinc
|
||||||
This option is currently only supported on Linux.
|
will dump the current network graph to the file
|
||||||
|
.Ar filename
|
||||||
|
every minute, unless there were no changes to the graph.
|
||||||
|
The file is in a format that can be read by graphviz tools.
|
||||||
|
If
|
||||||
|
.Ar filename
|
||||||
|
starts with a pipe symbol |,
|
||||||
|
then the rest of the filename is interpreted as a shell command
|
||||||
|
that is executed, the graph is then sent to stdin.
|
||||||
.It Va Hostnames Li = yes | no Pq no
|
.It Va Hostnames Li = yes | no Pq no
|
||||||
This option selects whether IP addresses (both real and on the VPN) should
|
This option selects whether IP addresses (both real and on the VPN) should
|
||||||
be resolved. Since DNS lookups are blocking, it might affect tinc's
|
be resolved. Since DNS lookups are blocking, it might affect tinc's
|
||||||
|
@ -333,40 +308,11 @@ Under Windows, this variable is used to select which network interface will be u
|
||||||
If you specified a
|
If you specified a
|
||||||
.Va Device ,
|
.Va Device ,
|
||||||
this variable is almost always already correctly set.
|
this variable is almost always already correctly set.
|
||||||
.It Va InvitationExpire Li = Ar seconds Pq 604800
|
|
||||||
This option controls the period invitations are valid.
|
|
||||||
.It Va KeyExpire Li = Ar seconds Pq 3600
|
.It Va KeyExpire Li = Ar seconds Pq 3600
|
||||||
This option controls the period the encryption keys used to encrypt the data are valid.
|
This option controls the period the encryption keys used to encrypt the data are valid.
|
||||||
It is common practice to change keys at regular intervals to make it even harder for crackers,
|
It is common practice to change keys at regular intervals to make it even harder for crackers,
|
||||||
even though it is thought to be nearly impossible to crack a single key.
|
even though it is thought to be nearly impossible to crack a single key.
|
||||||
.It Va ListenAddress Li = Ar address Op Ar port
|
.It Va LocalDiscovery Li = yes | no Po no Pc Bq experimental
|
||||||
If your computer has more than one IPv4 or IPv6 address,
|
|
||||||
.Nm tinc
|
|
||||||
will by default listen on all of them for incoming connections.
|
|
||||||
This option can be used to restrict which addresses tinc listens on.
|
|
||||||
Multiple
|
|
||||||
.Va ListenAddress
|
|
||||||
variables may be specified,
|
|
||||||
in which case listening sockets for each specified address are made.
|
|
||||||
.Pp
|
|
||||||
If no
|
|
||||||
.Ar port
|
|
||||||
is specified, the socket will listen on the port specified by the
|
|
||||||
.Va Port
|
|
||||||
option, or to port 655 if neither is given.
|
|
||||||
To only listen on a specific port but not on a specific address, use
|
|
||||||
.Li *
|
|
||||||
for the
|
|
||||||
.Ar address .
|
|
||||||
.Pp
|
|
||||||
If
|
|
||||||
.Ar port
|
|
||||||
is set to zero, it will be randomly assigned by the system. This is useful to randomize source ports of UDP packets, which can improve UDP hole punching reliability. In this case it is recommended to set
|
|
||||||
.Va AddressFamily
|
|
||||||
as well, otherwise
|
|
||||||
.Nm tinc
|
|
||||||
will assign different ports to different address families but other nodes can only know of one.
|
|
||||||
.It Va LocalDiscovery Li = yes | no Pq yes
|
|
||||||
When enabled,
|
When enabled,
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
will try to detect peers that are on the same local network.
|
will try to detect peers that are on the same local network.
|
||||||
|
@ -374,20 +320,14 @@ This will allow direct communication using LAN addresses, even if both peers are
|
||||||
and they only ConnectTo a third node outside the NAT,
|
and they only ConnectTo a third node outside the NAT,
|
||||||
which normally would prevent the peers from learning each other's LAN address.
|
which normally would prevent the peers from learning each other's LAN address.
|
||||||
.Pp
|
.Pp
|
||||||
Currently, local discovery is implemented by sending some packets to the local address of the node during UDP discovery. This will not work with old nodes that don't transmit their local address.
|
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
|
||||||
.It Va LogLevel Li = level Pq 0
|
This feature may not work in all possible situations.
|
||||||
This option controls the verbosity of the logging. The higher the debug level, the more messages it will log.
|
|
||||||
.It Va MACExpire Li = Ar seconds Pq 600
|
.It Va MACExpire Li = Ar seconds Pq 600
|
||||||
This option controls the amount of time MAC addresses are kept before they are removed.
|
This option controls the amount of time MAC addresses are kept before they are removed.
|
||||||
This only has effect when
|
This only has effect when
|
||||||
.Va Mode
|
.Va Mode
|
||||||
is set to
|
is set to
|
||||||
.Qq switch .
|
.Qq switch .
|
||||||
.It Va MaxConnectionBurst Li = Ar count Pq 100
|
|
||||||
This option controls how many connections tinc accepts in quick succession.
|
|
||||||
If there are more connections than the given number in a short time interval,
|
|
||||||
tinc will reduce the number of accepted connections to only one per second,
|
|
||||||
until the burst has passed.
|
|
||||||
.It Va MaxTimeout Li = Ar seconds Pq 900
|
.It Va MaxTimeout Li = Ar seconds Pq 900
|
||||||
This is the maximum delay before trying to reconnect to other tinc daemons.
|
This is the maximum delay before trying to reconnect to other tinc daemons.
|
||||||
.It Va Mode Li = router | switch | hub Pq router
|
.It Va Mode Li = router | switch | hub Pq router
|
||||||
|
@ -397,7 +337,7 @@ This option selects the way packets are routed to other daemons.
|
||||||
In this mode
|
In this mode
|
||||||
.Va Subnet
|
.Va Subnet
|
||||||
variables in the host configuration files will be used to form a routing table.
|
variables in the host configuration files will be used to form a routing table.
|
||||||
Only packets of routable protocols (IPv4 and IPv6) are supported in this mode.
|
Only unicast packets of routable protocols (IPv4 and IPv6) are supported in this mode.
|
||||||
.Pp
|
.Pp
|
||||||
This is the default mode, and unless you really know you need another mode, don't change it.
|
This is the default mode, and unless you really know you need another mode, don't change it.
|
||||||
.It switch
|
.It switch
|
||||||
|
@ -415,8 +355,7 @@ while no routing table is managed.
|
||||||
.It Va Name Li = Ar name Bq required
|
.It Va Name Li = Ar name Bq required
|
||||||
This is the name which identifies this tinc daemon.
|
This is the name which identifies this tinc daemon.
|
||||||
It must be unique for the virtual private network this daemon will connect to.
|
It must be unique for the virtual private network this daemon will connect to.
|
||||||
.Va Name
|
The Name may only consist of alphanumeric and underscore characters.
|
||||||
may only consist of alphanumeric and underscore characters (a-z, A-Z, 0-9 and _), and is case sensitive.
|
|
||||||
If
|
If
|
||||||
.Va Name
|
.Va Name
|
||||||
starts with a
|
starts with a
|
||||||
|
@ -446,9 +385,7 @@ It will allow this tinc daemon to authenticate itself to other daemons.
|
||||||
.It Va PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv Pc
|
.It Va PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv Pc
|
||||||
The file in which the private RSA key of this tinc daemon resides.
|
The file in which the private RSA key of this tinc daemon resides.
|
||||||
.It Va ProcessPriority Li = low | normal | high
|
.It Va ProcessPriority Li = low | normal | high
|
||||||
When this option is used the priority of the
|
When this option is used the priority of the tincd process will be adjusted.
|
||||||
.Nm tincd
|
|
||||||
process will be adjusted.
|
|
||||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||||
.It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental
|
.It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental
|
||||||
Use a proxy when making outgoing connections.
|
Use a proxy when making outgoing connections.
|
||||||
|
@ -482,13 +419,13 @@ and
|
||||||
.Ev REMOTEPORT
|
.Ev REMOTEPORT
|
||||||
are available.
|
are available.
|
||||||
.El
|
.El
|
||||||
.It Va ReplayWindow Li = Ar bytes Pq 32
|
.It Va ReplayWindow Li = Ar bytes Pq 16
|
||||||
This is the size of the replay tracking window for each remote node, in bytes.
|
This is the size of the replay tracking window for each remote node, in bytes.
|
||||||
The window is a bitfield which tracks 1 packet per bit, so for example
|
The window is a bitfield which tracks 1 packet per bit, so for example
|
||||||
the default setting of 32 will track up to 256 packets in the window. In high
|
the default setting of 16 will track up to 128 packets in the window. In high
|
||||||
bandwidth scenarios, setting this to a higher value can reduce packet loss from
|
bandwidth scenarios, setting this to a higher value can reduce packet loss from
|
||||||
the interaction of replay tracking with underlying real packet loss and/or
|
the interaction of replay tracking with underlying real packet loss and/or
|
||||||
reordering. Setting this to zero will disable replay tracking completely and
|
reordering. Setting this to zero will disable replay tracking completely and
|
||||||
pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
|
pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
|
||||||
traffic.
|
traffic.
|
||||||
.It Va StrictSubnets Li = yes | no Po no Pc Bq experimental
|
.It Va StrictSubnets Li = yes | no Po no Pc Bq experimental
|
||||||
|
@ -503,42 +440,12 @@ and will only allow connections with nodes for which host config files are prese
|
||||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
||||||
directory.
|
directory.
|
||||||
Setting this options also implicitly sets StrictSubnets.
|
Setting this options also implicitly sets StrictSubnets.
|
||||||
.It Va UDPDiscovery Li = yes | no Po yes Pc
|
.It Va UDPRcvBuf Li = Ar bytes Pq OS default
|
||||||
When this option is enabled tinc will try to establish UDP connectivity to nodes,
|
|
||||||
using TCP while it determines if a node is reachable over UDP. If it is disabled,
|
|
||||||
tinc always assumes a node is reachable over UDP.
|
|
||||||
Note that tinc will never use UDP with nodes that have
|
|
||||||
.Va TCPOnly
|
|
||||||
enabled.
|
|
||||||
.It Va UDPDiscoveryKeepaliveInterval Li = Ar seconds Pq 9
|
|
||||||
The minimum amount of time between sending UDP ping datagrams to check UDP connectivity once it has been established.
|
|
||||||
Note that these pings are large, since they are used to verify link MTU as well.
|
|
||||||
.It Va UDPDiscoveryInterval Li = Ar seconds Pq 2
|
|
||||||
The minimum amount of time between sending UDP ping datagrams to try to establish UDP connectivity.
|
|
||||||
.It Va UDPDiscoveryTimeout Li = Ar seconds Pq 30
|
|
||||||
If tinc doesn't receive any UDP ping replies over the specified interval,
|
|
||||||
it will assume UDP communication is broken and will fall back to TCP.
|
|
||||||
.It Va UDPInfoInterval Li = Ar seconds Pq 5
|
|
||||||
The minimum amount of time between sending periodic updates about UDP addresses, which are mostly useful for UDP hole punching.
|
|
||||||
.It Va UDPRcvBuf Li = Ar bytes Pq 1048576
|
|
||||||
Sets the socket receive buffer size for the UDP socket, in bytes.
|
Sets the socket receive buffer size for the UDP socket, in bytes.
|
||||||
If set to zero, the default buffer size will be used by the operating system.
|
If unset, the default buffer size will be used by the operating system.
|
||||||
Note: this setting can have a significant impact on performance, especially raw throughput.
|
.It Va UDPSndBuf Li = Ar bytes Pq OS default
|
||||||
.It Va UDPSndBuf Li = Ar bytes Pq 1048576
|
|
||||||
Sets the socket send buffer size for the UDP socket, in bytes.
|
Sets the socket send buffer size for the UDP socket, in bytes.
|
||||||
If set to zero, the default buffer size will be used by the operating system.
|
If unset, the default buffer size will be used by the operating system.
|
||||||
Note: this setting can have a significant impact on performance, especially raw throughput.
|
|
||||||
.It Va UPnP Li = yes | udponly | no Po no Pc
|
|
||||||
If this option is enabled then tinc will search for UPnP-IGD devices on the local network.
|
|
||||||
It will then create and maintain port mappings for tinc's listening TCP and UDP ports.
|
|
||||||
If set to "udponly", tinc will only create a mapping for its UDP (data) port, not for its TCP (metaconnection) port.
|
|
||||||
Note that tinc must have been built with miniupnpc support for this feature to be available.
|
|
||||||
Furthermore, be advised that enabling this can have security implications, because the miniupnpc library that
|
|
||||||
tinc uses might not be well-hardened with regard to malicious UPnP replies.
|
|
||||||
.It Va UPnPDiscoverWait Li = Ar seconds Pq 5
|
|
||||||
The amount of time to wait for replies when probing the local network for UPnP devices.
|
|
||||||
.It Va UPnPRefreshPeriod Li = Ar seconds Pq 60
|
|
||||||
How often tinc will re-add the port mapping, in case it gets reset on the UPnP device. This also controls the duration of the port mapping itself, which will be set to twice that duration.
|
|
||||||
.El
|
.El
|
||||||
.Sh HOST CONFIGURATION FILES
|
.Sh HOST CONFIGURATION FILES
|
||||||
The host configuration files contain all information needed
|
The host configuration files contain all information needed
|
||||||
|
@ -561,15 +468,13 @@ Multiple
|
||||||
.Va Address
|
.Va Address
|
||||||
variables can be specified, in which case each address will be tried until a working
|
variables can be specified, in which case each address will be tried until a working
|
||||||
connection has been established.
|
connection has been established.
|
||||||
.It Va Cipher Li = Ar cipher Pq blowfish
|
.It Va Cipher Li = Ar cipher Pq aes-256-cbc
|
||||||
The symmetric cipher algorithm used to encrypt UDP packets.
|
The symmetric cipher algorithm used to encrypt UDP packets.
|
||||||
Any cipher supported by LibreSSL or OpenSSL is recognised.
|
Any cipher supported by LibreSSL or OpenSSL is recognised.
|
||||||
Furthermore, specifying
|
Furthermore, specifying
|
||||||
.Qq none
|
.Qq none
|
||||||
will turn off packet encryption.
|
will turn off packet encryption.
|
||||||
It is best to use only those ciphers which support CBC mode.
|
It is best to use only those ciphers which support CBC mode.
|
||||||
This option has no effect for connections between nodes using
|
|
||||||
.Va ExperimentalProtocol .
|
|
||||||
.It Va ClampMSS Li = yes | no Pq yes
|
.It Va ClampMSS Li = yes | no Pq yes
|
||||||
This option specifies whether tinc should clamp the maximum segment size (MSS)
|
This option specifies whether tinc should clamp the maximum segment size (MSS)
|
||||||
of TCP packets to the path MTU. This helps in situations where ICMP
|
of TCP packets to the path MTU. This helps in situations where ICMP
|
||||||
|
@ -578,14 +483,12 @@ Fragmentation Needed or Packet too Big messages are dropped by firewalls.
|
||||||
This option sets the level of compression used for UDP packets.
|
This option sets the level of compression used for UDP packets.
|
||||||
Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
|
Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
|
||||||
10 (fast lzo) and 11 (best lzo).
|
10 (fast lzo) and 11 (best lzo).
|
||||||
.It Va Digest Li = Ar digest Pq sha1
|
.It Va Digest Li = Ar digest Pq sha256
|
||||||
The digest algorithm used to authenticate UDP packets.
|
The digest algorithm used to authenticate UDP packets.
|
||||||
Any digest supported by LibreSSL or OpenSSL is recognised.
|
Any digest supported by LibreSSL or OpenSSL is recognised.
|
||||||
Furthermore, specifying
|
Furthermore, specifying
|
||||||
.Qq none
|
.Qq none
|
||||||
will turn off packet authentication.
|
will turn off packet authentication.
|
||||||
This option has no effect for connections between nodes using
|
|
||||||
.Va ExperimentalProtocol .
|
|
||||||
.It Va IndirectData Li = yes | no Pq no
|
.It Va IndirectData Li = yes | no Pq no
|
||||||
When set to yes, only nodes which already have a meta connection to you
|
When set to yes, only nodes which already have a meta connection to you
|
||||||
will try to establish direct communication with you.
|
will try to establish direct communication with you.
|
||||||
|
@ -595,28 +498,16 @@ The length of the message authentication code used to authenticate UDP packets.
|
||||||
Can be anything from
|
Can be anything from
|
||||||
.Qq 0
|
.Qq 0
|
||||||
up to the length of the digest produced by the digest algorithm.
|
up to the length of the digest produced by the digest algorithm.
|
||||||
This option has no effect for connections between nodes using
|
|
||||||
.Va ExperimentalProtocol .
|
|
||||||
.It Va PMTU Li = Ar mtu Po 1514 Pc
|
.It Va PMTU Li = Ar mtu Po 1514 Pc
|
||||||
This option controls the initial path MTU to this node.
|
This option controls the initial path MTU to this node.
|
||||||
.It Va PMTUDiscovery Li = yes | no Po yes Pc
|
.It Va PMTUDiscovery Li = yes | no Po yes Pc
|
||||||
When this option is enabled, tinc will try to discover the path MTU to this node.
|
When this option is enabled, tinc will try to discover the path MTU to this node.
|
||||||
After the path MTU has been discovered, it will be enforced on the VPN.
|
After the path MTU has been discovered, it will be enforced on the VPN.
|
||||||
.It Va MTUInfoInterval Li = Ar seconds Pq 5
|
|
||||||
The minimum amount of time between sending periodic updates about relay path MTU. Useful for quickly determining MTU to indirect nodes.
|
|
||||||
.It Va Port Li = Ar port Pq 655
|
.It Va Port Li = Ar port Pq 655
|
||||||
The port number on which this tinc daemon is listening for incoming connections,
|
The port number on which this tinc daemon is listening for incoming connections,
|
||||||
which is used if no port number is specified in an
|
which is used if no port number is specified in an
|
||||||
.Va Address
|
.Va Address
|
||||||
statement.
|
statement.
|
||||||
.Pp
|
|
||||||
If this is set to zero, the port will be randomly assigned by the system. This is useful to randomize source ports of UDP packets, which can improve UDP hole punching reliability. When setting
|
|
||||||
.Va Port
|
|
||||||
to zero it is recommended to set
|
|
||||||
.Va AddressFamily
|
|
||||||
as well, otherwise
|
|
||||||
.Nm tinc
|
|
||||||
will assign different ports to different address families but other nodes can only know of one.
|
|
||||||
.It Va PublicKey Li = Ar key Bq obsolete
|
.It Va PublicKey Li = Ar key Bq obsolete
|
||||||
The public RSA key of this tinc daemon.
|
The public RSA key of this tinc daemon.
|
||||||
It will be used to cryptographically verify it's identity and to set up a secure connection.
|
It will be used to cryptographically verify it's identity and to set up a secure connection.
|
||||||
|
@ -651,7 +542,7 @@ IPv6 subnets are notated like fec0:0:0:1::/64.
|
||||||
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
||||||
.Pp
|
.Pp
|
||||||
A Subnet can be given a weight to indicate its priority over identical Subnets
|
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
|
owned by different nodes. The default weight is 10. Lower values indicate
|
||||||
higher priority. Packets will be sent to the node with the highest priority,
|
higher priority. Packets will be sent to the node with the highest priority,
|
||||||
unless that node is not reachable, in which case the node with the next highest
|
unless that node is not reachable, in which case the node with the next highest
|
||||||
priority will be tried, and so on.
|
priority will be tried, and so on.
|
||||||
|
@ -665,12 +556,6 @@ Setting this options also implicitly sets IndirectData.
|
||||||
.Pp
|
.Pp
|
||||||
Since version 1.0.10, tinc will automatically detect whether communication via
|
Since version 1.0.10, tinc will automatically detect whether communication via
|
||||||
UDP is possible or not.
|
UDP is possible or not.
|
||||||
.It Va Weight Li = Ar weight
|
|
||||||
If this variable is set, it overrides the weight given to connections made with
|
|
||||||
another host. A higher
|
|
||||||
.Ar weight
|
|
||||||
means a lower priority is given to this connection when broadcasting or
|
|
||||||
forwarding packets.
|
|
||||||
.El
|
.El
|
||||||
.Sh SCRIPTS
|
.Sh SCRIPTS
|
||||||
Apart from reading the server and host configuration files,
|
Apart from reading the server and host configuration files,
|
||||||
|
@ -684,23 +569,17 @@ This guarantees that scripts will execute in the exact same order as the events
|
||||||
If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background.
|
If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background.
|
||||||
.Pp
|
.Pp
|
||||||
Under Windows (not Cygwin), the scripts must have the extension
|
Under Windows (not Cygwin), the scripts must have the extension
|
||||||
.Pa .bat
|
.Pa .bat .
|
||||||
or
|
|
||||||
.Pa .cmd .
|
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
||||||
This is the most important script.
|
This is the most important script.
|
||||||
If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device (or when the first node becomes reachable if
|
If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device.
|
||||||
.Va DeviceStandby
|
|
||||||
is used).
|
|
||||||
It should be used to set up the corresponding network interface,
|
It should be used to set up the corresponding network interface,
|
||||||
but can also be used to start other things.
|
but can also be used to start other things.
|
||||||
.Pp
|
.Pp
|
||||||
Under Windows you can use the Network Connections control panel instead of creating this script.
|
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
|
.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
|
This script is started right before the tinc daemon quits.
|
||||||
.Va DeviceStandby
|
|
||||||
is used).
|
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -up
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -up
|
||||||
This script is started when the tinc daemon with name
|
This script is started when the tinc daemon with name
|
||||||
.Ar HOST
|
.Ar HOST
|
||||||
|
@ -718,10 +597,6 @@ This script is started when a Subnet becomes reachable.
|
||||||
The Subnet and the node it belongs to are passed in environment variables.
|
The Subnet and the node it belongs to are passed in environment variables.
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-down
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-down
|
||||||
This script is started when a Subnet becomes unreachable.
|
This script is started when a Subnet becomes unreachable.
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /invitation-created
|
|
||||||
This script is started when a new invitation has been created.
|
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /invitation-accepted
|
|
||||||
This script is started when an invitation has been used.
|
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The scripts are started without command line arguments, but can make use of certain environment variables.
|
The scripts are started without command line arguments, but can make use of certain environment variables.
|
||||||
|
@ -730,8 +605,6 @@ Under UNIX like operating systems the names of environment variables must be pre
|
||||||
in scripts.
|
in scripts.
|
||||||
Under Windows, in
|
Under Windows, in
|
||||||
.Pa .bat
|
.Pa .bat
|
||||||
or
|
|
||||||
.Pa .cmd
|
|
||||||
files, they have to be put between
|
files, they have to be put between
|
||||||
.Li %
|
.Li %
|
||||||
signs.
|
signs.
|
||||||
|
@ -757,14 +630,6 @@ When a host becomes (un)reachable, this is set to the port number it uses for co
|
||||||
When a subnet becomes (un)reachable, this is set to the subnet.
|
When a subnet becomes (un)reachable, this is set to the subnet.
|
||||||
.It Ev WEIGHT
|
.It Ev WEIGHT
|
||||||
When a subnet becomes (un)reachable, this is set to the subnet weight.
|
When a subnet becomes (un)reachable, this is set to the subnet weight.
|
||||||
.It Ev INVITATION_FILE
|
|
||||||
When the
|
|
||||||
.Pa invitation-created
|
|
||||||
script is called, this is set to the file where the invitation details will be stored.
|
|
||||||
.It Ev INVITATION_URL
|
|
||||||
When the
|
|
||||||
.Pa invitation-created
|
|
||||||
script is called, this is set to the invitation URL that has been created.
|
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command
|
Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command
|
||||||
|
@ -778,7 +643,7 @@ The top directory for configuration files.
|
||||||
The default name of the server configuration file for net
|
The default name of the server configuration file for net
|
||||||
.Ar NETNAME .
|
.Ar NETNAME .
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /conf.d/
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /conf.d/
|
||||||
Optional directory from which any .conf file will be loaded
|
Optional directory from which any *.conf file will be loaded
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
||||||
Host configuration files are kept in this directory.
|
Host configuration files are kept in this directory.
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
||||||
|
@ -789,14 +654,9 @@ It can be used to set up the corresponding network interface.
|
||||||
If an executable file with this name exists,
|
If an executable file with this name exists,
|
||||||
it will be executed right before the tinc daemon is going to close
|
it will be executed right before the tinc daemon is going to close
|
||||||
its connection to the virtual network device.
|
its connection to the virtual network device.
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /invitations/
|
|
||||||
This directory contains outstanding invitations.
|
|
||||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /invitation-data
|
|
||||||
After a successful join, this file contains a copy of the invitation data received.
|
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr tincd 8 ,
|
.Xr tincd 8 ,
|
||||||
.Xr tinc 8 ,
|
|
||||||
.Pa https://www.tinc-vpn.org/ ,
|
.Pa https://www.tinc-vpn.org/ ,
|
||||||
.Pa http://www.tldp.org/LDP/nag2/ .
|
.Pa http://www.tldp.org/LDP/nag2/ .
|
||||||
.Pp
|
.Pp
|
||||||
|
|
2582
doc/tinc.info
2582
doc/tinc.info
File diff suppressed because it is too large
Load diff
1569
doc/tinc.texi
1569
doc/tinc.texi
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
.Dd 2013-01-14
|
.Dd 2014-05-11
|
||||||
.Dt TINCD 8
|
.Dt TINCD 8
|
||||||
.\" Manual page created by:
|
.\" Manual page created by:
|
||||||
.\" Ivo Timmermans
|
.\" Ivo Timmermans
|
||||||
|
@ -8,15 +8,17 @@
|
||||||
.Nd tinc VPN daemon
|
.Nd tinc VPN daemon
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl cdDKnsoLRU
|
.Op Fl cdDkKnoLRU
|
||||||
.Op Fl -config Ns = Ns Ar DIR
|
.Op Fl -config Ns = Ns Ar DIR
|
||||||
.Op Fl -no-detach
|
.Op Fl -no-detach
|
||||||
.Op Fl -debug Ns Op = Ns Ar LEVEL
|
.Op Fl -debug Ns Op = Ns Ar LEVEL
|
||||||
|
.Op Fl -kill Ns Op = Ns Ar SIGNAL
|
||||||
.Op Fl -net Ns = Ns Ar NETNAME
|
.Op Fl -net Ns = Ns Ar NETNAME
|
||||||
|
.Op Fl -generate-keys Ns Op = Ns Ar BITS
|
||||||
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
|
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||||
.Op Fl -mlock
|
.Op Fl -mlock
|
||||||
.Op Fl -logfile Ns Op = Ns Ar FILE
|
.Op Fl -logfile Ns Op = Ns Ar FILE
|
||||||
.Op Fl -syslog
|
.Op Fl -pidfile Ns = Ns Ar FILE
|
||||||
.Op Fl -bypass-security
|
.Op Fl -bypass-security
|
||||||
.Op Fl -chroot
|
.Op Fl -chroot
|
||||||
.Op Fl -user Ns = Ns Ar USER
|
.Op Fl -user Ns = Ns Ar USER
|
||||||
|
@ -52,6 +54,14 @@ If not mentioned otherwise, this will show log messages on the standard error ou
|
||||||
Increase debug level or set it to
|
Increase debug level or set it to
|
||||||
.Ar LEVEL
|
.Ar LEVEL
|
||||||
(see below).
|
(see below).
|
||||||
|
.It Fl k, -kill Ns Op = Ns Ar SIGNAL
|
||||||
|
Attempt to kill a running
|
||||||
|
.Nm
|
||||||
|
(optionally with the specified
|
||||||
|
.Ar SIGNAL
|
||||||
|
instead of SIGTERM) and exit.
|
||||||
|
Under Windows (not Cygwin) the optional argument is ignored,
|
||||||
|
the service will always be stopped and removed.
|
||||||
.It Fl n, -net Ns = Ns Ar NETNAME
|
.It Fl n, -net Ns = Ns Ar NETNAME
|
||||||
Connect to net
|
Connect to net
|
||||||
.Ar NETNAME .
|
.Ar NETNAME .
|
||||||
|
@ -63,6 +73,13 @@ for
|
||||||
.Ar NETNAME
|
.Ar NETNAME
|
||||||
is the same as not specifying any
|
is the same as not specifying any
|
||||||
.Ar NETNAME .
|
.Ar NETNAME .
|
||||||
|
.It Fl K, -generate-keys Ns Op = Ns Ar BITS
|
||||||
|
Generate public/private RSA keypair and exit.
|
||||||
|
If
|
||||||
|
.Ar BITS
|
||||||
|
is omitted, the default length will be 2048 bits.
|
||||||
|
When saving keys to existing files, tinc will not delete the old keys,
|
||||||
|
you have to remove them manually.
|
||||||
.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
|
.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||||
Without specifying a
|
Without specifying a
|
||||||
.Ar HOST ,
|
.Ar HOST ,
|
||||||
|
@ -82,25 +99,18 @@ This option can be used more than once to specify multiple configuration variabl
|
||||||
.It Fl L, -mlock
|
.It Fl L, -mlock
|
||||||
Lock tinc into main memory.
|
Lock tinc into main memory.
|
||||||
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
|
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
|
||||||
This option is not supported on all platforms.
|
|
||||||
.It Fl -logfile Ns Op = Ns Ar FILE
|
.It Fl -logfile Ns Op = Ns Ar FILE
|
||||||
Write log entries to a file instead of to the system logging facility.
|
Write log entries to a file instead of to the system logging facility.
|
||||||
If
|
If
|
||||||
.Ar FILE
|
.Ar FILE
|
||||||
is omitted, the default is
|
is omitted, the default is
|
||||||
.Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
|
.Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
|
||||||
.It Fl s, -syslog
|
.It Fl -pidfile Ns = Ns Ar FILE
|
||||||
When this option is is set, tinc uses syslog instead of stderr in --no-detach mode.
|
Write PID to
|
||||||
.It Fl -pidfile Ns = Ns Ar FILENAME
|
|
||||||
Store a cookie in
|
|
||||||
.Ar FILENAME
|
|
||||||
which allows
|
|
||||||
.Xr tinc 8
|
|
||||||
to authenticate.
|
|
||||||
If
|
|
||||||
.Ar FILE
|
.Ar FILE
|
||||||
is omitted, the default is
|
instead of
|
||||||
.Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
|
.Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
|
||||||
|
Under Windows this option will be ignored.
|
||||||
.It Fl -bypass-security
|
.It Fl -bypass-security
|
||||||
Disables encryption and authentication of the meta protocol.
|
Disables encryption and authentication of the meta protocol.
|
||||||
Only useful for debugging.
|
Only useful for debugging.
|
||||||
|
@ -108,12 +118,10 @@ Only useful for debugging.
|
||||||
With this option tinc chroots into the directory where network
|
With this option tinc chroots into the directory where network
|
||||||
config is located (@sysconfdir@/tinc/NETNAME if -n option is used,
|
config is located (@sysconfdir@/tinc/NETNAME if -n option is used,
|
||||||
or to the directory specified with -c option) after initialization.
|
or to the directory specified with -c option) after initialization.
|
||||||
This option is not supported on all platforms.
|
|
||||||
.It Fl U, -user Ns = Ns Ar USER
|
.It Fl U, -user Ns = Ns Ar USER
|
||||||
setuid to the specified
|
setuid to the specified
|
||||||
.Ar USER
|
.Ar USER
|
||||||
after initialization.
|
after initialization.
|
||||||
This option is not supported on all platforms.
|
|
||||||
.It Fl -help
|
.It Fl -help
|
||||||
Display short list of options.
|
Display short list of options.
|
||||||
.It Fl -version
|
.It Fl -version
|
||||||
|
@ -143,6 +151,15 @@ If the
|
||||||
.Fl -logfile
|
.Fl -logfile
|
||||||
option is used, this will also close and reopen the log file,
|
option is used, this will also close and reopen the log file,
|
||||||
useful when log rotation is used.
|
useful when log rotation is used.
|
||||||
|
.It INT
|
||||||
|
Temporarily increases debug level to 5.
|
||||||
|
Send this signal again to revert to the original level.
|
||||||
|
.It USR1
|
||||||
|
Dumps the connection list to syslog.
|
||||||
|
.It USR2
|
||||||
|
Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
|
||||||
|
.It WINCH
|
||||||
|
Purges all information remembered about unreachable nodes.
|
||||||
.El
|
.El
|
||||||
.Sh DEBUG LEVELS
|
.Sh DEBUG LEVELS
|
||||||
The tinc daemon can send a lot of messages to the syslog.
|
The tinc daemon can send a lot of messages to the syslog.
|
||||||
|
@ -189,7 +206,6 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
|
||||||
.Sh TODO
|
.Sh TODO
|
||||||
A lot, especially security auditing.
|
A lot, especially security auditing.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr tinc 8 ,
|
|
||||||
.Xr tinc.conf 5 ,
|
.Xr tinc.conf 5 ,
|
||||||
.Pa https://www.tinc-vpn.org/ ,
|
.Pa https://www.tinc-vpn.org/ ,
|
||||||
.Pa http://www.cabal.org/ .
|
.Pa http://www.cabal.org/ .
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@set VERSION 1.1pre17
|
@set VERSION 1.0.36
|
||||||
@set PACKAGE tinc
|
@set PACKAGE tinc
|
||||||
@set sysconfdir /etc
|
@set sysconfdir /etc
|
||||||
@set localstatedir /var
|
@set localstatedir /var
|
||||||
|
|
|
@ -49,23 +49,21 @@
|
||||||
# modified version of the Autoconf Macro, you may extend this special
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
# exception to the GPL to apply to your modified version as well.
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
#serial 6
|
#serial 2
|
||||||
|
|
||||||
AC_DEFUN([AX_APPEND_FLAG],
|
AC_DEFUN([AX_APPEND_FLAG],
|
||||||
[dnl
|
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||||
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
|
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
|
||||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
|
AS_VAR_SET_IF(FLAGS,
|
||||||
AS_VAR_SET_IF(FLAGS,[
|
[case " AS_VAR_GET(FLAGS) " in
|
||||||
AS_CASE([" AS_VAR_GET(FLAGS) "],
|
*" $1 "*)
|
||||||
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
|
AC_RUN_LOG([: FLAGS already contains $1])
|
||||||
[
|
;;
|
||||||
AS_VAR_APPEND(FLAGS,[" $1"])
|
*)
|
||||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
AC_RUN_LOG([: FLAGS="$FLAGS $1"])
|
||||||
])
|
AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
|
||||||
],
|
;;
|
||||||
[
|
esac],
|
||||||
AS_VAR_SET(FLAGS,[$1])
|
[AS_VAR_SET(FLAGS,["$1"])])
|
||||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
|
||||||
])
|
|
||||||
AS_VAR_POPDEF([FLAGS])dnl
|
AS_VAR_POPDEF([FLAGS])dnl
|
||||||
])dnl AX_APPEND_FLAG
|
])dnl AX_APPEND_FLAG
|
||||||
|
|
|
@ -1,264 +0,0 @@
|
||||||
# ===========================================================================
|
|
||||||
# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_CODE_COVERAGE()
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
|
|
||||||
# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included
|
|
||||||
# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every
|
|
||||||
# build target (program or library) which should be built with code
|
|
||||||
# coverage support. Also defines CODE_COVERAGE_RULES which should be
|
|
||||||
# substituted in your Makefile; and $enable_code_coverage which can be
|
|
||||||
# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined
|
|
||||||
# and substituted, and corresponds to the value of the
|
|
||||||
# --enable-code-coverage option, which defaults to being disabled.
|
|
||||||
#
|
|
||||||
# Test also for gcov program and create GCOV variable that could be
|
|
||||||
# substituted.
|
|
||||||
#
|
|
||||||
# Note that all optimisation flags in CFLAGS must be disabled when code
|
|
||||||
# coverage is enabled.
|
|
||||||
#
|
|
||||||
# Usage example:
|
|
||||||
#
|
|
||||||
# configure.ac:
|
|
||||||
#
|
|
||||||
# AX_CODE_COVERAGE
|
|
||||||
#
|
|
||||||
# Makefile.am:
|
|
||||||
#
|
|
||||||
# @CODE_COVERAGE_RULES@
|
|
||||||
# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...
|
|
||||||
# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
|
|
||||||
# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
|
|
||||||
# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
|
|
||||||
#
|
|
||||||
# This results in a "check-code-coverage" rule being added to any
|
|
||||||
# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module
|
|
||||||
# has been configured with --enable-code-coverage). Running `make
|
|
||||||
# check-code-coverage` in that directory will run the module's test suite
|
|
||||||
# (`make check`) and build a code coverage report detailing the code which
|
|
||||||
# was touched, then print the URI for the report.
|
|
||||||
#
|
|
||||||
# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined
|
|
||||||
# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of
|
|
||||||
# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is
|
|
||||||
# deprecated. They have the same value.
|
|
||||||
#
|
|
||||||
# This code was derived from Makefile.decl in GLib, originally licenced
|
|
||||||
# under LGPLv2.1+.
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012, 2016 Philip Withnall
|
|
||||||
# Copyright (c) 2012 Xan Lopez
|
|
||||||
# Copyright (c) 2012 Christian Persch
|
|
||||||
# Copyright (c) 2012 Paolo Borelli
|
|
||||||
# Copyright (c) 2012 Dan Winship
|
|
||||||
# Copyright (c) 2015 Bastien ROUCARIES
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or modify it
|
|
||||||
# under the terms of the GNU Lesser General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
|
||||||
# your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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 Lesser
|
|
||||||
# General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#serial 21
|
|
||||||
|
|
||||||
AC_DEFUN([AX_CODE_COVERAGE],[
|
|
||||||
dnl Check for --enable-code-coverage
|
|
||||||
AC_REQUIRE([AC_PROG_SED])
|
|
||||||
|
|
||||||
# allow to override gcov location
|
|
||||||
AC_ARG_WITH([gcov],
|
|
||||||
[AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
|
|
||||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
|
|
||||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
|
|
||||||
|
|
||||||
AC_MSG_CHECKING([whether to build with code coverage support])
|
|
||||||
AC_ARG_ENABLE([code-coverage],
|
|
||||||
AS_HELP_STRING([--enable-code-coverage],
|
|
||||||
[Whether to enable code coverage support]),,
|
|
||||||
enable_code_coverage=no)
|
|
||||||
|
|
||||||
AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes])
|
|
||||||
AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
|
|
||||||
AC_MSG_RESULT($enable_code_coverage)
|
|
||||||
|
|
||||||
AS_IF([ test "$enable_code_coverage" = "yes" ], [
|
|
||||||
# check for gcov
|
|
||||||
AC_CHECK_TOOL([GCOV],
|
|
||||||
[$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
|
|
||||||
[:])
|
|
||||||
AS_IF([test "X$GCOV" = "X:"],
|
|
||||||
[AC_MSG_ERROR([gcov is needed to do coverage])])
|
|
||||||
AC_SUBST([GCOV])
|
|
||||||
|
|
||||||
dnl Check if gcc is being used
|
|
||||||
AS_IF([ test "$GCC" = "no" ], [
|
|
||||||
AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_CHECK_PROG([LCOV], [lcov], [lcov])
|
|
||||||
AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
|
|
||||||
|
|
||||||
AS_IF([ test -z "$LCOV" ], [
|
|
||||||
AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])
|
|
||||||
])
|
|
||||||
|
|
||||||
AS_IF([ test -z "$GENHTML" ], [
|
|
||||||
AC_MSG_ERROR([Could not find genhtml from the lcov package])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl Build the code coverage flags
|
|
||||||
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
|
|
||||||
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
|
|
||||||
CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
|
||||||
CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
|
||||||
CODE_COVERAGE_LIBS="-lgcov"
|
|
||||||
CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS"
|
|
||||||
|
|
||||||
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
|
|
||||||
AC_SUBST([CODE_COVERAGE_CFLAGS])
|
|
||||||
AC_SUBST([CODE_COVERAGE_CXXFLAGS])
|
|
||||||
AC_SUBST([CODE_COVERAGE_LIBS])
|
|
||||||
AC_SUBST([CODE_COVERAGE_LDFLAGS])
|
|
||||||
|
|
||||||
[CODE_COVERAGE_RULES_CHECK='
|
|
||||||
-$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check
|
|
||||||
$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture
|
|
||||||
']
|
|
||||||
[CODE_COVERAGE_RULES_CAPTURE='
|
|
||||||
$(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS)
|
|
||||||
$(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS)
|
|
||||||
-@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp
|
|
||||||
$(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS)
|
|
||||||
@echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html"
|
|
||||||
']
|
|
||||||
[CODE_COVERAGE_RULES_CLEAN='
|
|
||||||
clean: code-coverage-clean
|
|
||||||
distclean: code-coverage-clean
|
|
||||||
code-coverage-clean:
|
|
||||||
-$(LCOV) --directory $(top_builddir) -z
|
|
||||||
-rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
|
||||||
-find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete
|
|
||||||
']
|
|
||||||
], [
|
|
||||||
[CODE_COVERAGE_RULES_CHECK='
|
|
||||||
@echo "Need to reconfigure with --enable-code-coverage"
|
|
||||||
']
|
|
||||||
CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK"
|
|
||||||
CODE_COVERAGE_RULES_CLEAN=''
|
|
||||||
])
|
|
||||||
|
|
||||||
[CODE_COVERAGE_RULES='
|
|
||||||
# Code coverage
|
|
||||||
#
|
|
||||||
# Optional:
|
|
||||||
# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
|
|
||||||
# Multiple directories may be specified, separated by whitespace.
|
|
||||||
# (Default: $(top_builddir))
|
|
||||||
# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
|
|
||||||
# by lcov for code coverage. (Default:
|
|
||||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info)
|
|
||||||
# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
|
|
||||||
# reports to be created. (Default:
|
|
||||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage)
|
|
||||||
# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
|
|
||||||
# set to 0 to disable it and leave empty to stay with the default.
|
|
||||||
# (Default: empty)
|
|
||||||
# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
|
|
||||||
# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
|
||||||
# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
|
|
||||||
# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
|
||||||
# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
|
|
||||||
# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
|
|
||||||
# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
|
||||||
# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
|
|
||||||
# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
|
||||||
# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
|
|
||||||
# lcov instance. (Default: empty)
|
|
||||||
# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
|
|
||||||
# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
|
||||||
# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
|
|
||||||
# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
|
||||||
# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
|
|
||||||
# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
|
|
||||||
# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
|
|
||||||
#
|
|
||||||
# The generated report will be titled using the $(PACKAGE_NAME) and
|
|
||||||
# $(PACKAGE_VERSION). In order to add the current git hash to the title,
|
|
||||||
# use the git-version-gen script, available online.
|
|
||||||
|
|
||||||
# Optional variables
|
|
||||||
CODE_COVERAGE_DIRECTORY ?= $(top_builddir)
|
|
||||||
CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info
|
|
||||||
CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage
|
|
||||||
CODE_COVERAGE_BRANCH_COVERAGE ?=
|
|
||||||
CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
|
||||||
--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
|
||||||
CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
|
||||||
CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)"
|
|
||||||
CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
|
||||||
CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
|
||||||
CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
|
|
||||||
CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
|
||||||
CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
|
|
||||||
$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
|
||||||
--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
|
||||||
CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULTS)
|
|
||||||
CODE_COVERAGE_IGNORE_PATTERN ?=
|
|
||||||
|
|
||||||
code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V))
|
|
||||||
code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY))
|
|
||||||
code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\
|
|
||||||
$(CODE_COVERAGE_OUTPUT_FILE);
|
|
||||||
code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V))
|
|
||||||
code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY))
|
|
||||||
code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\
|
|
||||||
$(CODE_COVERAGE_IGNORE_PATTERN);
|
|
||||||
code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V))
|
|
||||||
code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY))
|
|
||||||
code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY);
|
|
||||||
code_coverage_quiet = $(code_coverage_quiet_$(V))
|
|
||||||
code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY))
|
|
||||||
code_coverage_quiet_0 = --quiet
|
|
||||||
|
|
||||||
# sanitizes the test-name: replaces with underscores: dashes and dots
|
|
||||||
code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1)))
|
|
||||||
|
|
||||||
# Use recursive makes in order to ignore errors during check
|
|
||||||
check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"'
|
|
||||||
|
|
||||||
# Capture code coverage data
|
|
||||||
code-coverage-capture: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"'
|
|
||||||
|
|
||||||
# Hook rule executed before code-coverage-capture, overridable by the user
|
|
||||||
code-coverage-capture-hook:
|
|
||||||
|
|
||||||
'"$CODE_COVERAGE_RULES_CLEAN"'
|
|
||||||
|
|
||||||
GITIGNOREFILES ?=
|
|
||||||
GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
|
||||||
|
|
||||||
A''M_DISTCHECK_CONFIGURE_FLAGS ?=
|
|
||||||
A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage
|
|
||||||
|
|
||||||
.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean
|
|
||||||
']
|
|
||||||
|
|
||||||
AC_SUBST([CODE_COVERAGE_RULES])
|
|
||||||
m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])])
|
|
||||||
])
|
|
44
m4/curses.m4
44
m4/curses.m4
|
@ -1,44 +0,0 @@
|
||||||
dnl Check to find the curses headers/libraries
|
|
||||||
|
|
||||||
AC_DEFUN([tinc_CURSES],
|
|
||||||
[
|
|
||||||
AC_ARG_ENABLE([curses],
|
|
||||||
AS_HELP_STRING([--disable-curses], [disable curses support]))
|
|
||||||
AS_IF([test "x$enable_curses" != "xno"], [
|
|
||||||
AC_DEFINE(HAVE_CURSES, 1, [have curses support])
|
|
||||||
curses=true
|
|
||||||
AC_ARG_WITH(curses,
|
|
||||||
AS_HELP_STRING([--with-curses=DIR], [curses base directory, or:]),
|
|
||||||
[curses="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(curses-include,
|
|
||||||
AS_HELP_STRING([--with-curses-include=DIR], [curses headers directory]),
|
|
||||||
[curses_include="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(curses-lib,
|
|
||||||
AS_HELP_STRING([--with-curses-lib=DIR], [curses library directory]),
|
|
||||||
[curses_lib="$withval"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS(curses.h,
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR("curses header files not found."); break]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_LIB(ncurses, initscr,
|
|
||||||
[CURSES_LIBS="-lncurses"; AC_CHECK_LIB(tinfo, wtimeout, [CURSES_LIBS+=" -ltinfo"], [])],
|
|
||||||
[AC_CHECK_LIB(curses, initscr,
|
|
||||||
[CURSES_LIBS="-lcurses"],
|
|
||||||
[AC_MSG_ERROR("curses libraries not found.")]
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_SUBST(CURSES_LIBS)
|
|
||||||
])
|
|
|
@ -1,33 +0,0 @@
|
||||||
dnl Check to find the libgcrypt headers/libraries
|
|
||||||
|
|
||||||
AC_DEFUN([tinc_LIBGCRYPT],
|
|
||||||
[
|
|
||||||
AC_ARG_WITH(libgcrypt,
|
|
||||||
AS_HELP_STRING([--with-libgcrypt=DIR], [libgcrypt base directory, or:]),
|
|
||||||
[libgcrypt="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(libgcrypt-include,
|
|
||||||
AS_HELP_STRING([--with-libgcrypt-include=DIR], [libgcrypt headers directory (without trailing /libgcrypt)]),
|
|
||||||
[libgcrypt_include="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(libgcrypt-lib,
|
|
||||||
AS_HELP_STRING([--with-libgcrypt-lib=DIR], [libgcrypt library directory]),
|
|
||||||
[libgcrypt_lib="$withval"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS([gcrypt.h],
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR([libgcrypt header files not found.]); break]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_LIB(gcrypt, gcry_cipher_encrypt,
|
|
||||||
[LIBS="-lgcrypt $LIBS"],
|
|
||||||
[AC_MSG_ERROR([libgcrypt libraries not found.])]
|
|
||||||
)
|
|
||||||
])
|
|
|
@ -1,40 +0,0 @@
|
||||||
dnl Check to find the miniupnpc headers/libraries
|
|
||||||
|
|
||||||
AC_DEFUN([tinc_MINIUPNPC],
|
|
||||||
[
|
|
||||||
AC_ARG_ENABLE([miniupnpc],
|
|
||||||
AS_HELP_STRING([--enable-miniupnpc], [enable miniupnpc support]))
|
|
||||||
AS_IF([test "x$enable_miniupnpc" = "xyes"], [
|
|
||||||
AC_DEFINE(HAVE_MINIUPNPC, 1, [have miniupnpc support])
|
|
||||||
AC_ARG_WITH(miniupnpc,
|
|
||||||
AS_HELP_STRING([--with-miniupnpc=DIR], [miniupnpc base directory, or:]),
|
|
||||||
[miniupnpc="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(miniupnpc-include,
|
|
||||||
AS_HELP_STRING([--with-miniupnpc-include=DIR], [miniupnpc headers directory]),
|
|
||||||
[miniupnpc_include="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(miniupnpc-lib,
|
|
||||||
AS_HELP_STRING([--with-miniupnpc-lib=DIR], [miniupnpc library directory]),
|
|
||||||
[miniupnpc_lib="$withval"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS(miniupnpc/miniupnpc.h,
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR("miniupnpc header files not found."); break]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_LIB(miniupnpc, upnpDiscover,
|
|
||||||
[MINIUPNPC_LIBS="$LIBS -lminiupnpc"],
|
|
||||||
[AC_MSG_ERROR("miniupnpc libraries not found.")]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_SUBST(MINIUPNPC_LIBS)
|
|
||||||
])
|
|
|
@ -35,7 +35,7 @@ AC_DEFUN([tinc_OPENSSL],
|
||||||
LDFLAGS="$LDFLAGS -L$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_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([LibreSSL/OpenSSL header files not found.]); break]
|
[AC_MSG_ERROR([LibreSSL/OpenSSL header files not found.]); break]
|
||||||
)
|
)
|
||||||
|
@ -54,6 +54,5 @@ AC_DEFUN([tinc_OPENSSL],
|
||||||
[#include <openssl/evp.h>]
|
[#include <openssl/evp.h>]
|
||||||
)
|
)
|
||||||
|
|
||||||
AC_CHECK_FUNCS([BN_GENCB_new ERR_remove_state RSA_set0_key], , , [#include <openssl/rsa.h>])
|
AC_CHECK_FUNCS([BN_GENCB_new RSA_set0_key], , , [#include <openssl/rsa.h>])
|
||||||
AC_CHECK_FUNCS([HMAC_CTX_new], , , [#include <openssl/hmac.h>])
|
|
||||||
])
|
])
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
dnl Check to find the readline headers/libraries
|
|
||||||
|
|
||||||
AC_DEFUN([tinc_READLINE],
|
|
||||||
[
|
|
||||||
AC_ARG_ENABLE([readline],
|
|
||||||
AS_HELP_STRING([--disable-readline], [disable readline support]))
|
|
||||||
AS_IF([test "x$enable_readline" != "xno"], [
|
|
||||||
AC_DEFINE(HAVE_READLINE, 1, [have readline support])
|
|
||||||
readline=true
|
|
||||||
AC_ARG_WITH(readline,
|
|
||||||
AS_HELP_STRING([--with-readline=DIR], [readline base directory, or:]),
|
|
||||||
[readline="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(readline-include,
|
|
||||||
AS_HELP_STRING([--with-readline-include=DIR], [readline headers directory]),
|
|
||||||
[readline_include="$withval"
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_ARG_WITH(readline-lib,
|
|
||||||
AS_HELP_STRING([--with-readline-lib=DIR], [readline library directory]),
|
|
||||||
[readline_lib="$withval"
|
|
||||||
LDFLAGS="$LDFLAGS -L$withval"]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
|
||||||
[],
|
|
||||||
[AC_MSG_ERROR("readline header files not found."); break]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_LIB(readline, readline,
|
|
||||||
[READLINE_LIBS="-lreadline"],
|
|
||||||
[AC_MSG_ERROR("readline library not found.")],
|
|
||||||
[$CURSES_LIBS]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_SUBST(READLINE_LIBS)
|
|
||||||
])
|
|
222
src/Makefile.am
222
src/Makefile.am
|
@ -1,174 +1,54 @@
|
||||||
## Produce this file with automake to get Makefile.in
|
## Produce this file with automake to get Makefile.in
|
||||||
|
|
||||||
sbin_PROGRAMS = tincd tinc
|
sbin_PROGRAMS = tincd
|
||||||
check_PROGRAMS = sptps_test sptps_keypair
|
|
||||||
EXTRA_PROGRAMS = sptps_test sptps_keypair
|
|
||||||
|
|
||||||
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
|
|
||||||
EXTRA_PROGRAMS += sptps_speed
|
|
||||||
endif
|
|
||||||
|
|
||||||
ed25519_SOURCES = \
|
|
||||||
ed25519/ed25519.h \
|
|
||||||
ed25519/fe.c ed25519/fe.h \
|
|
||||||
ed25519/fixedint.h \
|
|
||||||
ed25519/ge.c ed25519/ge.h \
|
|
||||||
ed25519/key_exchange.c \
|
|
||||||
ed25519/keypair.c \
|
|
||||||
ed25519/precomp_data.h \
|
|
||||||
ed25519/sc.c ed25519/sc.h \
|
|
||||||
ed25519/sha512.c ed25519/sha512.h \
|
|
||||||
ed25519/sign.c \
|
|
||||||
ed25519/verify.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
|
|
||||||
|
|
||||||
tincd_SOURCES = \
|
tincd_SOURCES = \
|
||||||
address_cache.c address_cache.h \
|
have.h \
|
||||||
autoconnect.c autoconnect.h \
|
system.h \
|
||||||
buffer.c buffer.h \
|
avl_tree.c avl_tree.h \
|
||||||
cipher.h \
|
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
connection.c connection.h \
|
connection.c connection.h \
|
||||||
control.c control.h \
|
|
||||||
control_common.h \
|
|
||||||
crypto.h \
|
|
||||||
device.h \
|
device.h \
|
||||||
digest.h \
|
|
||||||
dropin.c dropin.h \
|
dropin.c dropin.h \
|
||||||
dummy_device.c \
|
dummy_device.c \
|
||||||
ecdh.h \
|
|
||||||
ecdsa.h \
|
|
||||||
ecdsagen.h \
|
|
||||||
edge.c edge.h \
|
edge.c edge.h \
|
||||||
ethernet.h \
|
ethernet.h \
|
||||||
event.c event.h \
|
event.c event.h \
|
||||||
fd_device.c \
|
fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||||
|
fake-getnameinfo.c fake-getnameinfo.h \
|
||||||
graph.c graph.h \
|
graph.c graph.h \
|
||||||
hash.c hash.h \
|
|
||||||
have.h \
|
|
||||||
ipv4.h \
|
ipv4.h \
|
||||||
ipv6.h \
|
ipv6.h \
|
||||||
list.c list.h \
|
list.c list.h \
|
||||||
logger.c logger.h \
|
logger.c logger.h \
|
||||||
meta.c meta.h \
|
meta.c meta.h \
|
||||||
multicast_device.c \
|
multicast_device.c \
|
||||||
names.c names.h \
|
|
||||||
net.c net.h \
|
net.c net.h \
|
||||||
net_packet.c \
|
net_packet.c \
|
||||||
net_setup.c \
|
net_setup.c \
|
||||||
net_socket.c \
|
net_socket.c \
|
||||||
netutl.c netutl.h \
|
netutl.c netutl.h \
|
||||||
node.c node.h \
|
node.c node.h \
|
||||||
prf.h \
|
pidfile.c pidfile.h \
|
||||||
process.c process.h \
|
process.c process.h \
|
||||||
protocol.c protocol.h \
|
protocol.c protocol.h \
|
||||||
protocol_auth.c \
|
protocol_auth.c \
|
||||||
protocol_edge.c \
|
protocol_edge.c \
|
||||||
protocol_key.c \
|
|
||||||
protocol_misc.c \
|
protocol_misc.c \
|
||||||
|
protocol_key.c \
|
||||||
protocol_subnet.c \
|
protocol_subnet.c \
|
||||||
|
proxy.c proxy.h \
|
||||||
raw_socket_device.c \
|
raw_socket_device.c \
|
||||||
route.c route.h \
|
route.c route.h \
|
||||||
rsa.h \
|
|
||||||
rsagen.h \
|
|
||||||
script.c script.h \
|
|
||||||
splay_tree.c splay_tree.h \
|
|
||||||
sptps.c sptps.h \
|
|
||||||
subnet.c subnet.h \
|
subnet.c subnet.h \
|
||||||
subnet_parse.c \
|
|
||||||
system.h \
|
|
||||||
tincd.c \
|
tincd.c \
|
||||||
utils.c utils.h \
|
utils.c utils.h \
|
||||||
xalloc.h \
|
xalloc.h
|
||||||
version.c version.h \
|
|
||||||
ed25519/ecdh.c \
|
|
||||||
ed25519/ecdsa.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
|
if !GETOPT
|
||||||
tincd_SOURCES += \
|
tincd_SOURCES += \
|
||||||
getopt.c getopt.h \
|
getopt.c getopt.h \
|
||||||
getopt1.c
|
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
|
endif
|
||||||
|
|
||||||
if LINUX
|
if LINUX
|
||||||
|
@ -202,88 +82,8 @@ if VDE
|
||||||
tincd_SOURCES += vde_device.c
|
tincd_SOURCES += vde_device.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if OPENSSL
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
|
|
||||||
if MINIUPNPC
|
|
||||||
tincd_SOURCES += upnp.h upnp.c
|
|
||||||
tincd_LDADD = $(MINIUPNPC_LIBS)
|
|
||||||
tincd_LDFLAGS = -pthread
|
|
||||||
endif
|
|
||||||
|
|
||||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
|
||||||
sptps_speed_LDADD = -lrt
|
|
||||||
|
|
||||||
LIBS = @LIBS@ -lm $(CODE_COVERAGE_LIBS)
|
|
||||||
|
|
||||||
if TUNEMU
|
if TUNEMU
|
||||||
LIBS += -lpcap
|
LIBS += -lpcap
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote. $(CODE_COVERAGE_CFLAGS)
|
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/
|
||||||
AM_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS)
|
|
||||||
|
|
836
src/Makefile.in
836
src/Makefile.in
File diff suppressed because it is too large
Load diff
|
@ -1,277 +0,0 @@
|
||||||
/*
|
|
||||||
address_cache.c -- Manage cache of recently seen addresses
|
|
||||||
Copyright (C) 2018 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 "address_cache.h"
|
|
||||||
#include "conf.h"
|
|
||||||
#include "names.h"
|
|
||||||
#include "netutl.h"
|
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
static const unsigned int NOT_CACHED = -1;
|
|
||||||
|
|
||||||
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
|
|
||||||
static struct addrinfo *get_known_addresses(node_t *n) {
|
|
||||||
struct addrinfo *ai = NULL;
|
|
||||||
struct addrinfo *oai = NULL;
|
|
||||||
|
|
||||||
for splay_each(edge_t, e, n->edge_tree) {
|
|
||||||
if(!e->reverse) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
|
||||||
if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
oai = ai;
|
|
||||||
ai = xzalloc(sizeof(*ai));
|
|
||||||
ai->ai_family = e->reverse->address.sa.sa_family;
|
|
||||||
ai->ai_socktype = SOCK_STREAM;
|
|
||||||
ai->ai_protocol = IPPROTO_TCP;
|
|
||||||
ai->ai_addrlen = SALEN(e->reverse->address.sa);
|
|
||||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
|
||||||
memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
|
|
||||||
ai->ai_next = oai;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ai;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_known_addresses(struct addrinfo *ai) {
|
|
||||||
for(struct addrinfo *aip = ai, *next; aip; aip = next) {
|
|
||||||
next = aip->ai_next;
|
|
||||||
free(aip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int find_cached(address_cache_t *cache, const sockaddr_t *sa) {
|
|
||||||
for(unsigned int i = 0; i < cache->data.used; i++)
|
|
||||||
if(!sockaddrcmp(&cache->data.address[i], sa)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOT_CACHED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_recent_address(address_cache_t *cache, const sockaddr_t *sa) {
|
|
||||||
// Check if it's already cached
|
|
||||||
unsigned int pos = find_cached(cache, sa);
|
|
||||||
|
|
||||||
// It's in the first spot, so nothing to do
|
|
||||||
if(pos == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shift everything, move/add the address to the first slot
|
|
||||||
if(pos == NOT_CACHED) {
|
|
||||||
if(cache->data.used < MAX_CACHED_ADDRESSES) {
|
|
||||||
cache->data.used++;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = cache->data.used - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memmove(&cache->data.address[1], &cache->data.address[0], pos * sizeof(cache->data.address[0]));
|
|
||||||
|
|
||||||
cache->data.address[0] = *sa;
|
|
||||||
|
|
||||||
// Write the cache
|
|
||||||
char fname[PATH_MAX];
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, cache->node->name);
|
|
||||||
FILE *fp = fopen(fname, "wb");
|
|
||||||
|
|
||||||
if(fp) {
|
|
||||||
fwrite(&cache->data, sizeof(cache->data), 1, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sockaddr_t *get_recent_address(address_cache_t *cache) {
|
|
||||||
// Check if there is an address in our cache of recently seen addresses
|
|
||||||
if(cache->tried < cache->data.used) {
|
|
||||||
return &cache->data.address[cache->tried++];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, check any recently seen addresses not in our cache
|
|
||||||
while(cache->tried == cache->data.used) {
|
|
||||||
if(!cache->ai) {
|
|
||||||
cache->aip = cache->ai = get_known_addresses(cache->node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cache->ai) {
|
|
||||||
if(cache->aip) {
|
|
||||||
sockaddr_t *sa = (sockaddr_t *)cache->aip->ai_addr;
|
|
||||||
cache->aip = cache->aip->ai_next;
|
|
||||||
|
|
||||||
if(find_cached(cache, sa) != NOT_CACHED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sa;
|
|
||||||
} else {
|
|
||||||
free_known_addresses(cache->ai);
|
|
||||||
cache->ai = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->tried++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, check if there are any known Address statements
|
|
||||||
if(!cache->config_tree) {
|
|
||||||
init_configuration(&cache->config_tree);
|
|
||||||
read_host_config(cache->config_tree, cache->node->name, false);
|
|
||||||
cache->cfg = lookup_config(cache->config_tree, "Address");
|
|
||||||
}
|
|
||||||
|
|
||||||
while(cache->cfg && !cache->ai) {
|
|
||||||
char *address, *port;
|
|
||||||
|
|
||||||
get_config_string(cache->cfg, &address);
|
|
||||||
|
|
||||||
char *space = strchr(address, ' ');
|
|
||||||
|
|
||||||
if(space) {
|
|
||||||
port = xstrdup(space + 1);
|
|
||||||
*space = 0;
|
|
||||||
} else {
|
|
||||||
if(!get_config_string(lookup_config(cache->config_tree, "Port"), &port)) {
|
|
||||||
port = xstrdup("655");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->aip = cache->ai = str2addrinfo(address, port, SOCK_STREAM);
|
|
||||||
|
|
||||||
if(cache->ai) {
|
|
||||||
struct addrinfo *ai = NULL;
|
|
||||||
|
|
||||||
for(; cache->aip; cache->aip = cache->aip->ai_next) {
|
|
||||||
struct addrinfo *oai = ai;
|
|
||||||
|
|
||||||
ai = xzalloc(sizeof(*ai));
|
|
||||||
ai->ai_family = cache->aip->ai_family;
|
|
||||||
ai->ai_socktype = cache->aip->ai_socktype;
|
|
||||||
ai->ai_protocol = cache->aip->ai_protocol;
|
|
||||||
ai->ai_addrlen = cache->aip->ai_addrlen;
|
|
||||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
|
||||||
memcpy(ai->ai_addr, cache->aip->ai_addr, ai->ai_addrlen);
|
|
||||||
ai->ai_next = oai;
|
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(cache->ai);
|
|
||||||
cache->aip = cache->ai = ai;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(address);
|
|
||||||
free(port);
|
|
||||||
|
|
||||||
cache->cfg = lookup_config_next(cache->config_tree, cache->cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cache->ai) {
|
|
||||||
if(cache->aip) {
|
|
||||||
sockaddr_t *sa = (sockaddr_t *)cache->aip->ai_addr;
|
|
||||||
|
|
||||||
cache->aip = cache->aip->ai_next;
|
|
||||||
return sa;
|
|
||||||
} else {
|
|
||||||
free_known_addresses(cache->ai);
|
|
||||||
cache->ai = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're all out of addresses.
|
|
||||||
exit_configuration(&cache->config_tree);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
address_cache_t *open_address_cache(node_t *node) {
|
|
||||||
address_cache_t *cache = xmalloc(sizeof(*cache));
|
|
||||||
cache->node = node;
|
|
||||||
|
|
||||||
// Try to open an existing address cache
|
|
||||||
char fname[PATH_MAX];
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, node->name);
|
|
||||||
FILE *fp = fopen(fname, "rb");
|
|
||||||
|
|
||||||
if(!fp || fread(&cache->data, sizeof(cache->data), 1, fp) != 1 || cache->data.version != ADDRESS_CACHE_VERSION) {
|
|
||||||
memset(&cache->data, 0, sizeof(cache->data));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fp) {
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we have a valid state
|
|
||||||
cache->config_tree = NULL;
|
|
||||||
cache->cfg = NULL;
|
|
||||||
cache->ai = NULL;
|
|
||||||
cache->aip = NULL;
|
|
||||||
cache->tried = 0;
|
|
||||||
cache->data.version = ADDRESS_CACHE_VERSION;
|
|
||||||
|
|
||||||
if(cache->data.used > MAX_CACHED_ADDRESSES) {
|
|
||||||
cache->data.used = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa) {
|
|
||||||
if(sa) {
|
|
||||||
add_recent_address(cache, sa);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cache->config_tree) {
|
|
||||||
exit_configuration(&cache->config_tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cache->ai) {
|
|
||||||
free_known_addresses(cache->ai);
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->config_tree = NULL;
|
|
||||||
cache->cfg = NULL;
|
|
||||||
cache->ai = NULL;
|
|
||||||
cache->aip = NULL;
|
|
||||||
cache->tried = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_address_cache(address_cache_t *cache) {
|
|
||||||
if(cache->config_tree) {
|
|
||||||
exit_configuration(&cache->config_tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cache->ai) {
|
|
||||||
free_known_addresses(cache->ai);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cache);
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
#ifndef TINC_ADDRESS_CACHE_H
|
|
||||||
#define TINC_ADDRESS_CACHE_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
address_cache.h -- header for address_cache.c
|
|
||||||
Copyright (C) 2018 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 "net.h"
|
|
||||||
|
|
||||||
#define MAX_CACHED_ADDRESSES 8
|
|
||||||
#define ADDRESS_CACHE_VERSION 1
|
|
||||||
|
|
||||||
typedef struct address_cache_t {
|
|
||||||
struct node_t *node;
|
|
||||||
struct splay_tree_t *config_tree;
|
|
||||||
struct config_t *cfg;
|
|
||||||
struct addrinfo *ai;
|
|
||||||
struct addrinfo *aip;
|
|
||||||
unsigned int tried;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned int version;
|
|
||||||
unsigned int used;
|
|
||||||
sockaddr_t address[MAX_CACHED_ADDRESSES];
|
|
||||||
} data;
|
|
||||||
} address_cache_t;
|
|
||||||
|
|
||||||
void add_recent_address(address_cache_t *cache, const sockaddr_t *sa);
|
|
||||||
const sockaddr_t *get_recent_address(address_cache_t *cache);
|
|
||||||
|
|
||||||
address_cache_t *open_address_cache(struct node_t *node);
|
|
||||||
void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa);
|
|
||||||
void close_address_cache(address_cache_t *cache);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,195 +0,0 @@
|
||||||
/*
|
|
||||||
autoconnect.c -- automatic connection establishment
|
|
||||||
Copyright (C) 2017 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 "connection.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "node.h"
|
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
static void make_new_connection() {
|
|
||||||
/* Select a random node we haven't connected to yet. */
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!count) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(r--) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
|
||||||
if(outgoing->node == n) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found) {
|
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
|
||||||
outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
|
|
||||||
outgoing->node = n;
|
|
||||||
list_insert_tail(outgoing_list, outgoing);
|
|
||||||
setup_outgoing_connection(outgoing, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void connect_to_unreachable() {
|
|
||||||
/* Select a random known node. The rationale is that if there are many
|
|
||||||
* reachable nodes, and only a few unreachable nodes, we don't want all
|
|
||||||
* reachable nodes to try to connect to the unreachable ones at the
|
|
||||||
* same time. This way, we back off automatically. Conversely, if there
|
|
||||||
* are only a few reachable nodes, and many unreachable ones, we're
|
|
||||||
* going to try harder to connect to them. */
|
|
||||||
|
|
||||||
int r = rand() % node_tree->count;
|
|
||||||
|
|
||||||
for splay_each(node_t, n, node_tree) {
|
|
||||||
if(r--) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is it unreachable and do we know an address for it? If not, return. */
|
|
||||||
if(n == myself || n->connection || n->status.reachable || !n->status.has_address) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Are we already trying to make an outgoing connection to it? If so, return. */
|
|
||||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
|
||||||
if(outgoing->node == n) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
|
||||||
outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
|
|
||||||
outgoing->node = n;
|
|
||||||
list_insert_tail(outgoing_list, outgoing);
|
|
||||||
setup_outgoing_connection(outgoing, false);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drop_superfluous_outgoing_connection() {
|
|
||||||
/* Choose a random outgoing connection to a node that has at least one other connection. */
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for list_each(connection_t, c, connection_list) {
|
|
||||||
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!count) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int r = rand() % count;
|
|
||||||
|
|
||||||
for list_each(connection_t, c, connection_list) {
|
|
||||||
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r--) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
|
|
||||||
list_delete(outgoing_list, c->outgoing);
|
|
||||||
c->outgoing = NULL;
|
|
||||||
terminate_connection(c, c->edge);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drop_superfluous_pending_connections() {
|
|
||||||
for list_each(outgoing_t, o, outgoing_list) {
|
|
||||||
/* Only look for connections that are waiting to be retried later. */
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for list_each(connection_t, c, connection_list) {
|
|
||||||
if(c->outgoing == o) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->node->name);
|
|
||||||
list_delete_node(outgoing_list, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_autoconnect() {
|
|
||||||
/* Count number of active connections. */
|
|
||||||
int nc = 0;
|
|
||||||
|
|
||||||
for list_each(connection_t, c, connection_list) {
|
|
||||||
if(c->edge) {
|
|
||||||
nc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Less than 3 connections? Eagerly try to make a new one. */
|
|
||||||
if(nc < 3) {
|
|
||||||
make_new_connection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* More than 3 connections? See if we can get rid of a superfluous one. */
|
|
||||||
if(nc > 3) {
|
|
||||||
drop_superfluous_outgoing_connection();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check if there are unreachable nodes that we should try to connect to. */
|
|
||||||
connect_to_unreachable();
|
|
||||||
|
|
||||||
/* Drop pending outgoing connections from the outgoing list. */
|
|
||||||
drop_superfluous_pending_connections();
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
#ifndef TINC_AUTOCONNECT_H
|
|
||||||
#define TINC_AUTOCONNECT_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
autoconnect.h -- header for autoconnect.c
|
|
||||||
Copyright (C) 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void do_autoconnect(void);
|
|
||||||
|
|
||||||
#endif
|
|
757
src/avl_tree.c
Normal file
757
src/avl_tree.c
Normal file
|
@ -0,0 +1,757 @@
|
||||||
|
/*
|
||||||
|
avl_tree.c -- avl_ tree and linked list convenience
|
||||||
|
Copyright (C) 1998 Michael H. Buselli
|
||||||
|
2000-2005 Ivo Timmermans,
|
||||||
|
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
2000-2005 Wessel Dankers <wsl@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.
|
||||||
|
|
||||||
|
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||||
|
|
||||||
|
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||||
|
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||||
|
the code. Mail me if you found a bug.
|
||||||
|
|
||||||
|
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||||
|
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||||
|
Guus Sliepen <guus@tinc-vpn.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
#include "avl_tree.h"
|
||||||
|
#include "xalloc.h"
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
#define AVL_NODE_COUNT(n) ((n) ? (n)->count : 0)
|
||||||
|
#define AVL_L_COUNT(n) (AVL_NODE_COUNT((n)->left))
|
||||||
|
#define AVL_R_COUNT(n) (AVL_NODE_COUNT((n)->right))
|
||||||
|
#define AVL_CALC_COUNT(n) (AVL_L_COUNT(n) + AVL_R_COUNT(n) + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
#define AVL_NODE_DEPTH(n) ((n) ? (n)->depth : 0)
|
||||||
|
#define L_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->left))
|
||||||
|
#define R_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->right))
|
||||||
|
#define AVL_CALC_DEPTH(n) ((L_AVL_DEPTH(n)>R_AVL_DEPTH(n)?L_AVL_DEPTH(n):R_AVL_DEPTH(n)) + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AVL_DEPTH
|
||||||
|
static int lg(unsigned int u) __attribute__((__const__));
|
||||||
|
|
||||||
|
static int lg(unsigned int u) {
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if(!u) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u & 0xffff0000) {
|
||||||
|
u >>= 16;
|
||||||
|
r += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u & 0x0000ff00) {
|
||||||
|
u >>= 8;
|
||||||
|
r += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u & 0x000000f0) {
|
||||||
|
u >>= 4;
|
||||||
|
r += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u & 0x0000000c) {
|
||||||
|
u >>= 2;
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u & 0x00000002) {
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Internal helper functions */
|
||||||
|
|
||||||
|
static int avl_check_balance(const avl_node_t *node) {
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
int d;
|
||||||
|
|
||||||
|
d = R_AVL_DEPTH(node) - L_AVL_DEPTH(node);
|
||||||
|
|
||||||
|
return d < -1 ? -1 : d > 1 ? 1 : 0;
|
||||||
|
#else
|
||||||
|
/* int d;
|
||||||
|
* d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
|
||||||
|
* d = d<-1?-1:d>1?1:0;
|
||||||
|
*/
|
||||||
|
int pl, r;
|
||||||
|
|
||||||
|
pl = lg(AVL_L_COUNT(node));
|
||||||
|
r = AVL_R_COUNT(node);
|
||||||
|
|
||||||
|
if(r >> pl + 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pl < 2 || r >> pl - 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
avl_node_t *child;
|
||||||
|
avl_node_t *gchild;
|
||||||
|
avl_node_t *parent;
|
||||||
|
avl_node_t **superparent;
|
||||||
|
|
||||||
|
while(node) {
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
superparent =
|
||||||
|
parent ? node ==
|
||||||
|
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||||
|
|
||||||
|
switch(avl_check_balance(node)) {
|
||||||
|
case -1:
|
||||||
|
child = node->left;
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
|
||||||
|
if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
|
||||||
|
#else
|
||||||
|
|
||||||
|
if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
|
||||||
|
#endif
|
||||||
|
node->left = child->right;
|
||||||
|
|
||||||
|
if(node->left) {
|
||||||
|
node->left->parent = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->right = node;
|
||||||
|
node->parent = child;
|
||||||
|
*superparent = child;
|
||||||
|
child->parent = parent;
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = AVL_CALC_COUNT(node);
|
||||||
|
child->count = AVL_CALC_COUNT(child);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = AVL_CALC_DEPTH(node);
|
||||||
|
child->depth = AVL_CALC_DEPTH(child);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
gchild = child->right;
|
||||||
|
node->left = gchild->right;
|
||||||
|
|
||||||
|
if(node->left) {
|
||||||
|
node->left->parent = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->right = gchild->left;
|
||||||
|
|
||||||
|
if(child->right) {
|
||||||
|
child->right->parent = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchild->right = node;
|
||||||
|
|
||||||
|
gchild->right->parent = gchild;
|
||||||
|
gchild->left = child;
|
||||||
|
|
||||||
|
gchild->left->parent = gchild;
|
||||||
|
|
||||||
|
*superparent = gchild;
|
||||||
|
gchild->parent = parent;
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = AVL_CALC_COUNT(node);
|
||||||
|
child->count = AVL_CALC_COUNT(child);
|
||||||
|
gchild->count = AVL_CALC_COUNT(gchild);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = AVL_CALC_DEPTH(node);
|
||||||
|
child->depth = AVL_CALC_DEPTH(child);
|
||||||
|
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
child = node->right;
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
|
||||||
|
if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
|
||||||
|
#else
|
||||||
|
|
||||||
|
if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
|
||||||
|
#endif
|
||||||
|
node->right = child->left;
|
||||||
|
|
||||||
|
if(node->right) {
|
||||||
|
node->right->parent = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->left = node;
|
||||||
|
node->parent = child;
|
||||||
|
*superparent = child;
|
||||||
|
child->parent = parent;
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = AVL_CALC_COUNT(node);
|
||||||
|
child->count = AVL_CALC_COUNT(child);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = AVL_CALC_DEPTH(node);
|
||||||
|
child->depth = AVL_CALC_DEPTH(child);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
gchild = child->left;
|
||||||
|
node->right = gchild->left;
|
||||||
|
|
||||||
|
if(node->right) {
|
||||||
|
node->right->parent = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->left = gchild->right;
|
||||||
|
|
||||||
|
if(child->left) {
|
||||||
|
child->left->parent = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchild->left = node;
|
||||||
|
|
||||||
|
gchild->left->parent = gchild;
|
||||||
|
gchild->right = child;
|
||||||
|
|
||||||
|
gchild->right->parent = gchild;
|
||||||
|
|
||||||
|
*superparent = gchild;
|
||||||
|
gchild->parent = parent;
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = AVL_CALC_COUNT(node);
|
||||||
|
child->count = AVL_CALC_COUNT(child);
|
||||||
|
gchild->count = AVL_CALC_COUNT(gchild);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = AVL_CALC_DEPTH(node);
|
||||||
|
child->depth = AVL_CALC_DEPTH(child);
|
||||||
|
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = AVL_CALC_COUNT(node);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = AVL_CALC_DEPTH(node);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (De)constructors */
|
||||||
|
|
||||||
|
avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
|
||||||
|
avl_tree_t *tree;
|
||||||
|
|
||||||
|
tree = xmalloc_and_zero(sizeof(avl_tree_t));
|
||||||
|
tree->compare = compare;
|
||||||
|
tree->delete = delete;
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_free_tree(avl_tree_t *tree) {
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_alloc_node(void) {
|
||||||
|
return xmalloc_and_zero(sizeof(avl_node_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
if(node->data && tree->delete) {
|
||||||
|
tree->delete(node->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Searching */
|
||||||
|
|
||||||
|
void *avl_search(const avl_tree_t *tree, const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_node(tree, data);
|
||||||
|
|
||||||
|
return node ? node->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_closest_node(tree, data, result);
|
||||||
|
|
||||||
|
return node ? node->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_closest_smaller_node(tree, data);
|
||||||
|
|
||||||
|
return node ? node->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_closest_greater_node(tree, data);
|
||||||
|
|
||||||
|
return node ? node->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
node = avl_search_closest_node(tree, data, &result);
|
||||||
|
|
||||||
|
return result ? NULL : node;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
|
||||||
|
int *result) {
|
||||||
|
avl_node_t *node;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
node = tree->root;
|
||||||
|
|
||||||
|
if(!node) {
|
||||||
|
if(result) {
|
||||||
|
*result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
c = tree->compare(data, node->data);
|
||||||
|
|
||||||
|
if(c < 0) {
|
||||||
|
if(node->left) {
|
||||||
|
node = node->left;
|
||||||
|
} else {
|
||||||
|
if(result) {
|
||||||
|
*result = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(c > 0) {
|
||||||
|
if(node->right) {
|
||||||
|
node = node->right;
|
||||||
|
} else {
|
||||||
|
if(result) {
|
||||||
|
*result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(result) {
|
||||||
|
*result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
|
||||||
|
const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
node = avl_search_closest_node(tree, data, &result);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
node = node->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
|
||||||
|
const void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
node = avl_search_closest_node(tree, data, &result);
|
||||||
|
|
||||||
|
if(result > 0) {
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insertion and deletion */
|
||||||
|
|
||||||
|
avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
|
||||||
|
avl_node_t *closest, *new;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if(!tree->root) {
|
||||||
|
new = avl_alloc_node();
|
||||||
|
new->data = data;
|
||||||
|
avl_insert_top(tree, new);
|
||||||
|
} else {
|
||||||
|
closest = avl_search_closest_node(tree, data, &result);
|
||||||
|
|
||||||
|
switch(result) {
|
||||||
|
case -1:
|
||||||
|
new = avl_alloc_node();
|
||||||
|
new->data = data;
|
||||||
|
avl_insert_before(tree, closest, new);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
new = avl_alloc_node();
|
||||||
|
new->data = data;
|
||||||
|
avl_insert_after(tree, closest, new);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
new->count = 1;
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
new->depth = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
avl_node_t *closest;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if(!tree->root) {
|
||||||
|
avl_insert_top(tree, node);
|
||||||
|
} else {
|
||||||
|
closest = avl_search_closest_node(tree, node->data, &result);
|
||||||
|
|
||||||
|
switch(result) {
|
||||||
|
case -1:
|
||||||
|
avl_insert_before(tree, closest, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
avl_insert_after(tree, closest, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = 1;
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
node->prev = node->next = node->parent = NULL;
|
||||||
|
tree->head = tree->tail = tree->root = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
|
||||||
|
avl_node_t *node) {
|
||||||
|
if(!before) {
|
||||||
|
if(tree->tail) {
|
||||||
|
avl_insert_after(tree, tree->tail, node);
|
||||||
|
} else {
|
||||||
|
avl_insert_top(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->next = before;
|
||||||
|
node->parent = before;
|
||||||
|
node->prev = before->prev;
|
||||||
|
|
||||||
|
if(before->left) {
|
||||||
|
avl_insert_after(tree, before->prev, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(before->prev) {
|
||||||
|
before->prev->next = node;
|
||||||
|
} else {
|
||||||
|
tree->head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
before->prev = node;
|
||||||
|
before->left = node;
|
||||||
|
|
||||||
|
avl_rebalance(tree, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
|
||||||
|
if(!after) {
|
||||||
|
if(tree->head) {
|
||||||
|
avl_insert_before(tree, tree->head, node);
|
||||||
|
} else {
|
||||||
|
avl_insert_top(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(after->right) {
|
||||||
|
avl_insert_before(tree, after->next, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->prev = after;
|
||||||
|
node->parent = after;
|
||||||
|
node->next = after->next;
|
||||||
|
|
||||||
|
if(after->next) {
|
||||||
|
after->next->prev = node;
|
||||||
|
} else {
|
||||||
|
tree->tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
after->next = node;
|
||||||
|
after->right = node;
|
||||||
|
|
||||||
|
avl_rebalance(tree, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_node(tree, data);
|
||||||
|
|
||||||
|
if(node) {
|
||||||
|
avl_unlink_node(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
avl_node_t *parent;
|
||||||
|
avl_node_t **superparent;
|
||||||
|
avl_node_t *subst, *left, *right;
|
||||||
|
avl_node_t *balnode;
|
||||||
|
|
||||||
|
if(node->prev) {
|
||||||
|
node->prev->next = node->next;
|
||||||
|
} else {
|
||||||
|
tree->head = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node->next) {
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
} else {
|
||||||
|
tree->tail = node->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
superparent =
|
||||||
|
parent ? node ==
|
||||||
|
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||||
|
|
||||||
|
left = node->left;
|
||||||
|
right = node->right;
|
||||||
|
|
||||||
|
if(!left) {
|
||||||
|
*superparent = right;
|
||||||
|
|
||||||
|
if(right) {
|
||||||
|
right->parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
balnode = parent;
|
||||||
|
} else if(!right) {
|
||||||
|
*superparent = left;
|
||||||
|
left->parent = parent;
|
||||||
|
balnode = parent;
|
||||||
|
} else {
|
||||||
|
subst = node->prev;
|
||||||
|
|
||||||
|
if(!subst) { // This only happens if node is not actually in a tree at all.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subst == left) {
|
||||||
|
balnode = subst;
|
||||||
|
} else {
|
||||||
|
balnode = subst->parent;
|
||||||
|
balnode->right = subst->left;
|
||||||
|
|
||||||
|
if(balnode->right) {
|
||||||
|
balnode->right->parent = balnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
subst->left = left;
|
||||||
|
left->parent = subst;
|
||||||
|
}
|
||||||
|
|
||||||
|
subst->right = right;
|
||||||
|
subst->parent = parent;
|
||||||
|
right->parent = subst;
|
||||||
|
*superparent = subst;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_rebalance(tree, balnode);
|
||||||
|
|
||||||
|
node->next = node->prev = node->parent = node->left = node->right = NULL;
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
node->count = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
node->depth = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
|
||||||
|
avl_unlink_node(tree, node);
|
||||||
|
avl_free_node(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_delete(avl_tree_t *tree, void *data) {
|
||||||
|
avl_node_t *node;
|
||||||
|
|
||||||
|
node = avl_search_node(tree, data);
|
||||||
|
|
||||||
|
if(node) {
|
||||||
|
avl_delete_node(tree, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fast tree cleanup */
|
||||||
|
|
||||||
|
void avl_delete_tree(avl_tree_t *tree) {
|
||||||
|
avl_node_t *node, *next;
|
||||||
|
|
||||||
|
for(node = tree->head; node; node = next) {
|
||||||
|
next = node->next;
|
||||||
|
avl_free_node(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_free_tree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tree walking */
|
||||||
|
|
||||||
|
void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
|
||||||
|
avl_node_t *node, *next;
|
||||||
|
|
||||||
|
for(node = tree->head; node; node = next) {
|
||||||
|
next = node->next;
|
||||||
|
action(node->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
|
||||||
|
avl_node_t *node, *next;
|
||||||
|
|
||||||
|
for(node = tree->head; node; node = next) {
|
||||||
|
next = node->next;
|
||||||
|
action(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indexing */
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
unsigned int avl_count(const avl_tree_t *tree) {
|
||||||
|
return AVL_NODE_COUNT(tree->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
|
||||||
|
avl_node_t *node;
|
||||||
|
unsigned int c;
|
||||||
|
|
||||||
|
node = tree->root;
|
||||||
|
|
||||||
|
while(node) {
|
||||||
|
c = AVL_L_COUNT(node);
|
||||||
|
|
||||||
|
if(index < c) {
|
||||||
|
node = node->left;
|
||||||
|
} else if(index > c) {
|
||||||
|
node = node->right;
|
||||||
|
index -= c + 1;
|
||||||
|
} else {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int avl_index(const avl_node_t *node) {
|
||||||
|
avl_node_t *next;
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = AVL_L_COUNT(node);
|
||||||
|
|
||||||
|
while((next = node->parent)) {
|
||||||
|
if(node == next->right) {
|
||||||
|
index += AVL_L_COUNT(next) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
unsigned int avl_depth(const avl_tree_t *tree) {
|
||||||
|
return AVL_NODE_DEPTH(tree->root);
|
||||||
|
}
|
||||||
|
#endif
|
142
src/avl_tree.h
Normal file
142
src/avl_tree.h
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#ifndef TINC_AVL_TREE_H
|
||||||
|
#define TINC_AVL_TREE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
avl_tree.h -- header file for avl_tree.c
|
||||||
|
Copyright (C) 1998 Michael H. Buselli
|
||||||
|
2000-2005 Ivo Timmermans,
|
||||||
|
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
2000-2005 Wessel Dankers <wsl@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.
|
||||||
|
|
||||||
|
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||||
|
|
||||||
|
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||||
|
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||||
|
the code. Mail me if you found a bug.
|
||||||
|
|
||||||
|
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||||
|
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||||
|
Guus Sliepen <guus@tinc-vpn.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AVL_DEPTH
|
||||||
|
#ifndef AVL_COUNT
|
||||||
|
#define AVL_DEPTH
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct avl_node_t {
|
||||||
|
|
||||||
|
/* Linked list part */
|
||||||
|
|
||||||
|
struct avl_node_t *next;
|
||||||
|
struct avl_node_t *prev;
|
||||||
|
|
||||||
|
/* Tree part */
|
||||||
|
|
||||||
|
struct avl_node_t *parent;
|
||||||
|
struct avl_node_t *left;
|
||||||
|
struct avl_node_t *right;
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
unsigned int count;
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
unsigned char depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Payload */
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
} avl_node_t;
|
||||||
|
|
||||||
|
typedef int (*avl_compare_t)(const void *data1, const void *data2);
|
||||||
|
typedef void (*avl_action_t)(const void *data);
|
||||||
|
typedef void (*avl_action_node_t)(const avl_node_t *node);
|
||||||
|
|
||||||
|
typedef struct avl_tree_t {
|
||||||
|
|
||||||
|
/* Linked list part */
|
||||||
|
|
||||||
|
avl_node_t *head;
|
||||||
|
avl_node_t *tail;
|
||||||
|
|
||||||
|
/* Tree part */
|
||||||
|
|
||||||
|
avl_node_t *root;
|
||||||
|
|
||||||
|
avl_compare_t compare;
|
||||||
|
avl_action_t delete;
|
||||||
|
|
||||||
|
} avl_tree_t;
|
||||||
|
|
||||||
|
/* (De)constructors */
|
||||||
|
|
||||||
|
extern avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete);
|
||||||
|
extern void avl_free_tree(avl_tree_t *tree);
|
||||||
|
|
||||||
|
extern avl_node_t *avl_alloc_node(void);
|
||||||
|
extern void avl_free_node(avl_tree_t *tree, avl_node_t *node);
|
||||||
|
|
||||||
|
/* Insertion and deletion */
|
||||||
|
|
||||||
|
extern avl_node_t *avl_insert(avl_tree_t *tree, void *data);
|
||||||
|
extern avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node);
|
||||||
|
|
||||||
|
extern void avl_insert_top(avl_tree_t *tree, avl_node_t *node);
|
||||||
|
extern void avl_insert_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node);
|
||||||
|
extern void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node);
|
||||||
|
|
||||||
|
extern avl_node_t *avl_unlink(avl_tree_t *tree, void *data);
|
||||||
|
extern void avl_unlink_node(avl_tree_t *tree, avl_node_t *node);
|
||||||
|
extern void avl_delete(avl_tree_t *tree, void *data);
|
||||||
|
extern void avl_delete_node(avl_tree_t *tree, avl_node_t *node);
|
||||||
|
|
||||||
|
/* Fast tree cleanup */
|
||||||
|
|
||||||
|
extern void avl_delete_tree(avl_tree_t *tree);
|
||||||
|
|
||||||
|
/* Searching */
|
||||||
|
|
||||||
|
extern void *avl_search(const avl_tree_t *tree, const void *data);
|
||||||
|
extern void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result);
|
||||||
|
extern void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data);
|
||||||
|
extern void *avl_search_closest_greater(const avl_tree_t *tree, const void *data);
|
||||||
|
|
||||||
|
extern avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data);
|
||||||
|
extern avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, int *result);
|
||||||
|
extern avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, const void *data);
|
||||||
|
extern avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, const void *data);
|
||||||
|
|
||||||
|
/* Tree walking */
|
||||||
|
|
||||||
|
extern void avl_foreach(const avl_tree_t *tree, avl_action_t action);
|
||||||
|
extern void avl_foreach_node(const avl_tree_t *tree, avl_action_t action);
|
||||||
|
|
||||||
|
/* Indexing */
|
||||||
|
|
||||||
|
#ifdef AVL_COUNT
|
||||||
|
extern unsigned int avl_count(const avl_tree_t *tree);
|
||||||
|
extern avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index);
|
||||||
|
extern unsigned int avl_index(const avl_node_t *node);
|
||||||
|
#endif
|
||||||
|
#ifdef AVL_DEPTH
|
||||||
|
extern unsigned int avl_depth(const avl_tree_t *tree);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
168
src/bsd/device.c
168
src/bsd/device.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
device.c -- Interaction BSD tun/tap device
|
device.c -- Interaction BSD tun/tap device
|
||||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||||
2001-2017 Guus Sliepen <guus@tinc-vpn.org>
|
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -24,14 +24,13 @@
|
||||||
#include "../conf.h"
|
#include "../conf.h"
|
||||||
#include "../device.h"
|
#include "../device.h"
|
||||||
#include "../logger.h"
|
#include "../logger.h"
|
||||||
#include "../names.h"
|
|
||||||
#include "../net.h"
|
#include "../net.h"
|
||||||
#include "../route.h"
|
#include "../route.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
#include "../xalloc.h"
|
#include "../xalloc.h"
|
||||||
|
|
||||||
#ifdef ENABLE_TUNEMU
|
#ifdef ENABLE_TUNEMU
|
||||||
#include "bsd/tunemu.h"
|
#include "tunemu.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NET_IF_UTUN_H
|
#ifdef HAVE_NET_IF_UTUN_H
|
||||||
|
@ -57,6 +56,8 @@ int device_fd = -1;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
char *iface = NULL;
|
char *iface = NULL;
|
||||||
static const char *device_info = "OS X utun device";
|
static const char *device_info = "OS X utun device";
|
||||||
|
static uint64_t device_total_in = 0;
|
||||||
|
static uint64_t device_total_out = 0;
|
||||||
#if defined(ENABLE_TUNEMU)
|
#if defined(ENABLE_TUNEMU)
|
||||||
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
||||||
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD) || defined(HAVE_DRAGONFLY)
|
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD) || defined(HAVE_DRAGONFLY)
|
||||||
|
@ -70,7 +71,7 @@ static bool setup_utun(void) {
|
||||||
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||||
|
|
||||||
if(device_fd == -1) {
|
if(device_fd == -1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ static bool setup_utun(void) {
|
||||||
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
|
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
|
||||||
|
|
||||||
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
|
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
logger(LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ static bool setup_utun(void) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -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));
|
logger(LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,14 +117,22 @@ static bool setup_utun(void) {
|
||||||
iface = xstrdup(name);
|
iface = xstrdup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool setup_device(void) {
|
static bool setup_device(void) {
|
||||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
// Find out which device file to open
|
||||||
|
|
||||||
|
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||||
|
if(routing_mode == RMODE_ROUTER) {
|
||||||
|
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||||
|
} else {
|
||||||
|
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find out if it's supposed to be a tun or a tap device
|
// Find out if it's supposed to be a tun or a tap device
|
||||||
|
|
||||||
|
@ -152,36 +161,26 @@ static bool setup_device(void) {
|
||||||
} else if(!strcasecmp(type, "tap")) {
|
} else if(!strcasecmp(type, "tap")) {
|
||||||
device_type = DEVICE_TYPE_TAP;
|
device_type = DEVICE_TYPE_TAP;
|
||||||
} else {
|
} else {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef HAVE_NET_IF_UTUN_H
|
#ifdef HAVE_NET_IF_UTUN_H
|
||||||
|
|
||||||
if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0)) {
|
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) {
|
||||||
device_type = DEVICE_TYPE_UTUN;
|
device_type = DEVICE_TYPE_UTUN;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER) {
|
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
|
||||||
device_type = DEVICE_TYPE_TAP;
|
device_type = DEVICE_TYPE_TAP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(routing_mode == RMODE_SWITCH && 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!");
|
logger(LOG_ERR, "Only tap devices support switch mode!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find out which device file to open
|
|
||||||
|
|
||||||
if(!device) {
|
|
||||||
if(device_type == DEVICE_TYPE_TAP) {
|
|
||||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
|
||||||
} else {
|
|
||||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the device
|
// Open the device
|
||||||
|
|
||||||
switch(device_type) {
|
switch(device_type) {
|
||||||
|
@ -204,7 +203,7 @@ static bool setup_device(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(device_fd < 0) {
|
if(device_fd < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +233,7 @@ static bool setup_device(void) {
|
||||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
|
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
|
||||||
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
|
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
|
||||||
} else if(strcmp(iface, 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.");
|
logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the device as best as we can
|
// Configure the device as best as we can
|
||||||
|
@ -249,7 +248,7 @@ static bool setup_device(void) {
|
||||||
const int zero = 0;
|
const int zero = 0;
|
||||||
|
|
||||||
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) {
|
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,7 +270,7 @@ static bool setup_device(void) {
|
||||||
const int one = 1;
|
const int one = 1;
|
||||||
|
|
||||||
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) {
|
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +297,10 @@ static bool setup_device(void) {
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
||||||
if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) {
|
if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) {
|
||||||
free(iface);
|
if(iface) {
|
||||||
|
free(iface);
|
||||||
|
}
|
||||||
|
|
||||||
iface = xstrdup(ifr.ifr_name);
|
iface = xstrdup(ifr.ifr_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,7 +323,7 @@ static bool setup_device(void) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -339,115 +341,112 @@ static void close_device(void) {
|
||||||
close(device_fd);
|
close(device_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
device_fd = -1;
|
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
device = NULL;
|
|
||||||
free(iface);
|
free(iface);
|
||||||
iface = NULL;
|
|
||||||
device_info = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_packet(vpn_packet_t *packet) {
|
static bool read_packet(vpn_packet_t *packet) {
|
||||||
int inlen;
|
int lenin;
|
||||||
|
|
||||||
switch(device_type) {
|
switch(device_type) {
|
||||||
case DEVICE_TYPE_TUN:
|
case DEVICE_TYPE_TUN:
|
||||||
#ifdef ENABLE_TUNEMU
|
#ifdef ENABLE_TUNEMU
|
||||||
case DEVICE_TYPE_TUNEMU:
|
case DEVICE_TYPE_TUNEMU:
|
||||||
if(device_type == DEVICE_TYPE_TUNEMU) {
|
if(device_type == DEVICE_TYPE_TUNEMU) {
|
||||||
inlen = tunemu_read(device_fd, DATA(packet) + 14, MTU - 14);
|
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
inlen = read(device_fd, DATA(packet) + 14, MTU - 14);
|
lenin = read(device_fd, packet->data + 14, MTU - 14);
|
||||||
|
|
||||||
if(inlen <= 0) {
|
if(lenin <= 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(DATA(packet)[14] >> 4) {
|
switch(packet->data[14] >> 4) {
|
||||||
case 4:
|
case 4:
|
||||||
DATA(packet)[12] = 0x08;
|
packet->data[12] = 0x08;
|
||||||
DATA(packet)[13] = 0x00;
|
packet->data[13] = 0x00;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
DATA(packet)[12] = 0x86;
|
packet->data[12] = 0x86;
|
||||||
DATA(packet)[13] = 0xDD;
|
packet->data[13] = 0xDD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||||
"Unknown IP version %d while reading packet from %s %s",
|
"Unknown IP version %d while reading packet from %s %s",
|
||||||
DATA(packet)[14] >> 4, device_info, device);
|
packet->data[14] >> 4, device_info, device);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(DATA(packet), 0, 12);
|
memset(packet->data, 0, 12);
|
||||||
packet->len = inlen + 14;
|
packet->len = lenin + 14;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEVICE_TYPE_UTUN:
|
case DEVICE_TYPE_UTUN:
|
||||||
case DEVICE_TYPE_TUNIFHEAD: {
|
case DEVICE_TYPE_TUNIFHEAD: {
|
||||||
if((inlen = read(device_fd, DATA(packet) + 10, MTU - 10)) <= 0) {
|
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(DATA(packet)[14] >> 4) {
|
switch(packet->data[14] >> 4) {
|
||||||
case 4:
|
case 4:
|
||||||
DATA(packet)[12] = 0x08;
|
packet->data[12] = 0x08;
|
||||||
DATA(packet)[13] = 0x00;
|
packet->data[13] = 0x00;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
DATA(packet)[12] = 0x86;
|
packet->data[12] = 0x86;
|
||||||
DATA(packet)[13] = 0xDD;
|
packet->data[13] = 0xDD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||||
"Unknown IP version %d while reading packet from %s %s",
|
"Unknown IP version %d while reading packet from %s %s",
|
||||||
DATA(packet)[14] >> 4, device_info, device);
|
packet->data[14] >> 4, device_info, device);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(DATA(packet), 0, 12);
|
memset(packet->data, 0, 12);
|
||||||
packet->len = inlen + 10;
|
packet->len = lenin + 10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DEVICE_TYPE_TAP:
|
case DEVICE_TYPE_TAP:
|
||||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->len = inlen;
|
packet->len = lenin;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
|
device_total_in += packet->len;
|
||||||
packet->len, device_info);
|
|
||||||
|
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||||
|
packet->len, device_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_packet(vpn_packet_t *packet) {
|
static bool write_packet(vpn_packet_t *packet) {
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||||
packet->len, device_info);
|
packet->len, device_info);
|
||||||
|
|
||||||
switch(device_type) {
|
switch(device_type) {
|
||||||
case DEVICE_TYPE_TUN:
|
case DEVICE_TYPE_TUN:
|
||||||
if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -456,7 +455,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
||||||
|
|
||||||
case DEVICE_TYPE_UTUN:
|
case DEVICE_TYPE_UTUN:
|
||||||
case DEVICE_TYPE_TUNIFHEAD: {
|
case DEVICE_TYPE_TUNIFHEAD: {
|
||||||
int af = (DATA(packet)[12] << 8) + DATA(packet)[13];
|
int af = (packet->data[12] << 8) + packet->data[13];
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
|
|
||||||
switch(af) {
|
switch(af) {
|
||||||
|
@ -469,16 +468,16 @@ static bool write_packet(vpn_packet_t *packet) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||||
"Unknown address family %x while writing packet to %s %s",
|
"Unknown address family %x while writing packet to %s %s",
|
||||||
af, device_info, device);
|
af, device_info, device);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(DATA(packet) + 10, &type, sizeof(type));
|
memcpy(packet->data + 10, &type, sizeof(type));
|
||||||
|
|
||||||
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
|
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -487,8 +486,8 @@ static bool write_packet(vpn_packet_t *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DEVICE_TYPE_TAP:
|
case DEVICE_TYPE_TAP:
|
||||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -498,8 +497,8 @@ static bool write_packet(vpn_packet_t *packet) {
|
||||||
#ifdef ENABLE_TUNEMU
|
#ifdef ENABLE_TUNEMU
|
||||||
|
|
||||||
case DEVICE_TYPE_TUNEMU:
|
case DEVICE_TYPE_TUNEMU:
|
||||||
if(tunemu_write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -511,12 +510,21 @@ static bool write_packet(vpn_packet_t *packet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_total_out += packet->len;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_device_stats(void) {
|
||||||
|
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||||
|
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||||
|
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||||
|
}
|
||||||
|
|
||||||
const devops_t os_devops = {
|
const devops_t os_devops = {
|
||||||
.setup = setup_device,
|
.setup = setup_device,
|
||||||
.close = close_device,
|
.close = close_device,
|
||||||
.read = read_packet,
|
.read = read_packet,
|
||||||
.write = write_packet,
|
.write = write_packet,
|
||||||
|
.dump_stats = dump_device_stats,
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,9 +45,9 @@
|
||||||
#define PPPIOCSFLAGS _IOW('t', 89, int)
|
#define PPPIOCSFLAGS _IOW('t', 89, int)
|
||||||
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
|
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
|
||||||
#define PPPIOCATTCHAN _IOW('t', 56, int)
|
#define PPPIOCATTCHAN _IOW('t', 56, int)
|
||||||
#define PPPIOCGCHAN _IOR('t', 55, int)
|
#define PPPIOCGCHAN _IOR('t', 55, int)
|
||||||
#define PPPIOCCONNECT _IOW('t', 58, int)
|
#define PPPIOCCONNECT _IOW('t', 58, int)
|
||||||
#define PPPIOCGUNIT _IOR('t', 86, int)
|
#define PPPIOCGUNIT _IOR('t', 86, int)
|
||||||
|
|
||||||
struct sockaddr_ppp {
|
struct sockaddr_ppp {
|
||||||
u_int8_t ppp_len;
|
u_int8_t ppp_len;
|
||||||
|
@ -83,7 +83,7 @@ static char *data_buffer = NULL;
|
||||||
static void tun_error(char *format, ...) {
|
static void tun_error(char *format, ...) {
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
vsnprintf(tunemu_error, sizeof(tunemu_error), format, vl);
|
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
110
src/buffer.c
110
src/buffer.c
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
buffer.c -- buffer management
|
|
||||||
Copyright (C) 2011 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 "buffer.h"
|
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
void buffer_compact(buffer_t *buffer, uint32_t maxsize) {
|
|
||||||
if(buffer->len >= maxsize || buffer->offset / 7 > buffer->len / 8) {
|
|
||||||
memmove(buffer->data, buffer->data + buffer->offset, buffer->len - buffer->offset);
|
|
||||||
buffer->len -= buffer->offset;
|
|
||||||
buffer->offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we can add size bytes to the buffer, and return a pointer to the start of those bytes.
|
|
||||||
|
|
||||||
char *buffer_prepare(buffer_t *buffer, uint32_t size) {
|
|
||||||
if(!buffer->data) {
|
|
||||||
buffer->maxlen = size;
|
|
||||||
buffer->data = xmalloc(size);
|
|
||||||
} else {
|
|
||||||
if(buffer->offset && buffer->len + size > buffer->maxlen) {
|
|
||||||
memmove(buffer->data, buffer->data + buffer->offset, buffer->len - buffer->offset);
|
|
||||||
buffer->len -= buffer->offset;
|
|
||||||
buffer->offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buffer->len + size > buffer->maxlen) {
|
|
||||||
buffer->maxlen = buffer->len + size;
|
|
||||||
buffer->data = xrealloc(buffer->data, buffer->maxlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *start = buffer->data + buffer->len;
|
|
||||||
|
|
||||||
buffer->len += size;
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy data into the buffer.
|
|
||||||
|
|
||||||
void buffer_add(buffer_t *buffer, const char *data, uint32_t size) {
|
|
||||||
memcpy(buffer_prepare(buffer, size), data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove given number of bytes from the buffer, return a pointer to the start of them.
|
|
||||||
|
|
||||||
static char *buffer_consume(buffer_t *buffer, uint32_t size) {
|
|
||||||
char *start = buffer->data + buffer->offset;
|
|
||||||
|
|
||||||
buffer->offset += size;
|
|
||||||
|
|
||||||
if(buffer->offset >= buffer->len) {
|
|
||||||
buffer->offset = 0;
|
|
||||||
buffer->len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there is a complete line in the buffer, and if so, return it NULL-terminated.
|
|
||||||
|
|
||||||
char *buffer_readline(buffer_t *buffer) {
|
|
||||||
char *newline = memchr(buffer->data + buffer->offset, '\n', buffer->len - buffer->offset);
|
|
||||||
|
|
||||||
if(!newline) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t len = newline + 1 - (buffer->data + buffer->offset);
|
|
||||||
*newline = 0;
|
|
||||||
return buffer_consume(buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have enough bytes in the buffer, and if so, return a pointer to the start of them.
|
|
||||||
|
|
||||||
char *buffer_read(buffer_t *buffer, uint32_t size) {
|
|
||||||
if(buffer->len - buffer->offset < size) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer_consume(buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void buffer_clear(buffer_t *buffer) {
|
|
||||||
free(buffer->data);
|
|
||||||
buffer->data = NULL;
|
|
||||||
buffer->maxlen = 0;
|
|
||||||
buffer->len = 0;
|
|
||||||
buffer->offset = 0;
|
|
||||||
}
|
|
18
src/buffer.h
18
src/buffer.h
|
@ -1,18 +0,0 @@
|
||||||
#ifndef TINC_BUFFER_H
|
|
||||||
#define TINC_BUFFER_H
|
|
||||||
|
|
||||||
typedef struct buffer_t {
|
|
||||||
char *data;
|
|
||||||
uint32_t maxlen;
|
|
||||||
uint32_t len;
|
|
||||||
uint32_t offset;
|
|
||||||
} buffer_t;
|
|
||||||
|
|
||||||
extern void buffer_compact(buffer_t *buffer, uint32_t maxsize);
|
|
||||||
extern char *buffer_prepare(buffer_t *buffer, uint32_t size);
|
|
||||||
extern void buffer_add(buffer_t *buffer, const char *data, uint32_t size);
|
|
||||||
extern char *buffer_readline(buffer_t *buffer);
|
|
||||||
extern char *buffer_read(buffer_t *buffer, uint32_t size);
|
|
||||||
extern void buffer_clear(buffer_t *buffer);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,106 +0,0 @@
|
||||||
#include "../system.h"
|
|
||||||
|
|
||||||
#include "../cipher.h"
|
|
||||||
#include "../xalloc.h"
|
|
||||||
|
|
||||||
#include "chacha.h"
|
|
||||||
#include "chacha-poly1305.h"
|
|
||||||
#include "poly1305.h"
|
|
||||||
|
|
||||||
struct chacha_poly1305_ctx {
|
|
||||||
struct chacha_ctx main_ctx, header_ctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
chacha_poly1305_ctx_t *chacha_poly1305_init(void) {
|
|
||||||
chacha_poly1305_ctx_t *ctx = xzalloc(sizeof(*ctx));
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void chacha_poly1305_exit(chacha_poly1305_ctx_t *ctx) {
|
|
||||||
free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *vkey) {
|
|
||||||
const uint8_t *key = vkey;
|
|
||||||
chacha_keysetup(&ctx->main_ctx, key, 256);
|
|
||||||
chacha_keysetup(&ctx->header_ctx, key + 32, 256);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void put_u64(void *vp, uint64_t v) {
|
|
||||||
uint8_t *p = (uint8_t *) vp;
|
|
||||||
|
|
||||||
p[0] = (uint8_t)(v >> 56) & 0xff;
|
|
||||||
p[1] = (uint8_t)(v >> 48) & 0xff;
|
|
||||||
p[2] = (uint8_t)(v >> 40) & 0xff;
|
|
||||||
p[3] = (uint8_t)(v >> 32) & 0xff;
|
|
||||||
p[4] = (uint8_t)(v >> 24) & 0xff;
|
|
||||||
p[5] = (uint8_t)(v >> 16) & 0xff;
|
|
||||||
p[6] = (uint8_t)(v >> 8) & 0xff;
|
|
||||||
p[7] = (uint8_t) v & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *voutdata, size_t *outlen) {
|
|
||||||
uint8_t seqbuf[8];
|
|
||||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
|
||||||
uint8_t poly_key[POLY1305_KEYLEN];
|
|
||||||
uint8_t *outdata = voutdata;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
|
||||||
* packet sequence number.
|
|
||||||
*/
|
|
||||||
memset(poly_key, 0, sizeof(poly_key));
|
|
||||||
put_u64(seqbuf, seqnr);
|
|
||||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
|
||||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
|
||||||
|
|
||||||
/* Set Chacha's block counter to 1 */
|
|
||||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
|
||||||
|
|
||||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
|
||||||
poly1305_auth(outdata + inlen, outdata, inlen, poly_key);
|
|
||||||
|
|
||||||
if(outlen) {
|
|
||||||
*outlen = inlen + POLY1305_TAGLEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *vindata, size_t inlen, void *outdata, size_t *outlen) {
|
|
||||||
uint8_t seqbuf[8];
|
|
||||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
|
||||||
uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
|
|
||||||
const uint8_t *indata = vindata;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
|
||||||
* packet sequence number.
|
|
||||||
*/
|
|
||||||
memset(poly_key, 0, sizeof(poly_key));
|
|
||||||
put_u64(seqbuf, seqnr);
|
|
||||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
|
||||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
|
||||||
|
|
||||||
/* Set Chacha's block counter to 1 */
|
|
||||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
|
||||||
|
|
||||||
/* Check tag before anything else */
|
|
||||||
inlen -= POLY1305_TAGLEN;
|
|
||||||
const uint8_t *tag = indata + inlen;
|
|
||||||
|
|
||||||
poly1305_auth(expected_tag, indata, inlen, poly_key);
|
|
||||||
|
|
||||||
if(memcmp(expected_tag, tag, POLY1305_TAGLEN)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
|
||||||
|
|
||||||
if(outlen) {
|
|
||||||
*outlen = inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef CHACHA_POLY1305_H
|
|
||||||
#define CHACHA_POLY1305_H
|
|
||||||
|
|
||||||
#define CHACHA_POLY1305_KEYLEN 64
|
|
||||||
|
|
||||||
typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t;
|
|
||||||
|
|
||||||
extern chacha_poly1305_ctx_t *chacha_poly1305_init(void);
|
|
||||||
extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *);
|
|
||||||
extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key);
|
|
||||||
|
|
||||||
extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
|
||||||
extern bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
|
||||||
|
|
||||||
#endif //CHACHA_POLY1305_H
|
|
|
@ -1,224 +0,0 @@
|
||||||
/*
|
|
||||||
chacha-merged.c version 20080118
|
|
||||||
D. J. Bernstein
|
|
||||||
Public domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../system.h"
|
|
||||||
|
|
||||||
#include "chacha.h"
|
|
||||||
|
|
||||||
typedef struct chacha_ctx chacha_ctx;
|
|
||||||
|
|
||||||
#define U8C(v) (v##U)
|
|
||||||
#define U32C(v) (v##U)
|
|
||||||
|
|
||||||
#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
|
|
||||||
#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
|
|
||||||
|
|
||||||
#define ROTL32(v, n) \
|
|
||||||
(U32V((v) << (n)) | ((v) >> (32 - (n))))
|
|
||||||
|
|
||||||
#define U8TO32_LITTLE(p) \
|
|
||||||
(((uint32_t)((p)[0]) ) | \
|
|
||||||
((uint32_t)((p)[1]) << 8) | \
|
|
||||||
((uint32_t)((p)[2]) << 16) | \
|
|
||||||
((uint32_t)((p)[3]) << 24))
|
|
||||||
|
|
||||||
#define U32TO8_LITTLE(p, v) \
|
|
||||||
do { \
|
|
||||||
(p)[0] = U8V((v) ); \
|
|
||||||
(p)[1] = U8V((v) >> 8); \
|
|
||||||
(p)[2] = U8V((v) >> 16); \
|
|
||||||
(p)[3] = U8V((v) >> 24); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define ROTATE(v,c) (ROTL32(v,c))
|
|
||||||
#define XOR(v,w) ((v) ^ (w))
|
|
||||||
#define PLUS(v,w) (U32V((v) + (w)))
|
|
||||||
#define PLUSONE(v) (PLUS((v),1))
|
|
||||||
|
|
||||||
#define QUARTERROUND(a,b,c,d) \
|
|
||||||
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
|
|
||||||
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
|
|
||||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
|
||||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
|
||||||
|
|
||||||
static const char sigma[16] = "expand 32-byte k";
|
|
||||||
static const char tau[16] = "expand 16-byte k";
|
|
||||||
|
|
||||||
void chacha_keysetup(chacha_ctx *x, const uint8_t *k, uint32_t kbits) {
|
|
||||||
const char *constants;
|
|
||||||
|
|
||||||
x->input[4] = U8TO32_LITTLE(k + 0);
|
|
||||||
x->input[5] = U8TO32_LITTLE(k + 4);
|
|
||||||
x->input[6] = U8TO32_LITTLE(k + 8);
|
|
||||||
x->input[7] = U8TO32_LITTLE(k + 12);
|
|
||||||
|
|
||||||
if(kbits == 256) { /* recommended */
|
|
||||||
k += 16;
|
|
||||||
constants = sigma;
|
|
||||||
} else { /* kbits == 128 */
|
|
||||||
constants = tau;
|
|
||||||
}
|
|
||||||
|
|
||||||
x->input[8] = U8TO32_LITTLE(k + 0);
|
|
||||||
x->input[9] = U8TO32_LITTLE(k + 4);
|
|
||||||
x->input[10] = U8TO32_LITTLE(k + 8);
|
|
||||||
x->input[11] = U8TO32_LITTLE(k + 12);
|
|
||||||
x->input[0] = U8TO32_LITTLE(constants + 0);
|
|
||||||
x->input[1] = U8TO32_LITTLE(constants + 4);
|
|
||||||
x->input[2] = U8TO32_LITTLE(constants + 8);
|
|
||||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
void chacha_ivsetup(chacha_ctx *x, const uint8_t *iv, const uint8_t *counter) {
|
|
||||||
x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
|
|
||||||
x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
|
|
||||||
x->input[14] = U8TO32_LITTLE(iv + 0);
|
|
||||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
chacha_encrypt_bytes(chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes) {
|
|
||||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
|
||||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
|
||||||
uint8_t *ctarget = NULL;
|
|
||||||
uint8_t tmp[64];
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
if(!bytes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
j0 = x->input[0];
|
|
||||||
j1 = x->input[1];
|
|
||||||
j2 = x->input[2];
|
|
||||||
j3 = x->input[3];
|
|
||||||
j4 = x->input[4];
|
|
||||||
j5 = x->input[5];
|
|
||||||
j6 = x->input[6];
|
|
||||||
j7 = x->input[7];
|
|
||||||
j8 = x->input[8];
|
|
||||||
j9 = x->input[9];
|
|
||||||
j10 = x->input[10];
|
|
||||||
j11 = x->input[11];
|
|
||||||
j12 = x->input[12];
|
|
||||||
j13 = x->input[13];
|
|
||||||
j14 = x->input[14];
|
|
||||||
j15 = x->input[15];
|
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
if(bytes < 64) {
|
|
||||||
for(i = 0; i < bytes; ++i) {
|
|
||||||
tmp[i] = m[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
m = tmp;
|
|
||||||
ctarget = c;
|
|
||||||
c = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
x0 = j0;
|
|
||||||
x1 = j1;
|
|
||||||
x2 = j2;
|
|
||||||
x3 = j3;
|
|
||||||
x4 = j4;
|
|
||||||
x5 = j5;
|
|
||||||
x6 = j6;
|
|
||||||
x7 = j7;
|
|
||||||
x8 = j8;
|
|
||||||
x9 = j9;
|
|
||||||
x10 = j10;
|
|
||||||
x11 = j11;
|
|
||||||
x12 = j12;
|
|
||||||
x13 = j13;
|
|
||||||
x14 = j14;
|
|
||||||
x15 = j15;
|
|
||||||
|
|
||||||
for(i = 20; i > 0; i -= 2) {
|
|
||||||
QUARTERROUND(x0, x4, x8, x12)
|
|
||||||
QUARTERROUND(x1, x5, x9, x13)
|
|
||||||
QUARTERROUND(x2, x6, x10, x14)
|
|
||||||
QUARTERROUND(x3, x7, x11, x15)
|
|
||||||
QUARTERROUND(x0, x5, x10, x15)
|
|
||||||
QUARTERROUND(x1, x6, x11, x12)
|
|
||||||
QUARTERROUND(x2, x7, x8, x13)
|
|
||||||
QUARTERROUND(x3, x4, x9, x14)
|
|
||||||
}
|
|
||||||
|
|
||||||
x0 = PLUS(x0, j0);
|
|
||||||
x1 = PLUS(x1, j1);
|
|
||||||
x2 = PLUS(x2, j2);
|
|
||||||
x3 = PLUS(x3, j3);
|
|
||||||
x4 = PLUS(x4, j4);
|
|
||||||
x5 = PLUS(x5, j5);
|
|
||||||
x6 = PLUS(x6, j6);
|
|
||||||
x7 = PLUS(x7, j7);
|
|
||||||
x8 = PLUS(x8, j8);
|
|
||||||
x9 = PLUS(x9, j9);
|
|
||||||
x10 = PLUS(x10, j10);
|
|
||||||
x11 = PLUS(x11, j11);
|
|
||||||
x12 = PLUS(x12, j12);
|
|
||||||
x13 = PLUS(x13, j13);
|
|
||||||
x14 = PLUS(x14, j14);
|
|
||||||
x15 = PLUS(x15, j15);
|
|
||||||
|
|
||||||
x0 = XOR(x0, U8TO32_LITTLE(m + 0));
|
|
||||||
x1 = XOR(x1, U8TO32_LITTLE(m + 4));
|
|
||||||
x2 = XOR(x2, U8TO32_LITTLE(m + 8));
|
|
||||||
x3 = XOR(x3, U8TO32_LITTLE(m + 12));
|
|
||||||
x4 = XOR(x4, U8TO32_LITTLE(m + 16));
|
|
||||||
x5 = XOR(x5, U8TO32_LITTLE(m + 20));
|
|
||||||
x6 = XOR(x6, U8TO32_LITTLE(m + 24));
|
|
||||||
x7 = XOR(x7, U8TO32_LITTLE(m + 28));
|
|
||||||
x8 = XOR(x8, U8TO32_LITTLE(m + 32));
|
|
||||||
x9 = XOR(x9, U8TO32_LITTLE(m + 36));
|
|
||||||
x10 = XOR(x10, U8TO32_LITTLE(m + 40));
|
|
||||||
x11 = XOR(x11, U8TO32_LITTLE(m + 44));
|
|
||||||
x12 = XOR(x12, U8TO32_LITTLE(m + 48));
|
|
||||||
x13 = XOR(x13, U8TO32_LITTLE(m + 52));
|
|
||||||
x14 = XOR(x14, U8TO32_LITTLE(m + 56));
|
|
||||||
x15 = XOR(x15, U8TO32_LITTLE(m + 60));
|
|
||||||
|
|
||||||
j12 = PLUSONE(j12);
|
|
||||||
|
|
||||||
if(!j12) {
|
|
||||||
j13 = PLUSONE(j13);
|
|
||||||
/* stopping at 2^70 bytes per nonce is user's responsibility */
|
|
||||||
}
|
|
||||||
|
|
||||||
U32TO8_LITTLE(c + 0, x0);
|
|
||||||
U32TO8_LITTLE(c + 4, x1);
|
|
||||||
U32TO8_LITTLE(c + 8, x2);
|
|
||||||
U32TO8_LITTLE(c + 12, x3);
|
|
||||||
U32TO8_LITTLE(c + 16, x4);
|
|
||||||
U32TO8_LITTLE(c + 20, x5);
|
|
||||||
U32TO8_LITTLE(c + 24, x6);
|
|
||||||
U32TO8_LITTLE(c + 28, x7);
|
|
||||||
U32TO8_LITTLE(c + 32, x8);
|
|
||||||
U32TO8_LITTLE(c + 36, x9);
|
|
||||||
U32TO8_LITTLE(c + 40, x10);
|
|
||||||
U32TO8_LITTLE(c + 44, x11);
|
|
||||||
U32TO8_LITTLE(c + 48, x12);
|
|
||||||
U32TO8_LITTLE(c + 52, x13);
|
|
||||||
U32TO8_LITTLE(c + 56, x14);
|
|
||||||
U32TO8_LITTLE(c + 60, x15);
|
|
||||||
|
|
||||||
if(bytes <= 64) {
|
|
||||||
if(bytes < 64) {
|
|
||||||
for(i = 0; i < bytes; ++i) {
|
|
||||||
ctarget[i] = c[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x->input[12] = j12;
|
|
||||||
x->input[13] = j13;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes -= 64;
|
|
||||||
c += 64;
|
|
||||||
m += 64;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
chacha-merged.c version 20080118
|
|
||||||
D. J. Bernstein
|
|
||||||
Public domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CHACHA_H
|
|
||||||
#define CHACHA_H
|
|
||||||
|
|
||||||
struct chacha_ctx {
|
|
||||||
uint32_t input[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CHACHA_MINKEYLEN 16
|
|
||||||
#define CHACHA_NONCELEN 8
|
|
||||||
#define CHACHA_CTRLEN 8
|
|
||||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
|
||||||
#define CHACHA_BLOCKLEN 64
|
|
||||||
|
|
||||||
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits);
|
|
||||||
void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr);
|
|
||||||
void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes);
|
|
||||||
|
|
||||||
#endif /* CHACHA_H */
|
|
|
@ -1,205 +0,0 @@
|
||||||
/*
|
|
||||||
* Public Domain poly1305 from Andrew Moon
|
|
||||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../system.h"
|
|
||||||
|
|
||||||
#include "poly1305.h"
|
|
||||||
|
|
||||||
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
|
|
||||||
|
|
||||||
#define U8TO32_LE(p) \
|
|
||||||
(((uint32_t)((p)[0])) | \
|
|
||||||
((uint32_t)((p)[1]) << 8) | \
|
|
||||||
((uint32_t)((p)[2]) << 16) | \
|
|
||||||
((uint32_t)((p)[3]) << 24))
|
|
||||||
|
|
||||||
#define U32TO8_LE(p, v) \
|
|
||||||
do { \
|
|
||||||
(p)[0] = (uint8_t)((v)); \
|
|
||||||
(p)[1] = (uint8_t)((v) >> 8); \
|
|
||||||
(p)[2] = (uint8_t)((v) >> 16); \
|
|
||||||
(p)[3] = (uint8_t)((v) >> 24); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
void
|
|
||||||
poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
|
|
||||||
uint32_t t0, t1, t2, t3;
|
|
||||||
uint32_t h0, h1, h2, h3, h4;
|
|
||||||
uint32_t r0, r1, r2, r3, r4;
|
|
||||||
uint32_t s1, s2, s3, s4;
|
|
||||||
uint32_t b, nb;
|
|
||||||
size_t j;
|
|
||||||
uint64_t t[5];
|
|
||||||
uint64_t f0, f1, f2, f3;
|
|
||||||
uint32_t g0, g1, g2, g3, g4;
|
|
||||||
uint64_t c;
|
|
||||||
unsigned char mp[16];
|
|
||||||
|
|
||||||
/* clamp key */
|
|
||||||
t0 = U8TO32_LE(key + 0);
|
|
||||||
t1 = U8TO32_LE(key + 4);
|
|
||||||
t2 = U8TO32_LE(key + 8);
|
|
||||||
t3 = U8TO32_LE(key + 12);
|
|
||||||
|
|
||||||
/* precompute multipliers */
|
|
||||||
r0 = t0 & 0x3ffffff;
|
|
||||||
t0 >>= 26;
|
|
||||||
t0 |= t1 << 6;
|
|
||||||
r1 = t0 & 0x3ffff03;
|
|
||||||
t1 >>= 20;
|
|
||||||
t1 |= t2 << 12;
|
|
||||||
r2 = t1 & 0x3ffc0ff;
|
|
||||||
t2 >>= 14;
|
|
||||||
t2 |= t3 << 18;
|
|
||||||
r3 = t2 & 0x3f03fff;
|
|
||||||
t3 >>= 8;
|
|
||||||
r4 = t3 & 0x00fffff;
|
|
||||||
|
|
||||||
s1 = r1 * 5;
|
|
||||||
s2 = r2 * 5;
|
|
||||||
s3 = r3 * 5;
|
|
||||||
s4 = r4 * 5;
|
|
||||||
|
|
||||||
/* init state */
|
|
||||||
h0 = 0;
|
|
||||||
h1 = 0;
|
|
||||||
h2 = 0;
|
|
||||||
h3 = 0;
|
|
||||||
h4 = 0;
|
|
||||||
|
|
||||||
/* full blocks */
|
|
||||||
if(inlen < 16) {
|
|
||||||
goto poly1305_donna_atmost15bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
poly1305_donna_16bytes:
|
|
||||||
m += 16;
|
|
||||||
inlen -= 16;
|
|
||||||
|
|
||||||
t0 = U8TO32_LE(m - 16);
|
|
||||||
t1 = U8TO32_LE(m - 12);
|
|
||||||
t2 = U8TO32_LE(m - 8);
|
|
||||||
t3 = U8TO32_LE(m - 4);
|
|
||||||
|
|
||||||
h0 += t0 & 0x3ffffff;
|
|
||||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
|
||||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
|
||||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
|
||||||
h4 += (t3 >> 8) | (1 << 24);
|
|
||||||
|
|
||||||
poly1305_donna_mul:
|
|
||||||
t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + mul32x32_64(h3, s2) + mul32x32_64(h4, s1);
|
|
||||||
t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + mul32x32_64(h3, s3) + mul32x32_64(h4, s2);
|
|
||||||
t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + mul32x32_64(h3, s4) + mul32x32_64(h4, s3);
|
|
||||||
t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + mul32x32_64(h3, r0) + mul32x32_64(h4, s4);
|
|
||||||
t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + mul32x32_64(h3, r1) + mul32x32_64(h4, r0);
|
|
||||||
|
|
||||||
h0 = (uint32_t) t[0] & 0x3ffffff;
|
|
||||||
c = (t[0] >> 26);
|
|
||||||
t[1] += c;
|
|
||||||
h1 = (uint32_t) t[1] & 0x3ffffff;
|
|
||||||
b = (uint32_t)(t[1] >> 26);
|
|
||||||
t[2] += b;
|
|
||||||
h2 = (uint32_t) t[2] & 0x3ffffff;
|
|
||||||
b = (uint32_t)(t[2] >> 26);
|
|
||||||
t[3] += b;
|
|
||||||
h3 = (uint32_t) t[3] & 0x3ffffff;
|
|
||||||
b = (uint32_t)(t[3] >> 26);
|
|
||||||
t[4] += b;
|
|
||||||
h4 = (uint32_t) t[4] & 0x3ffffff;
|
|
||||||
b = (uint32_t)(t[4] >> 26);
|
|
||||||
h0 += b * 5;
|
|
||||||
|
|
||||||
if(inlen >= 16) {
|
|
||||||
goto poly1305_donna_16bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* final bytes */
|
|
||||||
poly1305_donna_atmost15bytes:
|
|
||||||
|
|
||||||
if(!inlen) {
|
|
||||||
goto poly1305_donna_finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(j = 0; j < inlen; j++) {
|
|
||||||
mp[j] = m[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
mp[j++] = 1;
|
|
||||||
|
|
||||||
for(; j < 16; j++) {
|
|
||||||
mp[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inlen = 0;
|
|
||||||
|
|
||||||
t0 = U8TO32_LE(mp + 0);
|
|
||||||
t1 = U8TO32_LE(mp + 4);
|
|
||||||
t2 = U8TO32_LE(mp + 8);
|
|
||||||
t3 = U8TO32_LE(mp + 12);
|
|
||||||
|
|
||||||
h0 += t0 & 0x3ffffff;
|
|
||||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
|
||||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
|
||||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
|
||||||
h4 += (t3 >> 8);
|
|
||||||
|
|
||||||
goto poly1305_donna_mul;
|
|
||||||
|
|
||||||
poly1305_donna_finish:
|
|
||||||
b = h0 >> 26;
|
|
||||||
h0 = h0 & 0x3ffffff;
|
|
||||||
h1 += b;
|
|
||||||
b = h1 >> 26;
|
|
||||||
h1 = h1 & 0x3ffffff;
|
|
||||||
h2 += b;
|
|
||||||
b = h2 >> 26;
|
|
||||||
h2 = h2 & 0x3ffffff;
|
|
||||||
h3 += b;
|
|
||||||
b = h3 >> 26;
|
|
||||||
h3 = h3 & 0x3ffffff;
|
|
||||||
h4 += b;
|
|
||||||
b = h4 >> 26;
|
|
||||||
h4 = h4 & 0x3ffffff;
|
|
||||||
h0 += b * 5;
|
|
||||||
b = h0 >> 26;
|
|
||||||
h0 = h0 & 0x3ffffff;
|
|
||||||
h1 += b;
|
|
||||||
|
|
||||||
g0 = h0 + 5;
|
|
||||||
b = g0 >> 26;
|
|
||||||
g0 &= 0x3ffffff;
|
|
||||||
g1 = h1 + b;
|
|
||||||
b = g1 >> 26;
|
|
||||||
g1 &= 0x3ffffff;
|
|
||||||
g2 = h2 + b;
|
|
||||||
b = g2 >> 26;
|
|
||||||
g2 &= 0x3ffffff;
|
|
||||||
g3 = h3 + b;
|
|
||||||
b = g3 >> 26;
|
|
||||||
g3 &= 0x3ffffff;
|
|
||||||
g4 = h4 + b - (1 << 26);
|
|
||||||
|
|
||||||
b = (g4 >> 31) - 1;
|
|
||||||
nb = ~b;
|
|
||||||
h0 = (h0 & nb) | (g0 & b);
|
|
||||||
h1 = (h1 & nb) | (g1 & b);
|
|
||||||
h2 = (h2 & nb) | (g2 & b);
|
|
||||||
h3 = (h3 & nb) | (g3 & b);
|
|
||||||
h4 = (h4 & nb) | (g4 & b);
|
|
||||||
|
|
||||||
f0 = ((h0) | (h1 << 26)) + (uint64_t) U8TO32_LE(&key[16]);
|
|
||||||
f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t) U8TO32_LE(&key[20]);
|
|
||||||
f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t) U8TO32_LE(&key[24]);
|
|
||||||
f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t) U8TO32_LE(&key[28]);
|
|
||||||
|
|
||||||
U32TO8_LE(&out[0], f0);
|
|
||||||
f1 += (f0 >> 32);
|
|
||||||
U32TO8_LE(&out[4], f1);
|
|
||||||
f2 += (f1 >> 32);
|
|
||||||
U32TO8_LE(&out[8], f2);
|
|
||||||
f3 += (f2 >> 32);
|
|
||||||
U32TO8_LE(&out[12], f3);
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public Domain poly1305 from Andrew Moon
|
|
||||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef POLY1305_H
|
|
||||||
#define POLY1305_H
|
|
||||||
|
|
||||||
#define POLY1305_KEYLEN 32
|
|
||||||
#define POLY1305_TAGLEN 16
|
|
||||||
|
|
||||||
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]);
|
|
||||||
|
|
||||||
#endif /* POLY1305_H */
|
|
46
src/cipher.h
46
src/cipher.h
|
@ -1,46 +0,0 @@
|
||||||
#ifndef TINC_CIPHER_H
|
|
||||||
#define TINC_CIPHER_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
cipher.h -- header file cipher.c
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CIPHER_MAX_BLOCK_SIZE 32
|
|
||||||
#define CIPHER_MAX_IV_SIZE 16
|
|
||||||
#define CIPHER_MAX_KEY_SIZE 32
|
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
|
|
||||||
typedef struct cipher cipher_t;
|
|
||||||
|
|
||||||
extern cipher_t *cipher_open_by_name(const char *name) __attribute__((__malloc__));
|
|
||||||
extern cipher_t *cipher_open_by_nid(int nid) __attribute__((__malloc__));
|
|
||||||
extern void cipher_close(cipher_t *cipher);
|
|
||||||
extern size_t cipher_keylength(const cipher_t *cipher);
|
|
||||||
extern size_t cipher_blocksize(const cipher_t *cipher);
|
|
||||||
extern uint64_t cipher_budget(const cipher_t *cipher);
|
|
||||||
extern bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool cipher_set_key_from_rsa(cipher_t *cipher, void *rsa, size_t len, bool encrypt) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__((__warn_unused_result__));
|
|
||||||
extern int cipher_get_nid(const cipher_t *cipher);
|
|
||||||
extern bool cipher_active(const cipher_t *cipher);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
257
src/conf.c
257
src/conf.c
|
@ -1,11 +1,10 @@
|
||||||
/*
|
/*
|
||||||
conf.c -- configuration code
|
conf.c -- configuration code
|
||||||
Copyright (C) 1998 Robert van der Meulen
|
Copyright (C) 1998 Robert van der Meulen
|
||||||
1998-2005 Ivo Timmermans
|
1998-2005 Ivo Timmermans
|
||||||
2000 Cris van Pelt
|
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
||||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
2000 Cris van Pelt
|
||||||
2013 Florent Clairambault <florent@clairambault.fr>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,23 +23,25 @@
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include "splay_tree.h"
|
#include "avl_tree.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "names.h"
|
#include "netutl.h" /* for str2address */
|
||||||
#include "netutl.h" /* for str2address */
|
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "utils.h" /* for cp */
|
#include "utils.h" /* for cp */
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
||||||
splay_tree_t *config_tree;
|
avl_tree_t *config_tree;
|
||||||
|
|
||||||
int pinginterval = 0; /* seconds between pings */
|
int pinginterval = 0; /* seconds between pings */
|
||||||
int pingtimeout = 0; /* seconds to wait for response */
|
int pingtimeout = 0; /* seconds to wait for response */
|
||||||
|
char *confbase = NULL; /* directory in which all config files are */
|
||||||
|
char *netname = NULL; /* name of the vpn network */
|
||||||
list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */
|
list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */
|
||||||
|
|
||||||
|
|
||||||
static int config_compare(const config_t *a, const config_t *b) {
|
static int config_compare(const config_t *a, const config_t *b) {
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -66,17 +67,17 @@ static int config_compare(const config_t *a, const config_t *b) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_configuration(splay_tree_t **config_tree) {
|
void init_configuration(avl_tree_t **config_tree) {
|
||||||
*config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
|
*config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_configuration(splay_tree_t **config_tree) {
|
void exit_configuration(avl_tree_t **config_tree) {
|
||||||
splay_delete_tree(*config_tree);
|
avl_delete_tree(*config_tree);
|
||||||
*config_tree = NULL;
|
*config_tree = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
config_t *new_config(void) {
|
config_t *new_config(void) {
|
||||||
return xzalloc(sizeof(config_t));
|
return xmalloc_and_zero(sizeof(config_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_config(config_t *cfg) {
|
void free_config(config_t *cfg) {
|
||||||
|
@ -86,18 +87,18 @@ void free_config(config_t *cfg) {
|
||||||
free(cfg);
|
free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_add(splay_tree_t *config_tree, config_t *cfg) {
|
void config_add(avl_tree_t *config_tree, config_t *cfg) {
|
||||||
splay_insert(config_tree, cfg);
|
avl_insert(config_tree, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
|
config_t *lookup_config(const avl_tree_t *config_tree, char *variable) {
|
||||||
config_t cfg, *found;
|
config_t cfg, *found;
|
||||||
|
|
||||||
cfg.variable = variable;
|
cfg.variable = variable;
|
||||||
cfg.file = NULL;
|
cfg.file = NULL;
|
||||||
cfg.line = 0;
|
cfg.line = 0;
|
||||||
|
|
||||||
found = splay_search_closest_greater(config_tree, &cfg);
|
found = avl_search_closest_greater(config_tree, &cfg);
|
||||||
|
|
||||||
if(!found) {
|
if(!found) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -110,11 +111,11 @@ config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
|
config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) {
|
||||||
splay_node_t *node;
|
avl_node_t *node;
|
||||||
config_t *found;
|
config_t *found;
|
||||||
|
|
||||||
node = splay_search_node(config_tree, cfg);
|
node = avl_search_node(config_tree, cfg);
|
||||||
|
|
||||||
if(node) {
|
if(node) {
|
||||||
if(node->next) {
|
if(node->next) {
|
||||||
|
@ -142,7 +143,7 @@ bool get_config_bool(const config_t *cfg, bool *result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||||
cfg->variable, cfg->file, cfg->line);
|
cfg->variable, cfg->file, cfg->line);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -157,7 +158,7 @@ bool get_config_int(const config_t *cfg, int *result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||||
cfg->variable, cfg->file, cfg->line);
|
cfg->variable, cfg->file, cfg->line);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -187,7 +188,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||||
cfg->variable, cfg->file, cfg->line);
|
cfg->variable, cfg->file, cfg->line);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -201,7 +202,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t **result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!str2net(&subnet, cfg->value)) {
|
if(!str2net(&subnet, cfg->value)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||||
cfg->variable, cfg->file, cfg->line);
|
cfg->variable, cfg->file, cfg->line);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -209,10 +210,10 @@ bool get_config_subnet(const config_t *cfg, subnet_t **result) {
|
||||||
/* Teach newbies what subnets are... */
|
/* Teach newbies what subnets are... */
|
||||||
|
|
||||||
if(((subnet.type == SUBNET_IPV4)
|
if(((subnet.type == SUBNET_IPV4)
|
||||||
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(subnet.net.ipv4.address)))
|
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
|
||||||
|| ((subnet.type == SUBNET_IPV6)
|
|| ((subnet.type == SUBNET_IPV6)
|
||||||
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(subnet.net.ipv6.address)))) {
|
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||||
cfg->variable, cfg->file, cfg->line);
|
cfg->variable, cfg->file, cfg->line);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -245,10 +246,9 @@ static char *readline(FILE *fp, char *buf, size_t buflen) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kill newline and carriage return if necessary */
|
*newline = '\0'; /* kill newline */
|
||||||
*newline = '\0';
|
|
||||||
|
|
||||||
if(newline > p && newline[-1] == '\r') {
|
if(newline > p && newline[-1] == '\r') { /* and carriage return if necessary */
|
||||||
newline[-1] = '\0';
|
newline[-1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +282,10 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
||||||
const char err[] = "No value for variable";
|
const char err[] = "No value for variable";
|
||||||
|
|
||||||
if(fname)
|
if(fname)
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||||
err, variable, lineno, fname);
|
err, variable, lineno, fname);
|
||||||
else
|
else
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' in command line option %d",
|
logger(LOG_ERR, "%s `%s' in command line option %d",
|
||||||
err, variable, lineno);
|
err, variable, lineno);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -304,7 +304,7 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
||||||
Parse a configuration file and put the results in the configuration tree
|
Parse a configuration file and put the results in the configuration tree
|
||||||
starting at *base.
|
starting at *base.
|
||||||
*/
|
*/
|
||||||
bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose) {
|
bool read_config_file(avl_tree_t *config_tree, const char *fname) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char buffer[MAX_STRING_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
char *line;
|
char *line;
|
||||||
|
@ -316,7 +316,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
|
||||||
fp = fopen(fname, "r");
|
fp = fopen(fname, "r");
|
||||||
|
|
||||||
if(!fp) {
|
if(!fp) {
|
||||||
logger(verbose ? DEBUG_ALWAYS : DEBUG_CONNECTIONS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,12 +364,11 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_config_options(splay_tree_t *config_tree, const char *prefix) {
|
void read_config_options(avl_tree_t *config_tree, const char *prefix) {
|
||||||
size_t prefix_len = prefix ? strlen(prefix) : 0;
|
size_t prefix_len = prefix ? strlen(prefix) : 0;
|
||||||
|
|
||||||
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
|
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
|
||||||
const config_t *cfg = node->data;
|
const config_t *cfg = node->data;
|
||||||
config_t *new;
|
|
||||||
|
|
||||||
if(!prefix) {
|
if(!prefix) {
|
||||||
if(strchr(cfg->variable, '.')) {
|
if(strchr(cfg->variable, '.')) {
|
||||||
|
@ -382,7 +381,7 @@ void read_config_options(splay_tree_t *config_tree, const char *prefix) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new = new_config();
|
config_t *new = new_config();
|
||||||
|
|
||||||
if(prefix) {
|
if(prefix) {
|
||||||
new->variable = xstrdup(cfg->variable + prefix_len + 1);
|
new->variable = xstrdup(cfg->variable + prefix_len + 1);
|
||||||
|
@ -404,14 +403,14 @@ bool read_server_config(void) {
|
||||||
|
|
||||||
read_config_options(config_tree, NULL);
|
read_config_options(config_tree, NULL);
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "tinc.conf", confbase);
|
snprintf(fname, sizeof(fname), "%s/tinc.conf", confbase);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
x = read_config_file(config_tree, fname, true);
|
x = read_config_file(config_tree, fname);
|
||||||
|
|
||||||
// We will try to read the conf files in the "conf.d" dir
|
// We will try to read the conf files in the "conf.d" dir
|
||||||
if(x) {
|
if(x) {
|
||||||
char dname[PATH_MAX];
|
char dname[PATH_MAX];
|
||||||
snprintf(dname, sizeof(dname), "%s" SLASH "conf.d", confbase);
|
snprintf(dname, sizeof(dname), "%s/conf.d", confbase);
|
||||||
DIR *dir = opendir(dname);
|
DIR *dir = opendir(dname);
|
||||||
|
|
||||||
// If we can find this dir
|
// If we can find this dir
|
||||||
|
@ -424,12 +423,12 @@ bool read_server_config(void) {
|
||||||
|
|
||||||
// And we try to read the ones that end with ".conf"
|
// And we try to read the ones that end with ".conf"
|
||||||
if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
|
if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
|
||||||
if((size_t)snprintf(fname, sizeof(fname), "%s" SLASH "%s", dname, ep->d_name) >= sizeof(fname)) {
|
if((size_t)snprintf(fname, sizeof(fname), "%s/%s", dname, ep->d_name) >= sizeof(fname)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Pathname too long: %s/%s", dname, ep->d_name);
|
logger(LOG_ERR, "Pathname too long: %s/%s", dname, ep->d_name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
x = read_config_file(config_tree, fname, true);
|
x = read_config_file(config_tree, fname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,32 +437,166 @@ bool read_server_config(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!x && errno) {
|
if(!x && errno) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_host_config(splay_tree_t *config_tree, const char *name, bool verbose) {
|
bool read_connection_config(connection_t *c) {
|
||||||
read_config_options(config_tree, name);
|
|
||||||
|
|
||||||
char fname[PATH_MAX];
|
char fname[PATH_MAX];
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
bool x;
|
||||||
return read_config_file(config_tree, fname, verbose);
|
|
||||||
|
read_config_options(c->config_tree, c->name);
|
||||||
|
|
||||||
|
snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, c->name);
|
||||||
|
x = read_config_file(c->config_tree, fname);
|
||||||
|
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool append_config_file(const char *name, const char *key, const char *value) {
|
static void disable_old_keys(const char *filename) {
|
||||||
char fname[PATH_MAX];
|
char tmpfile[PATH_MAX] = "";
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
char buf[1024];
|
||||||
|
bool disabled = false;
|
||||||
|
FILE *r, *w;
|
||||||
|
|
||||||
FILE *fp = fopen(fname, "a");
|
r = fopen(filename, "r");
|
||||||
|
|
||||||
if(!fp) {
|
if(!r) {
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno));
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
|
int len = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
|
||||||
fclose(fp);
|
|
||||||
return true;
|
if(len < 0 || len >= PATH_MAX) {
|
||||||
|
fprintf(stderr, "Pathname too long: %s.tmp\n", filename);
|
||||||
|
w = NULL;
|
||||||
|
} else {
|
||||||
|
w = fopen(tmpfile, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
while(fgets(buf, sizeof(buf), r)) {
|
||||||
|
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
|
||||||
|
buf[11] = 'O';
|
||||||
|
buf[12] = 'L';
|
||||||
|
buf[13] = 'D';
|
||||||
|
disabled = true;
|
||||||
|
} else if(!strncmp(buf, "-----END RSA", 12)) {
|
||||||
|
buf[ 9] = 'O';
|
||||||
|
buf[10] = 'L';
|
||||||
|
buf[11] = 'D';
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(w && fputs(buf, w) < 0) {
|
||||||
|
disabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(w) {
|
||||||
|
fclose(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(r);
|
||||||
|
|
||||||
|
if(!w && disabled) {
|
||||||
|
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disabled) {
|
||||||
|
#ifdef HAVE_MINGW
|
||||||
|
// We cannot atomically replace files on Windows.
|
||||||
|
char bakfile[PATH_MAX] = "";
|
||||||
|
snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
|
||||||
|
|
||||||
|
if(rename(filename, bakfile) || rename(tmpfile, filename)) {
|
||||||
|
rename(bakfile, filename);
|
||||||
|
#else
|
||||||
|
|
||||||
|
if(rename(tmpfile, filename)) {
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||||
|
} else {
|
||||||
|
#ifdef HAVE_MINGW
|
||||||
|
unlink(bakfile);
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "Warning: old key(s) found and disabled.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(tmpfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *ask_and_open(const char *filename, const char *what) {
|
||||||
|
FILE *r;
|
||||||
|
char directory[PATH_MAX];
|
||||||
|
char line[PATH_MAX];
|
||||||
|
char abspath[PATH_MAX];
|
||||||
|
const char *fn;
|
||||||
|
|
||||||
|
/* Check stdin and stdout */
|
||||||
|
if(!isatty(0) || !isatty(1)) {
|
||||||
|
/* Argh, they are running us from a script or something. Write
|
||||||
|
the files to the current directory and let them burn in hell
|
||||||
|
for ever. */
|
||||||
|
fn = filename;
|
||||||
|
} else {
|
||||||
|
/* Ask for a file and/or directory name. */
|
||||||
|
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
|
||||||
|
what, filename);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
fn = readline(stdin, line, sizeof(line));
|
||||||
|
|
||||||
|
if(!fn) {
|
||||||
|
fprintf(stderr, "Error while reading stdin: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strlen(fn))
|
||||||
|
/* User just pressed enter. */
|
||||||
|
{
|
||||||
|
fn = filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_MINGW
|
||||||
|
|
||||||
|
if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
|
||||||
|
#else
|
||||||
|
|
||||||
|
if(fn[0] != '/') {
|
||||||
|
#endif
|
||||||
|
/* The directory is a relative path or a filename. */
|
||||||
|
getcwd(directory, sizeof(directory));
|
||||||
|
|
||||||
|
if((size_t)snprintf(abspath, sizeof(abspath), "%s/%s", directory, fn) >= sizeof(abspath)) {
|
||||||
|
fprintf(stderr, "Pathname too long: %s/%s\n", directory, fn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn = abspath;
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(0077); /* Disallow everything for group and other */
|
||||||
|
|
||||||
|
disable_old_keys(fn);
|
||||||
|
|
||||||
|
/* Open it first to keep the inode busy */
|
||||||
|
|
||||||
|
r = fopen(fn, "a");
|
||||||
|
|
||||||
|
if(!r) {
|
||||||
|
fprintf(stderr, "Error opening file `%s': %s\n",
|
||||||
|
fn, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
41
src/conf.h
41
src/conf.h
|
@ -4,7 +4,7 @@
|
||||||
/*
|
/*
|
||||||
conf.h -- header for conf.c
|
conf.h -- header for conf.c
|
||||||
Copyright (C) 1998-2005 Ivo Timmermans
|
Copyright (C) 1998-2005 Ivo Timmermans
|
||||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,9 +21,8 @@
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "avl_tree.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "splay_tree.h"
|
|
||||||
#include "subnet.h"
|
|
||||||
|
|
||||||
typedef struct config_t {
|
typedef struct config_t {
|
||||||
char *variable;
|
char *variable;
|
||||||
|
@ -32,33 +31,37 @@ typedef struct config_t {
|
||||||
int line;
|
int line;
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
|
#include "subnet.h"
|
||||||
|
|
||||||
extern splay_tree_t *config_tree;
|
extern avl_tree_t *config_tree;
|
||||||
|
|
||||||
extern int pinginterval;
|
extern int pinginterval;
|
||||||
extern int pingtimeout;
|
extern int pingtimeout;
|
||||||
extern int maxtimeout;
|
extern int maxtimeout;
|
||||||
|
extern int mintimeout;
|
||||||
extern bool bypass_security;
|
extern bool bypass_security;
|
||||||
|
extern char *confbase;
|
||||||
|
extern char *netname;
|
||||||
extern list_t *cmdline_conf;
|
extern list_t *cmdline_conf;
|
||||||
|
|
||||||
extern void init_configuration(splay_tree_t **config_tree);
|
extern void init_configuration(avl_tree_t **config_tree);
|
||||||
extern void exit_configuration(splay_tree_t **config_tree);
|
extern void exit_configuration(avl_tree_t **config_tree);
|
||||||
extern config_t *new_config(void) __attribute__((__malloc__));
|
extern config_t *new_config(void) __attribute__((__malloc__));
|
||||||
extern void free_config(config_t *config);
|
extern void free_config(config_t *cfg);
|
||||||
extern void config_add(splay_tree_t *config_tree, config_t *config);
|
extern void config_add(avl_tree_t *config_tree, config_t *cfg);
|
||||||
extern config_t *lookup_config(splay_tree_t *config_tree, char *variable);
|
extern config_t *lookup_config(const avl_tree_t *config_tree, char *variable);
|
||||||
extern config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *config);
|
extern config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg);
|
||||||
extern bool get_config_bool(const config_t *config, bool *result);
|
extern bool get_config_bool(const config_t *cfg, bool *result);
|
||||||
extern bool get_config_int(const config_t *config, int *result);
|
extern bool get_config_int(const config_t *cfg, int *result);
|
||||||
extern bool get_config_string(const config_t *config, char **result);
|
extern bool get_config_string(const config_t *cfg, char **result);
|
||||||
extern bool get_config_address(const config_t *config, struct addrinfo **result);
|
extern bool get_config_address(const config_t *cfg, struct addrinfo **result);
|
||||||
extern bool get_config_subnet(const config_t *config, struct subnet_t **result);
|
extern bool get_config_subnet(const config_t *cfg, struct subnet_t **result);
|
||||||
|
|
||||||
extern config_t *parse_config_line(char *line, const char *fname, int lineno);
|
extern config_t *parse_config_line(char *line, const char *fname, int lineno);
|
||||||
extern bool read_config_file(splay_tree_t *config_tree, const char *filename, bool verbose);
|
extern bool read_config_file(avl_tree_t *config_tree, const char *fname);
|
||||||
extern void read_config_options(splay_tree_t *config_tree, const char *prefix);
|
extern void read_config_options(avl_tree_t *config_tree, const char *prefix);
|
||||||
extern bool read_server_config(void);
|
extern bool read_server_config(void);
|
||||||
extern bool read_host_config(splay_tree_t *config_tree, const char *name, bool verbose);
|
extern bool read_connection_config(struct connection_t *c);
|
||||||
extern bool append_config_file(const char *name, const char *key, const char *value);
|
extern FILE *ask_and_open(const char *fname, const char *what);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
137
src/connection.c
137
src/connection.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
connection.c -- connection list management
|
connection.c -- connection list management
|
||||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2000-2005 Ivo Timmermans
|
2000-2005 Ivo Timmermans
|
||||||
2008 Max Rijevski <maksuf@gmail.com>
|
2008 Max Rijevski <maksuf@gmail.com>
|
||||||
|
|
||||||
|
@ -21,68 +21,100 @@
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include "list.h"
|
#include "avl_tree.h"
|
||||||
#include "cipher.h"
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "control_common.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "net.h"
|
|
||||||
#include "rsa.h"
|
|
||||||
#include "subnet.h"
|
#include "subnet.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
||||||
list_t *connection_list;
|
avl_tree_t *connection_tree; /* Meta connections */
|
||||||
connection_t *everyone;
|
connection_t *everyone;
|
||||||
|
|
||||||
|
static int connection_compare(const connection_t *a, const connection_t *b) {
|
||||||
|
return a < b ? -1 : a == b ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
void init_connections(void) {
|
void init_connections(void) {
|
||||||
connection_list = list_alloc((list_action_t) free_connection);
|
connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
|
||||||
everyone = new_connection();
|
everyone = new_connection();
|
||||||
everyone->name = xstrdup("everyone");
|
everyone->name = xstrdup("everyone");
|
||||||
everyone->hostname = xstrdup("BROADCAST");
|
everyone->hostname = xstrdup("BROADCAST");
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_connections(void) {
|
void exit_connections(void) {
|
||||||
list_delete_list(connection_list);
|
avl_delete_tree(connection_tree);
|
||||||
free_connection(everyone);
|
free_connection(everyone);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_t *new_connection(void) {
|
connection_t *new_connection(void) {
|
||||||
return xzalloc(sizeof(connection_t));
|
connection_t *c;
|
||||||
|
|
||||||
|
c = xmalloc_and_zero(sizeof(connection_t));
|
||||||
|
|
||||||
|
if(!c) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gettimeofday(&c->start, NULL);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_connection_partially(connection_t *c) {
|
||||||
|
free(c->inkey);
|
||||||
|
free(c->outkey);
|
||||||
|
free(c->mychallenge);
|
||||||
|
free(c->hischallenge);
|
||||||
|
free(c->outbuf);
|
||||||
|
|
||||||
|
c->inkey = NULL;
|
||||||
|
c->outkey = NULL;
|
||||||
|
c->mychallenge = NULL;
|
||||||
|
c->hischallenge = NULL;
|
||||||
|
c->outbuf = NULL;
|
||||||
|
|
||||||
|
c->status.pinged = false;
|
||||||
|
c->status.active = false;
|
||||||
|
c->status.connecting = false;
|
||||||
|
c->status.timeout = false;
|
||||||
|
c->status.encryptout = false;
|
||||||
|
c->status.decryptin = false;
|
||||||
|
c->status.mst = false;
|
||||||
|
|
||||||
|
c->options = 0;
|
||||||
|
c->buflen = 0;
|
||||||
|
c->reqlen = 0;
|
||||||
|
c->tcplen = 0;
|
||||||
|
c->allow_request = 0;
|
||||||
|
c->outbuflen = 0;
|
||||||
|
c->outbufsize = 0;
|
||||||
|
c->outbufstart = 0;
|
||||||
|
c->last_ping_time = 0;
|
||||||
|
c->last_flushed_time = 0;
|
||||||
|
c->inbudget = 0;
|
||||||
|
c->outbudget = 0;
|
||||||
|
|
||||||
|
if(c->inctx) {
|
||||||
|
EVP_CIPHER_CTX_reset(c->inctx);
|
||||||
|
free(c->inctx);
|
||||||
|
c->inctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c->outctx) {
|
||||||
|
EVP_CIPHER_CTX_reset(c->outctx);
|
||||||
|
free(c->outctx);
|
||||||
|
c->outctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c->rsa_key) {
|
||||||
|
RSA_free(c->rsa_key);
|
||||||
|
c->rsa_key = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_connection(connection_t *c) {
|
void free_connection(connection_t *c) {
|
||||||
if(!c) {
|
free_connection_partially(c);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
cipher_close(c->incipher);
|
|
||||||
digest_close(c->indigest);
|
|
||||||
cipher_close(c->outcipher);
|
|
||||||
digest_close(c->outdigest);
|
|
||||||
rsa_free(c->rsa);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sptps_stop(&c->sptps);
|
|
||||||
ecdsa_free(c->ecdsa);
|
|
||||||
|
|
||||||
free(c->hischallenge);
|
|
||||||
free(c->mychallenge);
|
|
||||||
|
|
||||||
buffer_clear(&c->inbuf);
|
|
||||||
buffer_clear(&c->outbuf);
|
|
||||||
|
|
||||||
io_del(&c->io);
|
|
||||||
|
|
||||||
if(c->socket > 0) {
|
|
||||||
if(c->status.tarpit) {
|
|
||||||
tarpit(c->socket);
|
|
||||||
} else {
|
|
||||||
closesocket(c->socket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(c->name);
|
free(c->name);
|
||||||
free(c->hostname);
|
free(c->hostname);
|
||||||
|
@ -95,20 +127,25 @@ void free_connection(connection_t *c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_add(connection_t *c) {
|
void connection_add(connection_t *c) {
|
||||||
list_insert_tail(connection_list, c);
|
avl_insert(connection_tree, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_del(connection_t *c) {
|
void connection_del(connection_t *c) {
|
||||||
list_delete(connection_list, c);
|
avl_delete(connection_tree, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_connections(connection_t *cdump) {
|
void dump_connections(void) {
|
||||||
for list_each(connection_t, c, connection_list) {
|
avl_node_t *node;
|
||||||
send_request(cdump, "%d %d %s %s %x %d %x",
|
connection_t *c;
|
||||||
CONTROL, REQ_DUMP_CONNECTIONS,
|
|
||||||
c->name, c->hostname, c->options, c->socket,
|
logger(LOG_DEBUG, "Connections:");
|
||||||
bitfield_to_int(&c->status, sizeof(c->status)));
|
|
||||||
|
for(node = connection_tree->head; node; node = node->next) {
|
||||||
|
c = node->data;
|
||||||
|
logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d",
|
||||||
|
c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)),
|
||||||
|
c->outbufsize, c->outbufstart, c->outbuflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_request(cdump, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS);
|
logger(LOG_DEBUG, "End of connections.");
|
||||||
}
|
}
|
||||||
|
|
106
src/connection.h
106
src/connection.h
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
connection.h -- header for connection.c
|
connection.h -- header for connection.c
|
||||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2000-2005 Ivo Timmermans
|
2000-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -21,50 +21,45 @@
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "buffer.h"
|
#include <openssl/rsa.h>
|
||||||
#include "cipher.h"
|
#include <openssl/evp.h>
|
||||||
#include "digest.h"
|
|
||||||
#include "rsa.h"
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
#include "list.h"
|
#define EVP_CIPHER_CTX_reset(c) EVP_CIPHER_CTX_cleanup(c)
|
||||||
#include "sptps.h"
|
#endif
|
||||||
|
|
||||||
|
#include "avl_tree.h"
|
||||||
|
|
||||||
#define OPTION_INDIRECT 0x0001
|
#define OPTION_INDIRECT 0x0001
|
||||||
#define OPTION_TCPONLY 0x0002
|
#define OPTION_TCPONLY 0x0002
|
||||||
#define OPTION_PMTU_DISCOVERY 0x0004
|
#define OPTION_PMTU_DISCOVERY 0x0004
|
||||||
#define OPTION_CLAMP_MSS 0x0008
|
#define OPTION_CLAMP_MSS 0x0008
|
||||||
#define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
|
|
||||||
|
|
||||||
typedef struct connection_status_t {
|
typedef struct connection_status_t {
|
||||||
unsigned int pinged: 1; /* sent ping */
|
unsigned int pinged: 1; /* sent ping */
|
||||||
unsigned int unused_active: 1;
|
unsigned int active: 1; /* 1 if active.. */
|
||||||
unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||||
unsigned int unused_termreq: 1; /* the termination of this connection was requested */
|
unsigned int unused_termreq: 1; /* the termination of this connection was requested */
|
||||||
unsigned int remove_unused: 1; /* Set to 1 if you want this connection removed */
|
unsigned int remove: 1; /* Set to 1 if you want this connection removed */
|
||||||
unsigned int timeout_unused: 1; /* 1 if gotten timeout */
|
unsigned int timeout: 1; /* 1 if gotten timeout */
|
||||||
unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
|
unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
|
||||||
unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
|
unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
|
||||||
unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
|
unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
|
||||||
unsigned int control: 1; /* 1 if this is a control connection */
|
unsigned int proxy_passed: 1; /* 1 if we are connecting via a proxy and we have finished talking with it */
|
||||||
unsigned int pcap: 1; /* 1 if this is a control connection requesting packet capture */
|
unsigned int tarpit: 1; /* 1 if the connection should be added to the tarpit */
|
||||||
unsigned int log: 1; /* 1 if this is a control connection requesting log dump */
|
unsigned int unused: 21;
|
||||||
unsigned int invitation: 1; /* 1 if this is an invitation */
|
|
||||||
unsigned int invitation_used: 1; /* 1 if the invitation has been consumed */
|
|
||||||
unsigned int tarpit: 1; /* 1 if the connection should be added to the tarpit */
|
|
||||||
unsigned int unused: 17;
|
|
||||||
} connection_status_t;
|
} connection_status_t;
|
||||||
|
|
||||||
#include "ecdsa.h"
|
|
||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
typedef struct connection_t {
|
typedef struct connection_t {
|
||||||
char *name; /* name he claims to have */
|
char *name; /* name he claims to have */
|
||||||
char *hostname; /* the hostname of its real ip */
|
|
||||||
|
|
||||||
union sockaddr_t address; /* his real (internet) ip */
|
union sockaddr_t address; /* his real (internet) ip */
|
||||||
int protocol_major; /* used protocol */
|
char *hostname; /* the hostname of its real ip */
|
||||||
int protocol_minor; /* used protocol */
|
int protocol_version; /* used protocol */
|
||||||
|
|
||||||
int socket; /* socket used for this connection */
|
int socket; /* socket used for this connection */
|
||||||
uint32_t options; /* options for this connection */
|
uint32_t options; /* options for this connection */
|
||||||
|
@ -76,48 +71,53 @@ typedef struct connection_t {
|
||||||
struct node_t *node; /* node associated with the other end */
|
struct node_t *node; /* node associated with the other end */
|
||||||
struct edge_t *edge; /* edge associated with this connection */
|
struct edge_t *edge; /* edge associated with this connection */
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
RSA *rsa_key; /* his public/private key */
|
||||||
rsa_t *rsa; /* his public RSA key */
|
const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
|
||||||
cipher_t *incipher; /* Cipher he will use to send data to us */
|
const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */
|
||||||
cipher_t *outcipher; /* Cipher we will use to send data to him */
|
EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */
|
||||||
digest_t *indigest;
|
EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */
|
||||||
digest_t *outdigest;
|
uint64_t inbudget; /* Encrypted bytes send budget */
|
||||||
uint64_t inbudget;
|
uint64_t outbudget; /* Encrypted bytes receive budget */
|
||||||
uint64_t outbudget;
|
char *inkey; /* His symmetric meta key + iv */
|
||||||
#endif
|
char *outkey; /* Our symmetric meta key + iv */
|
||||||
|
int inkeylength; /* Length of his key + iv */
|
||||||
ecdsa_t *ecdsa; /* his public ECDSA key */
|
int outkeylength; /* Length of our key + iv */
|
||||||
sptps_t sptps;
|
const EVP_MD *indigest;
|
||||||
|
const EVP_MD *outdigest;
|
||||||
int inmaclength;
|
int inmaclength;
|
||||||
int outmaclength;
|
int outmaclength;
|
||||||
int incompression;
|
int incompression;
|
||||||
int outcompression;
|
int outcompression;
|
||||||
|
char *mychallenge; /* challenge we received from him */
|
||||||
|
char *hischallenge; /* challenge we sent to him */
|
||||||
|
|
||||||
char *hischallenge; /* The challenge we sent to him */
|
char buffer[MAXBUFSIZE]; /* metadata input buffer */
|
||||||
char *mychallenge; /* The challenge we received */
|
int buflen; /* bytes read into buffer */
|
||||||
|
int reqlen; /* length of incoming request */
|
||||||
struct buffer_t inbuf;
|
length_t tcplen; /* length of incoming TCPpacket */
|
||||||
struct buffer_t outbuf;
|
|
||||||
io_t io; /* input/output event on this metadata connection */
|
|
||||||
int tcplen; /* length of incoming TCPpacket */
|
|
||||||
int sptpslen; /* length of incoming SPTPS packet */
|
|
||||||
int allow_request; /* defined if there's only one request possible */
|
int allow_request; /* defined if there's only one request possible */
|
||||||
|
|
||||||
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
char *outbuf; /* metadata output buffer */
|
||||||
|
int outbufstart; /* index of first meaningful byte in output buffer */
|
||||||
|
int outbuflen; /* number of meaningful bytes in output buffer */
|
||||||
|
int outbufsize; /* number of bytes allocated to output buffer */
|
||||||
|
|
||||||
splay_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||||
|
time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */
|
||||||
|
|
||||||
|
avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||||
} connection_t;
|
} connection_t;
|
||||||
|
|
||||||
extern list_t *connection_list;
|
extern avl_tree_t *connection_tree;
|
||||||
extern connection_t *everyone;
|
extern connection_t *everyone;
|
||||||
|
|
||||||
extern void init_connections(void);
|
extern void init_connections(void);
|
||||||
extern void exit_connections(void);
|
extern void exit_connections(void);
|
||||||
extern connection_t *new_connection(void) __attribute__((__malloc__));
|
extern connection_t *new_connection(void) __attribute__((__malloc__));
|
||||||
extern void free_connection(connection_t *c);
|
extern void free_connection(connection_t *c);
|
||||||
|
extern void free_connection_partially(connection_t *c);
|
||||||
extern void connection_add(connection_t *c);
|
extern void connection_add(connection_t *c);
|
||||||
extern void connection_del(connection_t *c);
|
extern void connection_del(connection_t *c);
|
||||||
extern bool dump_connections(struct connection_t *c);
|
extern void dump_connections(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
241
src/control.c
241
src/control.c
|
@ -1,241 +0,0 @@
|
||||||
/*
|
|
||||||
control.c -- Control socket handling.
|
|
||||||
Copyright (C) 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 "crypto.h"
|
|
||||||
#include "conf.h"
|
|
||||||
#include "control.h"
|
|
||||||
#include "control_common.h"
|
|
||||||
#include "graph.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "meta.h"
|
|
||||||
#include "names.h"
|
|
||||||
#include "net.h"
|
|
||||||
#include "netutl.h"
|
|
||||||
#include "protocol.h"
|
|
||||||
#include "route.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
char controlcookie[65];
|
|
||||||
|
|
||||||
static bool control_return(connection_t *c, int type, int error) {
|
|
||||||
return send_request(c, "%d %d %d", CONTROL, type, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool control_ok(connection_t *c, int type) {
|
|
||||||
return control_return(c, type, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool control_h(connection_t *c, const char *request) {
|
|
||||||
int type;
|
|
||||||
|
|
||||||
if(!c->status.control || c->allow_request != CONTROL) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unauthorized control request from %s (%s)", c->name, c->hostname);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sscanf(request, "%*d %d", &type) != 1) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case REQ_STOP:
|
|
||||||
event_exit();
|
|
||||||
return control_ok(c, REQ_STOP);
|
|
||||||
|
|
||||||
case REQ_DUMP_NODES:
|
|
||||||
return dump_nodes(c);
|
|
||||||
|
|
||||||
case REQ_DUMP_EDGES:
|
|
||||||
return dump_edges(c);
|
|
||||||
|
|
||||||
case REQ_DUMP_SUBNETS:
|
|
||||||
return dump_subnets(c);
|
|
||||||
|
|
||||||
case REQ_DUMP_CONNECTIONS:
|
|
||||||
return dump_connections(c);
|
|
||||||
|
|
||||||
case REQ_PURGE:
|
|
||||||
purge();
|
|
||||||
return control_ok(c, REQ_PURGE);
|
|
||||||
|
|
||||||
case REQ_SET_DEBUG: {
|
|
||||||
int new_level;
|
|
||||||
|
|
||||||
if(sscanf(request, "%*d %*d %d", &new_level) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
send_request(c, "%d %d %d", CONTROL, REQ_SET_DEBUG, debug_level);
|
|
||||||
|
|
||||||
if(new_level >= 0) {
|
|
||||||
debug_level = new_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case REQ_RETRY:
|
|
||||||
retry();
|
|
||||||
return control_ok(c, REQ_RETRY);
|
|
||||||
|
|
||||||
case REQ_RELOAD:
|
|
||||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got '%s' command", "reload");
|
|
||||||
int result = reload_configuration();
|
|
||||||
return control_return(c, REQ_RELOAD, result);
|
|
||||||
|
|
||||||
case REQ_DISCONNECT: {
|
|
||||||
char name[MAX_STRING_SIZE];
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1) {
|
|
||||||
return control_return(c, REQ_DISCONNECT, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for list_each(connection_t, other, connection_list) {
|
|
||||||
if(strcmp(other->name, name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
terminate_connection(other, other->edge);
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return control_return(c, REQ_DISCONNECT, found ? 0 : -2);
|
|
||||||
}
|
|
||||||
|
|
||||||
case REQ_DUMP_TRAFFIC:
|
|
||||||
return dump_traffic(c);
|
|
||||||
|
|
||||||
case REQ_PCAP:
|
|
||||||
sscanf(request, "%*d %*d %d", &c->outmaclength);
|
|
||||||
c->status.pcap = true;
|
|
||||||
pcap = true;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case REQ_LOG:
|
|
||||||
sscanf(request, "%*d %*d %d", &c->outcompression);
|
|
||||||
c->status.log = true;
|
|
||||||
logcontrol = true;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return send_request(c, "%d %d", CONTROL, REQ_INVALID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool init_control(void) {
|
|
||||||
randomize(controlcookie, sizeof(controlcookie) / 2);
|
|
||||||
bin2hex(controlcookie, controlcookie, sizeof(controlcookie) / 2);
|
|
||||||
|
|
||||||
mode_t mask = umask(0);
|
|
||||||
umask(mask | 077);
|
|
||||||
FILE *f = fopen(pidfilename, "w");
|
|
||||||
umask(mask);
|
|
||||||
|
|
||||||
if(!f) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the address and port of the first listening socket
|
|
||||||
|
|
||||||
char *localhost = NULL;
|
|
||||||
sockaddr_t sa = {0};
|
|
||||||
socklen_t len = sizeof(sa);
|
|
||||||
|
|
||||||
// Make sure we have a valid address, and map 0.0.0.0 and :: to 127.0.0.1 and ::1.
|
|
||||||
|
|
||||||
if(getsockname(listen_socket[0].tcp.fd, &sa.sa, &len)) {
|
|
||||||
xasprintf(&localhost, "127.0.0.1 port %s", myport);
|
|
||||||
} else {
|
|
||||||
if(sa.sa.sa_family == AF_INET) {
|
|
||||||
if(sa.in.sin_addr.s_addr == 0) {
|
|
||||||
sa.in.sin_addr.s_addr = htonl(0x7f000001);
|
|
||||||
}
|
|
||||||
} else if(sa.sa.sa_family == AF_INET6) {
|
|
||||||
static const uint8_t zero[16] = {0};
|
|
||||||
|
|
||||||
if(!memcmp(sa.in6.sin6_addr.s6_addr, zero, sizeof(zero))) {
|
|
||||||
sa.in6.sin6_addr.s6_addr[15] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
localhost = sockaddr2hostname(&sa);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(f, "%d %s %s\n", (int)getpid(), controlcookie, localhost);
|
|
||||||
|
|
||||||
free(localhost);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
|
||||||
int unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
if(unix_fd < 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create UNIX socket: %s", sockstrerror(sockerrno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_un sa_un;
|
|
||||||
|
|
||||||
sa_un.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
strncpy(sa_un.sun_path, unixsocketname, sizeof(sa_un.sun_path));
|
|
||||||
|
|
||||||
sa_un.sun_path[sizeof(sa_un.sun_path) - 1] = 0;
|
|
||||||
|
|
||||||
if(connect(unix_fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) >= 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "UNIX socket %s is still in use!", unixsocketname);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink(unixsocketname);
|
|
||||||
|
|
||||||
umask(mask | 077);
|
|
||||||
int result = bind(unix_fd, (struct sockaddr *)&sa_un, sizeof(sa_un));
|
|
||||||
umask(mask);
|
|
||||||
|
|
||||||
if(result < 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not bind UNIX socket to %s: %s", unixsocketname, sockstrerror(sockerrno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(listen(unix_fd, 3) < 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not listen on UNIX socket %s: %s", unixsocketname, sockstrerror(sockerrno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_add(&unix_socket, handle_new_unix_connection, &unix_socket, unix_fd, IO_READ);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exit_control(void) {
|
|
||||||
#ifndef HAVE_MINGW
|
|
||||||
unlink(unixsocketname);
|
|
||||||
io_del(&unix_socket);
|
|
||||||
close(unix_socket.fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unlink(pidfilename);
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef TINC_CONTROL_H
|
|
||||||
#define TINC_CONTROL_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
control.h -- header for control.c.
|
|
||||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern bool init_control(void);
|
|
||||||
extern void exit_control(void);
|
|
||||||
extern char controlcookie[];
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,48 +0,0 @@
|
||||||
#ifndef TINC_CONTROL_COMMON_H
|
|
||||||
#define TINC_CONTROL_COMMON_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
control_protocol.h -- control socket protocol.
|
|
||||||
Copyright (C) 2007 Scott Lamb <slamb@slamb.org>
|
|
||||||
2009-2012 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 "protocol.h"
|
|
||||||
|
|
||||||
enum request_type {
|
|
||||||
REQ_INVALID = -1,
|
|
||||||
REQ_STOP = 0,
|
|
||||||
REQ_RELOAD,
|
|
||||||
REQ_RESTART,
|
|
||||||
REQ_DUMP_NODES,
|
|
||||||
REQ_DUMP_EDGES,
|
|
||||||
REQ_DUMP_SUBNETS,
|
|
||||||
REQ_DUMP_CONNECTIONS,
|
|
||||||
REQ_DUMP_GRAPH,
|
|
||||||
REQ_PURGE,
|
|
||||||
REQ_SET_DEBUG,
|
|
||||||
REQ_RETRY,
|
|
||||||
REQ_CONNECT,
|
|
||||||
REQ_DISCONNECT,
|
|
||||||
REQ_DUMP_TRAFFIC,
|
|
||||||
REQ_PCAP,
|
|
||||||
REQ_LOG,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TINC_CTL_VERSION_CURRENT 0
|
|
||||||
|
|
||||||
#endif
|
|
27
src/crypto.h
27
src/crypto.h
|
@ -1,27 +0,0 @@
|
||||||
#ifndef TINC_CRYPTO_H
|
|
||||||
#define TINC_CRYPTO_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
crypto.h -- header for crypto.c
|
|
||||||
Copyright (C) 2007-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void crypto_init(void);
|
|
||||||
extern void crypto_exit(void);
|
|
||||||
extern void randomize(void *buf, size_t buflen);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
2002-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -27,7 +27,6 @@
|
||||||
#include "../conf.h"
|
#include "../conf.h"
|
||||||
#include "../device.h"
|
#include "../device.h"
|
||||||
#include "../logger.h"
|
#include "../logger.h"
|
||||||
#include "../names.h"
|
|
||||||
#include "../route.h"
|
#include "../route.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
#include "../xalloc.h"
|
#include "../xalloc.h"
|
||||||
|
@ -40,6 +39,9 @@ char *device = NULL;
|
||||||
char *iface = NULL;
|
char *iface = NULL;
|
||||||
static const char *device_info = "Windows tap device";
|
static const char *device_info = "Windows tap device";
|
||||||
|
|
||||||
|
static uint64_t device_total_in = 0;
|
||||||
|
static uint64_t device_total_out = 0;
|
||||||
|
|
||||||
static pid_t reader_pid;
|
static pid_t reader_pid;
|
||||||
static int sp[2];
|
static int sp[2];
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ static bool setup_device(void) {
|
||||||
/* Open registry and look for network adapters */
|
/* Open registry and look for network adapters */
|
||||||
|
|
||||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +127,7 @@ static bool setup_device(void) {
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
|
|
||||||
if(!found) {
|
if(!found) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
|
logger(LOG_ERR, "No Windows tap device found!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +146,7 @@ static bool setup_device(void) {
|
||||||
Furthermore I don't really know how to do it the "Windows" way. */
|
Furthermore I don't really know how to do it the "Windows" way. */
|
||||||
|
|
||||||
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
|
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +155,7 @@ static bool setup_device(void) {
|
||||||
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||||
|
|
||||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +164,7 @@ static bool setup_device(void) {
|
||||||
/* Get MAC address from tap device */
|
/* Get MAC address from tap device */
|
||||||
|
|
||||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +177,7 @@ static bool setup_device(void) {
|
||||||
reader_pid = fork();
|
reader_pid = fork();
|
||||||
|
|
||||||
if(reader_pid == -1) {
|
if(reader_pid == -1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,20 +186,20 @@ static bool setup_device(void) {
|
||||||
It passes everything it reads to the socket. */
|
It passes everything it reads to the socket. */
|
||||||
|
|
||||||
char buf[MTU];
|
char buf[MTU];
|
||||||
long inlen;
|
long lenin;
|
||||||
|
|
||||||
CloseHandle(device_handle);
|
CloseHandle(device_handle);
|
||||||
|
|
||||||
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||||
|
|
||||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
write(sp[1], buf, 1);
|
write(sp[1], buf, 1);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader forked and running.");
|
logger(LOG_DEBUG, "Tap reader forked and running.");
|
||||||
|
|
||||||
/* Notify success */
|
/* Notify success */
|
||||||
|
|
||||||
|
@ -207,19 +209,19 @@ static bool setup_device(void) {
|
||||||
/* Pass packets */
|
/* Pass packets */
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ReadFile(device_handle, buf, MTU, &inlen, NULL);
|
ReadFile(device_handle, buf, MTU, &lenin, NULL);
|
||||||
write(sp[1], buf, inlen);
|
write(sp[1], buf, lenin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read(device_fd, &gelukt, 1);
|
read(device_fd, &gelukt, 1);
|
||||||
|
|
||||||
if(gelukt != 1) {
|
if(gelukt != 1) {
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader failed!");
|
logger(LOG_DEBUG, "Tap reader failed!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -228,51 +230,58 @@ static void close_device(void) {
|
||||||
close(sp[0]);
|
close(sp[0]);
|
||||||
close(sp[1]);
|
close(sp[1]);
|
||||||
CloseHandle(device_handle);
|
CloseHandle(device_handle);
|
||||||
device_handle = INVALID_HANDLE_VALUE;
|
|
||||||
|
|
||||||
kill(reader_pid, SIGKILL);
|
kill(reader_pid, SIGKILL);
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
device = NULL;
|
|
||||||
free(iface);
|
free(iface);
|
||||||
iface = NULL;
|
|
||||||
device_info = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_packet(vpn_packet_t *packet) {
|
static bool read_packet(vpn_packet_t *packet) {
|
||||||
int inlen;
|
int lenin;
|
||||||
|
|
||||||
if((inlen = read(sp[0], DATA(packet), MTU)) <= 0) {
|
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||||
device, strerror(errno));
|
device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->len = inlen;
|
packet->len = lenin;
|
||||||
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
device_total_in += packet->len;
|
||||||
device_info);
|
|
||||||
|
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||||
|
device_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_packet(vpn_packet_t *packet) {
|
static bool write_packet(vpn_packet_t *packet) {
|
||||||
long outlen;
|
long lenout;
|
||||||
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||||
packet->len, device_info);
|
packet->len, device_info);
|
||||||
|
|
||||||
if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, NULL)) {
|
if(!WriteFile(device_handle, packet->data, packet->len, &lenout, NULL)) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_total_out += packet->len;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_device_stats(void) {
|
||||||
|
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||||
|
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||||
|
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||||
|
}
|
||||||
|
|
||||||
const devops_t os_devops = {
|
const devops_t os_devops = {
|
||||||
.setup = setup_device,
|
.setup = setup_device,
|
||||||
.close = close_device,
|
.close = close_device,
|
||||||
.read = read_packet,
|
.read = read_packet,
|
||||||
.write = write_packet,
|
.write = write_packet,
|
||||||
|
.dump_stats = dump_device_stats,
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,22 +25,21 @@
|
||||||
|
|
||||||
extern int device_fd;
|
extern int device_fd;
|
||||||
extern char *device;
|
extern char *device;
|
||||||
|
|
||||||
extern char *iface;
|
extern char *iface;
|
||||||
|
|
||||||
typedef struct devops_t {
|
typedef struct devops_t {
|
||||||
bool (*setup)(void);
|
bool (*setup)(void);
|
||||||
void (*close)(void);
|
void (*close)(void);
|
||||||
bool (*read)(struct vpn_packet_t *);
|
bool (*read)(struct vpn_packet_t *packet);
|
||||||
bool (*write)(struct vpn_packet_t *);
|
bool (*write)(struct vpn_packet_t *packet);
|
||||||
void (*enable)(void); /* optional */
|
void (*dump_stats)(void);
|
||||||
void (*disable)(void); /* optional */
|
|
||||||
} devops_t;
|
} devops_t;
|
||||||
|
|
||||||
extern const devops_t os_devops;
|
extern const devops_t os_devops;
|
||||||
extern const devops_t dummy_devops;
|
extern const devops_t dummy_devops;
|
||||||
extern const devops_t raw_socket_devops;
|
extern const devops_t raw_socket_devops;
|
||||||
extern const devops_t multicast_devops;
|
extern const devops_t multicast_devops;
|
||||||
extern const devops_t fd_devops;
|
|
||||||
extern const devops_t uml_devops;
|
extern const devops_t uml_devops;
|
||||||
extern const devops_t vde_devops;
|
extern const devops_t vde_devops;
|
||||||
extern devops_t devops;
|
extern devops_t devops;
|
||||||
|
|
42
src/digest.h
42
src/digest.h
|
@ -1,42 +0,0 @@
|
||||||
#ifndef TINC_DIGEST_H
|
|
||||||
#define TINC_DIGEST_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
digest.h -- header file digest.c
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DIGEST_MAX_SIZE 64
|
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
|
|
||||||
typedef struct digest digest_t;
|
|
||||||
|
|
||||||
extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__((__malloc__));
|
|
||||||
extern digest_t *digest_open_by_nid(int nid, int maclength) __attribute__((__malloc__));
|
|
||||||
extern void digest_close(digest_t *digest);
|
|
||||||
extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *digestdata) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool digest_set_key(digest_t *digest, const void *key, size_t len) __attribute__((__warn_unused_result__));
|
|
||||||
extern int digest_get_nid(const digest_t *digest);
|
|
||||||
extern size_t digest_keylength(const digest_t *digest);
|
|
||||||
extern size_t digest_length(const digest_t *digest);
|
|
||||||
extern bool digest_active(const digest_t *digest);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
22
src/dropin.c
22
src/dropin.c
|
@ -107,6 +107,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
||||||
|
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
status = vsnprintf(*buf, len, fmt, aq);
|
status = vsnprintf(*buf, len, fmt, aq);
|
||||||
|
buf[len - 1] = 0;
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
|
|
||||||
if(status >= 0) {
|
if(status >= 0) {
|
||||||
|
@ -114,7 +115,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(status > len - 1) {
|
if(status > len - 1) {
|
||||||
len = status + 1;
|
len = status;
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
status = vsnprintf(*buf, len, fmt, aq);
|
status = vsnprintf(*buf, len, fmt, aq);
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
|
@ -126,25 +127,16 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
||||||
|
|
||||||
#ifndef HAVE_GETTIMEOFDAY
|
#ifndef HAVE_GETTIMEOFDAY
|
||||||
int gettimeofday(struct timeval *tv, void *tz) {
|
int gettimeofday(struct timeval *tv, void *tz) {
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
FILETIME ft;
|
|
||||||
GetSystemTimeAsFileTime(&ft);
|
|
||||||
uint64_t lt = (uint64_t)ft.dwLowDateTime | ((uint64_t)ft.dwHighDateTime << 32);
|
|
||||||
lt -= 116444736000000000ULL;
|
|
||||||
tv->tv_sec = lt / 10000000;
|
|
||||||
tv->tv_usec = (lt / 10) % 1000000;
|
|
||||||
#else
|
|
||||||
#warning No high resolution time source!
|
|
||||||
tv->tv_sec = time(NULL);
|
tv->tv_sec = time(NULL);
|
||||||
tv->tv_usec = 0;
|
tv->tv_usec = 0;
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_NANOSLEEP
|
#ifndef HAVE_USLEEP
|
||||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
int usleep(long long usec) {
|
||||||
struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
|
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
|
||||||
return select(0, NULL, NULL, NULL, &tv);
|
select(0, NULL, NULL, NULL, &tv);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
50
src/dropin.h
50
src/dropin.h
|
@ -4,7 +4,7 @@
|
||||||
/*
|
/*
|
||||||
dropin.h -- header file for dropin.c
|
dropin.h -- header file for dropin.c
|
||||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,50 +21,28 @@
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "fake-getaddrinfo.h"
|
||||||
|
#include "fake-getnameinfo.h"
|
||||||
|
|
||||||
#ifndef HAVE_DAEMON
|
#ifndef HAVE_DAEMON
|
||||||
extern int daemon(int, int);
|
extern int daemon(int nochdir, int noclose);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||||
|
extern char *get_current_dir_name(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_ASPRINTF
|
#ifndef HAVE_ASPRINTF
|
||||||
extern int asprintf(char **, const char *, ...);
|
extern int asprintf(char **buf, const char *fmt, ...);
|
||||||
extern int vasprintf(char **, const char *, va_list ap);
|
extern int vasprintf(char **buf, const char *fmt, va_list ap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_GETTIMEOFDAY
|
#ifndef HAVE_GETTIMEOFDAY
|
||||||
extern int gettimeofday(struct timeval *, void *);
|
extern int gettimeofday(struct timeval *tv, void *tz);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_NANOSLEEP
|
#ifndef HAVE_USLEEP
|
||||||
extern int nanosleep(const struct timespec *req, struct timespec *rem);
|
extern int usleep(long long usec);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef timeradd
|
|
||||||
#define timeradd(a, b, r) do {\
|
|
||||||
(r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
|
|
||||||
(r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
|
|
||||||
if((r)->tv_usec >= 1000000)\
|
|
||||||
(r)->tv_sec++, (r)->tv_usec -= 1000000;\
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef timersub
|
|
||||||
#define timersub(a, b, r) do {\
|
|
||||||
(r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
|
|
||||||
(r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
|
|
||||||
if((r)->tv_usec < 0)\
|
|
||||||
(r)->tv_sec--, (r)->tv_usec += 1000000;\
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
#define mkdir(a, b) mkdir(a)
|
|
||||||
#ifndef SHUT_RDWR
|
|
||||||
#define SHUT_RDWR SD_BOTH
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EAI_SYSTEM
|
|
||||||
#define EAI_SYSTEM 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
device.c -- Dummy device
|
device.c -- Dummy device
|
||||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,14 +26,19 @@
|
||||||
|
|
||||||
static const char *device_info = "dummy device";
|
static const char *device_info = "dummy device";
|
||||||
|
|
||||||
|
static uint64_t device_total_in = 0;
|
||||||
|
static uint64_t device_total_out = 0;
|
||||||
|
|
||||||
static bool setup_device(void) {
|
static bool setup_device(void) {
|
||||||
device = xstrdup("dummy");
|
device = xstrdup("dummy");
|
||||||
iface = xstrdup("dummy");
|
iface = xstrdup("dummy");
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_device(void) {
|
static void close_device(void) {
|
||||||
|
free(device);
|
||||||
|
free(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_packet(vpn_packet_t *packet) {
|
static bool read_packet(vpn_packet_t *packet) {
|
||||||
|
@ -42,13 +47,20 @@ static bool read_packet(vpn_packet_t *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_packet(vpn_packet_t *packet) {
|
static bool write_packet(vpn_packet_t *packet) {
|
||||||
(void)packet;
|
device_total_out += packet->len;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_device_stats(void) {
|
||||||
|
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||||
|
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||||
|
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||||
|
}
|
||||||
|
|
||||||
const devops_t dummy_devops = {
|
const devops_t dummy_devops = {
|
||||||
.setup = setup_device,
|
.setup = setup_device,
|
||||||
.close = close_device,
|
.close = close_device,
|
||||||
.read = read_packet,
|
.read = read_packet,
|
||||||
.write = write_packet,
|
.write = write_packet,
|
||||||
|
.dump_stats = dump_device_stats,
|
||||||
};
|
};
|
||||||
|
|
34
src/ecdh.h
34
src/ecdh.h
|
@ -1,34 +0,0 @@
|
||||||
#ifndef TINC_ECDH_H
|
|
||||||
#define TINC_ECDH_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
ecdh.h -- header file for ecdh.c
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ECDH_SIZE 32
|
|
||||||
#define ECDH_SHARED_SIZE 32
|
|
||||||
|
|
||||||
#ifndef TINC_ECDH_INTERNAL
|
|
||||||
typedef struct ecdh ecdh_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern ecdh_t *ecdh_generate_public(void *pubkey) __attribute__((__malloc__));
|
|
||||||
extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) __attribute__((__warn_unused_result__));
|
|
||||||
extern void ecdh_free(ecdh_t *ecdh);
|
|
||||||
|
|
||||||
#endif
|
|
37
src/ecdsa.h
37
src/ecdsa.h
|
@ -1,37 +0,0 @@
|
||||||
#ifndef TINC_ECDSA_H
|
|
||||||
#define TINC_ECDSA_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
ecdsa.h -- 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TINC_ECDSA_INTERNAL
|
|
||||||
typedef struct ecdsa ecdsa_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) __attribute__((__malloc__));
|
|
||||||
extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
|
|
||||||
extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) __attribute__((__malloc__));
|
|
||||||
extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) __attribute__((__malloc__));
|
|
||||||
extern size_t ecdsa_size(ecdsa_t *ecdsa);
|
|
||||||
extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool ecdsa_active(ecdsa_t *ecdsa);
|
|
||||||
extern void ecdsa_free(ecdsa_t *ecdsa);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,29 +0,0 @@
|
||||||
#ifndef TINC_ECDSAGEN_H
|
|
||||||
#define TINC_ECDSAGEN_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
ecdsagen.h -- 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 "ecdsa.h"
|
|
||||||
|
|
||||||
extern ecdsa_t *ecdsa_generate(void) __attribute__((__malloc__));
|
|
||||||
extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
|
|
||||||
extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
ecdh.c -- Diffie-Hellman key exchange 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 "ed25519.h"
|
|
||||||
|
|
||||||
#define TINC_ECDH_INTERNAL
|
|
||||||
typedef struct ecdh_t {
|
|
||||||
uint8_t private[64];
|
|
||||||
} ecdh_t;
|
|
||||||
|
|
||||||
#include "../crypto.h"
|
|
||||||
#include "../ecdh.h"
|
|
||||||
#include "../xalloc.h"
|
|
||||||
|
|
||||||
ecdh_t *ecdh_generate_public(void *pubkey) {
|
|
||||||
ecdh_t *ecdh = xzalloc(sizeof(*ecdh));
|
|
||||||
|
|
||||||
uint8_t seed[32];
|
|
||||||
randomize(seed, sizeof(seed));
|
|
||||||
ed25519_create_keypair(pubkey, ecdh->private, seed);
|
|
||||||
|
|
||||||
return ecdh;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
|
||||||
ed25519_key_exchange(shared, pubkey, ecdh->private);
|
|
||||||
free(ecdh);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ecdh_free(ecdh_t *ecdh) {
|
|
||||||
free(ecdh);
|
|
||||||
}
|
|
|
@ -1,168 +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 "ed25519.h"
|
|
||||||
|
|
||||||
#define TINC_ECDSA_INTERNAL
|
|
||||||
typedef struct {
|
|
||||||
uint8_t private[64];
|
|
||||||
uint8_t public[32];
|
|
||||||
} ecdsa_t;
|
|
||||||
|
|
||||||
#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) {
|
|
||||||
int len = strlen(p);
|
|
||||||
|
|
||||||
if(len != 43) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid size %d for public key!", len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
|
||||||
len = b64decode(p, ecdsa->public, len);
|
|
||||||
|
|
||||||
if(len != 32) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid format of public key! len = %d", len);
|
|
||||||
free(ecdsa);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ecdsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
|
||||||
char *base64 = xmalloc(44);
|
|
||||||
b64encode(ecdsa->public, base64, sizeof(ecdsa->public));
|
|
||||||
|
|
||||||
return base64;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read PEM ECDSA keys
|
|
||||||
|
|
||||||
static bool read_pem(FILE *fp, const char *type, void *vbuf, size_t size) {
|
|
||||||
char line[1024];
|
|
||||||
bool data = false;
|
|
||||||
size_t typelen = strlen(type);
|
|
||||||
char *buf = vbuf;
|
|
||||||
|
|
||||||
while(fgets(line, sizeof(line), fp)) {
|
|
||||||
if(!data) {
|
|
||||||
if(strncmp(line, "-----BEGIN ", 11)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strncmp(line + 11, type, typelen)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strncmp(line, "-----END ", 9)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t linelen = strcspn(line, "\r\n");
|
|
||||||
size_t len = b64decode(line, line, linelen);
|
|
||||||
|
|
||||||
if(!len) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n");
|
|
||||||
errno = EINVAL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(len > size) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n");
|
|
||||||
errno = EINVAL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buf, line, len);
|
|
||||||
buf += len;
|
|
||||||
size -= len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size) {
|
|
||||||
if(data) {
|
|
||||||
errno = EINVAL;
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n");
|
|
||||||
} else {
|
|
||||||
errno = ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
|
|
||||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
|
||||||
|
|
||||||
if(read_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public))) {
|
|
||||||
return ecdsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ecdsa);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
|
|
||||||
ecdsa_t *ecdsa = xmalloc(sizeof(*ecdsa));
|
|
||||||
|
|
||||||
if(read_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa))) {
|
|
||||||
return ecdsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ecdsa);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
|
||||||
(void)ecdsa;
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: standardise output format?
|
|
||||||
|
|
||||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
|
||||||
ed25519_sign(sig, in, len, ecdsa->public, ecdsa->private);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
|
||||||
return ed25519_verify(sig, in, len, ecdsa->public);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
|
||||||
return ecdsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
|
||||||
free(ecdsa);
|
|
||||||
}
|
|
|
@ -1,73 +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 "ed25519.h"
|
|
||||||
|
|
||||||
#define TINC_ECDSA_INTERNAL
|
|
||||||
typedef struct {
|
|
||||||
uint8_t private[64];
|
|
||||||
uint8_t public[32];
|
|
||||||
} ecdsa_t;
|
|
||||||
|
|
||||||
#include "../crypto.h"
|
|
||||||
#include "../ecdsagen.h"
|
|
||||||
#include "../utils.h"
|
|
||||||
#include "../xalloc.h"
|
|
||||||
|
|
||||||
// Generate ECDSA key
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa_generate(void) {
|
|
||||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
|
||||||
|
|
||||||
uint8_t seed[32];
|
|
||||||
randomize(seed, sizeof(seed));
|
|
||||||
ed25519_create_keypair(ecdsa->public, ecdsa->private, seed);
|
|
||||||
|
|
||||||
return ecdsa;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write PEM ECDSA keys
|
|
||||||
|
|
||||||
static bool write_pem(FILE *fp, const char *type, void *vbuf, size_t size) {
|
|
||||||
fprintf(fp, "-----BEGIN %s-----\n", type);
|
|
||||||
|
|
||||||
char *buf = vbuf;
|
|
||||||
char base64[65];
|
|
||||||
|
|
||||||
while(size) {
|
|
||||||
size_t todo = size > 48 ? 48 : size;
|
|
||||||
b64encode(buf, base64, todo);
|
|
||||||
fprintf(fp, "%s\n", base64);
|
|
||||||
buf += todo;
|
|
||||||
size -= todo;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "-----END %s-----\n", type);
|
|
||||||
return !ferror(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
|
||||||
return write_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
|
||||||
return write_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa));
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
#ifndef ED25519_H
|
|
||||||
#define ED25519_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#if defined(ED25519_BUILD_DLL)
|
|
||||||
#define ED25519_DECLSPEC __declspec(dllexport)
|
|
||||||
#elif defined(ED25519_DLL)
|
|
||||||
#define ED25519_DECLSPEC __declspec(dllimport)
|
|
||||||
#else
|
|
||||||
#define ED25519_DECLSPEC
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define ED25519_DECLSPEC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ED25519_NO_SEED
|
|
||||||
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
|
||||||
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
|
||||||
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);
|
|
||||||
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
1511
src/ed25519/fe.c
1511
src/ed25519/fe.c
File diff suppressed because it is too large
Load diff
|
@ -1,41 +0,0 @@
|
||||||
#ifndef FE_H
|
|
||||||
#define FE_H
|
|
||||||
|
|
||||||
#include "fixedint.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
fe means field element.
|
|
||||||
Here the field is \Z/(2^255-19).
|
|
||||||
An element t, entries t[0]...t[9], represents the integer
|
|
||||||
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
|
|
||||||
Bounds on each t[i] vary depending on context.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
typedef int32_t fe[10];
|
|
||||||
|
|
||||||
|
|
||||||
void fe_0(fe h);
|
|
||||||
void fe_1(fe h);
|
|
||||||
|
|
||||||
void fe_frombytes(fe h, const unsigned char *s);
|
|
||||||
void fe_tobytes(unsigned char *s, const fe h);
|
|
||||||
|
|
||||||
void fe_copy(fe h, const fe f);
|
|
||||||
int fe_isnegative(const fe f);
|
|
||||||
int fe_isnonzero(const fe f);
|
|
||||||
void fe_cmov(fe f, const fe g, unsigned int b);
|
|
||||||
void fe_cswap(fe f, fe g, unsigned int b);
|
|
||||||
|
|
||||||
void fe_neg(fe h, const fe f);
|
|
||||||
void fe_add(fe h, const fe f, const fe g);
|
|
||||||
void fe_invert(fe out, const fe z);
|
|
||||||
void fe_sq(fe h, const fe f);
|
|
||||||
void fe_sq2(fe h, const fe f);
|
|
||||||
void fe_mul(fe h, const fe f, const fe g);
|
|
||||||
void fe_mul121666(fe h, fe f);
|
|
||||||
void fe_pow22523(fe out, const fe z);
|
|
||||||
void fe_sub(fe h, const fe f, const fe g);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,91 +0,0 @@
|
||||||
#ifndef TINC_FIXEDINT_H
|
|
||||||
#define TINC_FIXEDINT_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
Portable header to provide the 32 and 64 bits type.
|
|
||||||
|
|
||||||
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
|
|
||||||
#include <stdint.h>
|
|
||||||
#define FIXEDINT_H_INCLUDED
|
|
||||||
|
|
||||||
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
|
||||||
#include <limits.h>
|
|
||||||
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef FIXEDINT_H_INCLUDED
|
|
||||||
#define FIXEDINT_H_INCLUDED
|
|
||||||
|
|
||||||
/* (u)int32_t */
|
|
||||||
#ifndef uint32_t
|
|
||||||
#if (ULONG_MAX == 0xffffffffUL)
|
|
||||||
typedef unsigned long uint32_t;
|
|
||||||
#elif (UINT_MAX == 0xffffffffUL)
|
|
||||||
typedef unsigned int uint32_t;
|
|
||||||
#elif (USHRT_MAX == 0xffffffffUL)
|
|
||||||
typedef unsigned short uint32_t;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef int32_t
|
|
||||||
#if (LONG_MAX == 0x7fffffffL)
|
|
||||||
typedef signed long int32_t;
|
|
||||||
#elif (INT_MAX == 0x7fffffffL)
|
|
||||||
typedef signed int int32_t;
|
|
||||||
#elif (SHRT_MAX == 0x7fffffffL)
|
|
||||||
typedef signed short int32_t;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* (u)int64_t */
|
|
||||||
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
|
||||||
typedef long long int64_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
|
|
||||||
#define UINT64_C(v) v ##ULL
|
|
||||||
#define INT64_C(v) v ##LL
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
__extension__ typedef long long int64_t;
|
|
||||||
__extension__ typedef unsigned long long uint64_t;
|
|
||||||
|
|
||||||
#define UINT64_C(v) v ##ULL
|
|
||||||
#define INT64_C(v) v ##LL
|
|
||||||
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
|
||||||
typedef long long int64_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
|
|
||||||
#define UINT64_C(v) v ##ULL
|
|
||||||
#define INT64_C(v) v ##LL
|
|
||||||
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
|
||||||
typedef __int64 int64_t;
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
|
|
||||||
#define UINT64_C(v) v ##UI64
|
|
||||||
#define INT64_C(v) v ##I64
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline unsigned char shlu8(unsigned char a, uint32_t b) {
|
|
||||||
return a << b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int32_t shl32(uint32_t a, uint32_t b) {
|
|
||||||
return a << b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int64_t shl64(uint64_t a, uint32_t b) {
|
|
||||||
return a << b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64_t shlu64(uint64_t a, uint32_t b) {
|
|
||||||
return a << b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
467
src/ed25519/ge.c
467
src/ed25519/ge.c
|
@ -1,467 +0,0 @@
|
||||||
#include "ge.h"
|
|
||||||
#include "precomp_data.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p + q
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
|
||||||
fe t0;
|
|
||||||
fe_add(r->X, p->Y, p->X);
|
|
||||||
fe_sub(r->Y, p->Y, p->X);
|
|
||||||
fe_mul(r->Z, r->X, q->YplusX);
|
|
||||||
fe_mul(r->Y, r->Y, q->YminusX);
|
|
||||||
fe_mul(r->T, q->T2d, p->T);
|
|
||||||
fe_mul(r->X, p->Z, q->Z);
|
|
||||||
fe_add(t0, r->X, r->X);
|
|
||||||
fe_sub(r->X, r->Z, r->Y);
|
|
||||||
fe_add(r->Y, r->Z, r->Y);
|
|
||||||
fe_add(r->Z, t0, r->T);
|
|
||||||
fe_sub(r->T, t0, r->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void slide(signed char *r, const unsigned char *a) {
|
|
||||||
int i;
|
|
||||||
int b;
|
|
||||||
int k;
|
|
||||||
|
|
||||||
for(i = 0; i < 256; ++i) {
|
|
||||||
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < 256; ++i)
|
|
||||||
if(r[i]) {
|
|
||||||
for(b = 1; b <= 6 && i + b < 256; ++b) {
|
|
||||||
if(r[i + b]) {
|
|
||||||
if(r[i] + (r[i + b] << b) <= 15) {
|
|
||||||
r[i] += r[i + b] << b;
|
|
||||||
r[i + b] = 0;
|
|
||||||
} else if(r[i] - (r[i + b] << b) >= -15) {
|
|
||||||
r[i] -= r[i + b] << b;
|
|
||||||
|
|
||||||
for(k = i + b; k < 256; ++k) {
|
|
||||||
if(!r[k]) {
|
|
||||||
r[k] = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r[k] = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = a * A + b * B
|
|
||||||
where a = a[0]+256*a[1]+...+256^31 a[31].
|
|
||||||
and b = b[0]+256*b[1]+...+256^31 b[31].
|
|
||||||
B is the Ed25519 base point (x,4/5) with x positive.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
|
||||||
signed char aslide[256];
|
|
||||||
signed char bslide[256];
|
|
||||||
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
|
||||||
ge_p1p1 t;
|
|
||||||
ge_p3 u;
|
|
||||||
ge_p3 A2;
|
|
||||||
int i;
|
|
||||||
slide(aslide, a);
|
|
||||||
slide(bslide, b);
|
|
||||||
ge_p3_to_cached(&Ai[0], A);
|
|
||||||
ge_p3_dbl(&t, A);
|
|
||||||
ge_p1p1_to_p3(&A2, &t);
|
|
||||||
ge_add(&t, &A2, &Ai[0]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[1], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[1]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[2], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[2]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[3], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[3]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[4], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[4]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[5], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[5]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[6], &u);
|
|
||||||
ge_add(&t, &A2, &Ai[6]);
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_p3_to_cached(&Ai[7], &u);
|
|
||||||
ge_p2_0(r);
|
|
||||||
|
|
||||||
for(i = 255; i >= 0; --i) {
|
|
||||||
if(aslide[i] || bslide[i]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(; i >= 0; --i) {
|
|
||||||
ge_p2_dbl(&t, r);
|
|
||||||
|
|
||||||
if(aslide[i] > 0) {
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
|
||||||
} else if(aslide[i] < 0) {
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bslide[i] > 0) {
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
|
||||||
} else if(bslide[i] < 0) {
|
|
||||||
ge_p1p1_to_p3(&u, &t);
|
|
||||||
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ge_p1p1_to_p2(r, &t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const fe d = {
|
|
||||||
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
|
||||||
};
|
|
||||||
|
|
||||||
static const fe sqrtm1 = {
|
|
||||||
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
|
||||||
};
|
|
||||||
|
|
||||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
|
||||||
fe u;
|
|
||||||
fe v;
|
|
||||||
fe v3;
|
|
||||||
fe vxx;
|
|
||||||
fe check;
|
|
||||||
fe_frombytes(h->Y, s);
|
|
||||||
fe_1(h->Z);
|
|
||||||
fe_sq(u, h->Y);
|
|
||||||
fe_mul(v, u, d);
|
|
||||||
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
|
||||||
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
|
||||||
fe_sq(v3, v);
|
|
||||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
|
||||||
fe_sq(h->X, v3);
|
|
||||||
fe_mul(h->X, h->X, v);
|
|
||||||
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
|
||||||
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
|
||||||
fe_mul(h->X, h->X, v3);
|
|
||||||
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
|
||||||
fe_sq(vxx, h->X);
|
|
||||||
fe_mul(vxx, vxx, v);
|
|
||||||
fe_sub(check, vxx, u); /* vx^2-u */
|
|
||||||
|
|
||||||
if(fe_isnonzero(check)) {
|
|
||||||
fe_add(check, vxx, u); /* vx^2+u */
|
|
||||||
|
|
||||||
if(fe_isnonzero(check)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fe_mul(h->X, h->X, sqrtm1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fe_isnegative(h->X) == (s[31] >> 7)) {
|
|
||||||
fe_neg(h->X, h->X);
|
|
||||||
}
|
|
||||||
|
|
||||||
fe_mul(h->T, h->X, h->Y);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p + q
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
|
||||||
fe t0;
|
|
||||||
fe_add(r->X, p->Y, p->X);
|
|
||||||
fe_sub(r->Y, p->Y, p->X);
|
|
||||||
fe_mul(r->Z, r->X, q->yplusx);
|
|
||||||
fe_mul(r->Y, r->Y, q->yminusx);
|
|
||||||
fe_mul(r->T, q->xy2d, p->T);
|
|
||||||
fe_add(t0, p->Z, p->Z);
|
|
||||||
fe_sub(r->X, r->Z, r->Y);
|
|
||||||
fe_add(r->Y, r->Z, r->Y);
|
|
||||||
fe_add(r->Z, t0, r->T);
|
|
||||||
fe_sub(r->T, t0, r->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p - q
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
|
||||||
fe t0;
|
|
||||||
|
|
||||||
fe_add(r->X, p->Y, p->X);
|
|
||||||
fe_sub(r->Y, p->Y, p->X);
|
|
||||||
fe_mul(r->Z, r->X, q->yminusx);
|
|
||||||
fe_mul(r->Y, r->Y, q->yplusx);
|
|
||||||
fe_mul(r->T, q->xy2d, p->T);
|
|
||||||
fe_add(t0, p->Z, p->Z);
|
|
||||||
fe_sub(r->X, r->Z, r->Y);
|
|
||||||
fe_add(r->Y, r->Z, r->Y);
|
|
||||||
fe_sub(r->Z, t0, r->T);
|
|
||||||
fe_add(r->T, t0, r->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
|
||||||
fe_mul(r->X, p->X, p->T);
|
|
||||||
fe_mul(r->Y, p->Y, p->Z);
|
|
||||||
fe_mul(r->Z, p->Z, p->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
|
||||||
fe_mul(r->X, p->X, p->T);
|
|
||||||
fe_mul(r->Y, p->Y, p->Z);
|
|
||||||
fe_mul(r->Z, p->Z, p->T);
|
|
||||||
fe_mul(r->T, p->X, p->Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ge_p2_0(ge_p2 *h) {
|
|
||||||
fe_0(h->X);
|
|
||||||
fe_1(h->Y);
|
|
||||||
fe_1(h->Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = 2 * p
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
|
||||||
fe t0;
|
|
||||||
|
|
||||||
fe_sq(r->X, p->X);
|
|
||||||
fe_sq(r->Z, p->Y);
|
|
||||||
fe_sq2(r->T, p->Z);
|
|
||||||
fe_add(r->Y, p->X, p->Y);
|
|
||||||
fe_sq(t0, r->Y);
|
|
||||||
fe_add(r->Y, r->Z, r->X);
|
|
||||||
fe_sub(r->Z, r->Z, r->X);
|
|
||||||
fe_sub(r->X, t0, r->Y);
|
|
||||||
fe_sub(r->T, r->T, r->Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ge_p3_0(ge_p3 *h) {
|
|
||||||
fe_0(h->X);
|
|
||||||
fe_1(h->Y);
|
|
||||||
fe_1(h->Z);
|
|
||||||
fe_0(h->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = 2 * p
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
|
||||||
ge_p2 q;
|
|
||||||
ge_p3_to_p2(&q, p);
|
|
||||||
ge_p2_dbl(r, &q);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const fe d2 = {
|
|
||||||
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
|
||||||
};
|
|
||||||
|
|
||||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
|
||||||
fe_add(r->YplusX, p->Y, p->X);
|
|
||||||
fe_sub(r->YminusX, p->Y, p->X);
|
|
||||||
fe_copy(r->Z, p->Z);
|
|
||||||
fe_mul(r->T2d, p->T, d2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
|
||||||
fe_copy(r->X, p->X);
|
|
||||||
fe_copy(r->Y, p->Y);
|
|
||||||
fe_copy(r->Z, p->Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
|
||||||
fe recip;
|
|
||||||
fe x;
|
|
||||||
fe y;
|
|
||||||
fe_invert(recip, h->Z);
|
|
||||||
fe_mul(x, h->X, recip);
|
|
||||||
fe_mul(y, h->Y, recip);
|
|
||||||
fe_tobytes(s, y);
|
|
||||||
s[31] ^= fe_isnegative(x) << 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned char equal(signed char b, signed char c) {
|
|
||||||
unsigned char ub = b;
|
|
||||||
unsigned char uc = c;
|
|
||||||
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
|
||||||
uint64_t y = x; /* 0: yes; 1..255: no */
|
|
||||||
y -= 1; /* large: yes; 0..254: no */
|
|
||||||
y >>= 63; /* 1: yes; 0: no */
|
|
||||||
return (unsigned char) y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char negative(signed char b) {
|
|
||||||
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
|
||||||
x >>= 63; /* 1: yes; 0: no */
|
|
||||||
return (unsigned char) x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
|
|
||||||
fe_cmov(t->yplusx, u->yplusx, b);
|
|
||||||
fe_cmov(t->yminusx, u->yminusx, b);
|
|
||||||
fe_cmov(t->xy2d, u->xy2d, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void select(ge_precomp *t, int pos, signed char b) {
|
|
||||||
ge_precomp minust;
|
|
||||||
unsigned char bnegative = negative(b);
|
|
||||||
unsigned char babs = b - shlu8(((-bnegative) & b), 1);
|
|
||||||
fe_1(t->yplusx);
|
|
||||||
fe_1(t->yminusx);
|
|
||||||
fe_0(t->xy2d);
|
|
||||||
cmov(t, &base[pos][0], equal(babs, 1));
|
|
||||||
cmov(t, &base[pos][1], equal(babs, 2));
|
|
||||||
cmov(t, &base[pos][2], equal(babs, 3));
|
|
||||||
cmov(t, &base[pos][3], equal(babs, 4));
|
|
||||||
cmov(t, &base[pos][4], equal(babs, 5));
|
|
||||||
cmov(t, &base[pos][5], equal(babs, 6));
|
|
||||||
cmov(t, &base[pos][6], equal(babs, 7));
|
|
||||||
cmov(t, &base[pos][7], equal(babs, 8));
|
|
||||||
fe_copy(minust.yplusx, t->yminusx);
|
|
||||||
fe_copy(minust.yminusx, t->yplusx);
|
|
||||||
fe_neg(minust.xy2d, t->xy2d);
|
|
||||||
cmov(t, &minust, bnegative);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
h = a * B
|
|
||||||
where a = a[0]+256*a[1]+...+256^31 a[31]
|
|
||||||
B is the Ed25519 base point (x,4/5) with x positive.
|
|
||||||
|
|
||||||
Preconditions:
|
|
||||||
a[31] <= 127
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
|
||||||
signed char e[64];
|
|
||||||
signed char carry;
|
|
||||||
ge_p1p1 r;
|
|
||||||
ge_p2 s;
|
|
||||||
ge_precomp t;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < 32; ++i) {
|
|
||||||
e[2 * i + 0] = (a[i] >> 0) & 15;
|
|
||||||
e[2 * i + 1] = (a[i] >> 4) & 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* each e[i] is between 0 and 15 */
|
|
||||||
/* e[63] is between 0 and 7 */
|
|
||||||
carry = 0;
|
|
||||||
|
|
||||||
for(i = 0; i < 63; ++i) {
|
|
||||||
e[i] += carry;
|
|
||||||
carry = e[i] + 8;
|
|
||||||
carry >>= 4;
|
|
||||||
e[i] -= shl32(carry, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
e[63] += carry;
|
|
||||||
/* each e[i] is between -8 and 8 */
|
|
||||||
ge_p3_0(h);
|
|
||||||
|
|
||||||
for(i = 1; i < 64; i += 2) {
|
|
||||||
select(&t, i / 2, e[i]);
|
|
||||||
ge_madd(&r, h, &t);
|
|
||||||
ge_p1p1_to_p3(h, &r);
|
|
||||||
}
|
|
||||||
|
|
||||||
ge_p3_dbl(&r, h);
|
|
||||||
ge_p1p1_to_p2(&s, &r);
|
|
||||||
ge_p2_dbl(&r, &s);
|
|
||||||
ge_p1p1_to_p2(&s, &r);
|
|
||||||
ge_p2_dbl(&r, &s);
|
|
||||||
ge_p1p1_to_p2(&s, &r);
|
|
||||||
ge_p2_dbl(&r, &s);
|
|
||||||
ge_p1p1_to_p3(h, &r);
|
|
||||||
|
|
||||||
for(i = 0; i < 64; i += 2) {
|
|
||||||
select(&t, i / 2, e[i]);
|
|
||||||
ge_madd(&r, h, &t);
|
|
||||||
ge_p1p1_to_p3(h, &r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
r = p - q
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
|
||||||
fe t0;
|
|
||||||
|
|
||||||
fe_add(r->X, p->Y, p->X);
|
|
||||||
fe_sub(r->Y, p->Y, p->X);
|
|
||||||
fe_mul(r->Z, r->X, q->YminusX);
|
|
||||||
fe_mul(r->Y, r->Y, q->YplusX);
|
|
||||||
fe_mul(r->T, q->T2d, p->T);
|
|
||||||
fe_mul(r->X, p->Z, q->Z);
|
|
||||||
fe_add(t0, r->X, r->X);
|
|
||||||
fe_sub(r->X, r->Z, r->Y);
|
|
||||||
fe_add(r->Y, r->Z, r->Y);
|
|
||||||
fe_sub(r->Z, t0, r->T);
|
|
||||||
fe_add(r->T, t0, r->T);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
|
||||||
fe recip;
|
|
||||||
fe x;
|
|
||||||
fe y;
|
|
||||||
fe_invert(recip, h->Z);
|
|
||||||
fe_mul(x, h->X, recip);
|
|
||||||
fe_mul(y, h->Y, recip);
|
|
||||||
fe_tobytes(s, y);
|
|
||||||
s[31] ^= fe_isnegative(x) << 7;
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
#ifndef GE_H
|
|
||||||
#define GE_H
|
|
||||||
|
|
||||||
#include "fe.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ge means group element.
|
|
||||||
|
|
||||||
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
|
||||||
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
|
||||||
where d = -121665/121666.
|
|
||||||
|
|
||||||
Representations:
|
|
||||||
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
|
||||||
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
|
||||||
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
|
||||||
ge_precomp (Duif): (y+x,y-x,2dxy)
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fe X;
|
|
||||||
fe Y;
|
|
||||||
fe Z;
|
|
||||||
} ge_p2;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fe X;
|
|
||||||
fe Y;
|
|
||||||
fe Z;
|
|
||||||
fe T;
|
|
||||||
} ge_p3;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fe X;
|
|
||||||
fe Y;
|
|
||||||
fe Z;
|
|
||||||
fe T;
|
|
||||||
} ge_p1p1;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fe yplusx;
|
|
||||||
fe yminusx;
|
|
||||||
fe xy2d;
|
|
||||||
} ge_precomp;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fe YplusX;
|
|
||||||
fe YminusX;
|
|
||||||
fe Z;
|
|
||||||
fe T2d;
|
|
||||||
} ge_cached;
|
|
||||||
|
|
||||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
|
||||||
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
|
||||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
|
||||||
|
|
||||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
|
||||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
|
||||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
|
||||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
|
||||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
|
||||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
|
||||||
|
|
||||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
|
||||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
|
||||||
void ge_p2_0(ge_p2 *h);
|
|
||||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
|
||||||
void ge_p3_0(ge_p3 *h);
|
|
||||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
|
||||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
|
||||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,80 +0,0 @@
|
||||||
#include "ed25519.h"
|
|
||||||
#include "fe.h"
|
|
||||||
|
|
||||||
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
|
||||||
unsigned char e[32];
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
fe x1;
|
|
||||||
fe x2;
|
|
||||||
fe z2;
|
|
||||||
fe x3;
|
|
||||||
fe z3;
|
|
||||||
fe tmp0;
|
|
||||||
fe tmp1;
|
|
||||||
|
|
||||||
int pos;
|
|
||||||
unsigned int swap;
|
|
||||||
unsigned int b;
|
|
||||||
|
|
||||||
/* copy the private key and make sure it's valid */
|
|
||||||
for(i = 0; i < 32; ++i) {
|
|
||||||
e[i] = private_key[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
e[0] &= 248;
|
|
||||||
e[31] &= 63;
|
|
||||||
e[31] |= 64;
|
|
||||||
|
|
||||||
/* unpack the public key and convert edwards to montgomery */
|
|
||||||
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
|
||||||
fe_frombytes(x1, public_key);
|
|
||||||
fe_1(tmp1);
|
|
||||||
fe_add(tmp0, x1, tmp1);
|
|
||||||
fe_sub(tmp1, tmp1, x1);
|
|
||||||
fe_invert(tmp1, tmp1);
|
|
||||||
fe_mul(x1, tmp0, tmp1);
|
|
||||||
|
|
||||||
fe_1(x2);
|
|
||||||
fe_0(z2);
|
|
||||||
fe_copy(x3, x1);
|
|
||||||
fe_1(z3);
|
|
||||||
|
|
||||||
swap = 0;
|
|
||||||
|
|
||||||
for(pos = 254; pos >= 0; --pos) {
|
|
||||||
b = e[pos / 8] >> (pos & 7);
|
|
||||||
b &= 1;
|
|
||||||
swap ^= b;
|
|
||||||
fe_cswap(x2, x3, swap);
|
|
||||||
fe_cswap(z2, z3, swap);
|
|
||||||
swap = b;
|
|
||||||
|
|
||||||
/* from montgomery.h */
|
|
||||||
fe_sub(tmp0, x3, z3);
|
|
||||||
fe_sub(tmp1, x2, z2);
|
|
||||||
fe_add(x2, x2, z2);
|
|
||||||
fe_add(z2, x3, z3);
|
|
||||||
fe_mul(z3, tmp0, x2);
|
|
||||||
fe_mul(z2, z2, tmp1);
|
|
||||||
fe_sq(tmp0, tmp1);
|
|
||||||
fe_sq(tmp1, x2);
|
|
||||||
fe_add(x3, z3, z2);
|
|
||||||
fe_sub(z2, z3, z2);
|
|
||||||
fe_mul(x2, tmp1, tmp0);
|
|
||||||
fe_sub(tmp1, tmp1, tmp0);
|
|
||||||
fe_sq(z2, z2);
|
|
||||||
fe_mul121666(z3, tmp1);
|
|
||||||
fe_sq(x3, x3);
|
|
||||||
fe_add(tmp0, tmp0, z3);
|
|
||||||
fe_mul(z3, x1, z2);
|
|
||||||
fe_mul(z2, tmp1, tmp0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fe_cswap(x2, x3, swap);
|
|
||||||
fe_cswap(z2, z3, swap);
|
|
||||||
|
|
||||||
fe_invert(z2, z2);
|
|
||||||
fe_mul(x2, x2, z2);
|
|
||||||
fe_tobytes(shared_secret, x2);
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#include "ed25519.h"
|
|
||||||
#include "sha512.h"
|
|
||||||
#include "ge.h"
|
|
||||||
|
|
||||||
|
|
||||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
|
||||||
ge_p3 A;
|
|
||||||
|
|
||||||
sha512(seed, 32, private_key);
|
|
||||||
private_key[0] &= 248;
|
|
||||||
private_key[31] &= 63;
|
|
||||||
private_key[31] |= 64;
|
|
||||||
|
|
||||||
ge_scalarmult_base(&A, private_key);
|
|
||||||
ge_p3_tobytes(public_key, &A);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
785
src/ed25519/sc.c
785
src/ed25519/sc.c
|
@ -1,785 +0,0 @@
|
||||||
#include "fixedint.h"
|
|
||||||
#include "sc.h"
|
|
||||||
|
|
||||||
static uint64_t load_3(const unsigned char *in) {
|
|
||||||
uint64_t result;
|
|
||||||
|
|
||||||
result = in[0];
|
|
||||||
result |= shlu64(in[1], 8);
|
|
||||||
result |= shlu64(in[2], 16);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t load_4(const unsigned char *in) {
|
|
||||||
uint64_t result;
|
|
||||||
|
|
||||||
result = in[0];
|
|
||||||
result |= shlu64(in[1], 8);
|
|
||||||
result |= shlu64(in[2], 16);
|
|
||||||
result |= shlu64(in[3], 24);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Input:
|
|
||||||
s[0]+256*s[1]+...+256^63*s[63] = s
|
|
||||||
|
|
||||||
Output:
|
|
||||||
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
|
||||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
|
||||||
Overwrites s in place.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sc_reduce(unsigned char *s) {
|
|
||||||
int64_t s0 = 2097151 & load_3(s);
|
|
||||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
|
||||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
|
||||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
|
||||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
|
||||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
|
||||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
|
||||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
|
||||||
int64_t s8 = 2097151 & load_3(s + 21);
|
|
||||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
|
||||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
|
||||||
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
|
||||||
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
|
||||||
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
|
||||||
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
|
||||||
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
|
||||||
int64_t s16 = 2097151 & load_3(s + 42);
|
|
||||||
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
|
||||||
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
|
||||||
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
|
||||||
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
|
||||||
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
|
||||||
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
|
||||||
int64_t s23 = (load_4(s + 60) >> 3);
|
|
||||||
int64_t carry0;
|
|
||||||
int64_t carry1;
|
|
||||||
int64_t carry2;
|
|
||||||
int64_t carry3;
|
|
||||||
int64_t carry4;
|
|
||||||
int64_t carry5;
|
|
||||||
int64_t carry6;
|
|
||||||
int64_t carry7;
|
|
||||||
int64_t carry8;
|
|
||||||
int64_t carry9;
|
|
||||||
int64_t carry10;
|
|
||||||
int64_t carry11;
|
|
||||||
int64_t carry12;
|
|
||||||
int64_t carry13;
|
|
||||||
int64_t carry14;
|
|
||||||
int64_t carry15;
|
|
||||||
int64_t carry16;
|
|
||||||
|
|
||||||
s11 += s23 * 666643;
|
|
||||||
s12 += s23 * 470296;
|
|
||||||
s13 += s23 * 654183;
|
|
||||||
s14 -= s23 * 997805;
|
|
||||||
s15 += s23 * 136657;
|
|
||||||
s16 -= s23 * 683901;
|
|
||||||
s10 += s22 * 666643;
|
|
||||||
s11 += s22 * 470296;
|
|
||||||
s12 += s22 * 654183;
|
|
||||||
s13 -= s22 * 997805;
|
|
||||||
s14 += s22 * 136657;
|
|
||||||
s15 -= s22 * 683901;
|
|
||||||
s9 += s21 * 666643;
|
|
||||||
s10 += s21 * 470296;
|
|
||||||
s11 += s21 * 654183;
|
|
||||||
s12 -= s21 * 997805;
|
|
||||||
s13 += s21 * 136657;
|
|
||||||
s14 -= s21 * 683901;
|
|
||||||
s8 += s20 * 666643;
|
|
||||||
s9 += s20 * 470296;
|
|
||||||
s10 += s20 * 654183;
|
|
||||||
s11 -= s20 * 997805;
|
|
||||||
s12 += s20 * 136657;
|
|
||||||
s13 -= s20 * 683901;
|
|
||||||
s7 += s19 * 666643;
|
|
||||||
s8 += s19 * 470296;
|
|
||||||
s9 += s19 * 654183;
|
|
||||||
s10 -= s19 * 997805;
|
|
||||||
s11 += s19 * 136657;
|
|
||||||
s12 -= s19 * 683901;
|
|
||||||
s6 += s18 * 666643;
|
|
||||||
s7 += s18 * 470296;
|
|
||||||
s8 += s18 * 654183;
|
|
||||||
s9 -= s18 * 997805;
|
|
||||||
s10 += s18 * 136657;
|
|
||||||
s11 -= s18 * 683901;
|
|
||||||
carry6 = (s6 + (1 << 20)) >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry8 = (s8 + (1 << 20)) >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry10 = (s10 + (1 << 20)) >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry12 = (s12 + (1 << 20)) >> 21;
|
|
||||||
s13 += carry12;
|
|
||||||
s12 -= shl64(carry12, 21);
|
|
||||||
carry14 = (s14 + (1 << 20)) >> 21;
|
|
||||||
s15 += carry14;
|
|
||||||
s14 -= shl64(carry14, 21);
|
|
||||||
carry16 = (s16 + (1 << 20)) >> 21;
|
|
||||||
s17 += carry16;
|
|
||||||
s16 -= shl64(carry16, 21);
|
|
||||||
carry7 = (s7 + (1 << 20)) >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry9 = (s9 + (1 << 20)) >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry11 = (s11 + (1 << 20)) >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
carry13 = (s13 + (1 << 20)) >> 21;
|
|
||||||
s14 += carry13;
|
|
||||||
s13 -= shl64(carry13, 21);
|
|
||||||
carry15 = (s15 + (1 << 20)) >> 21;
|
|
||||||
s16 += carry15;
|
|
||||||
s15 -= shl64(carry15, 21);
|
|
||||||
s5 += s17 * 666643;
|
|
||||||
s6 += s17 * 470296;
|
|
||||||
s7 += s17 * 654183;
|
|
||||||
s8 -= s17 * 997805;
|
|
||||||
s9 += s17 * 136657;
|
|
||||||
s10 -= s17 * 683901;
|
|
||||||
s4 += s16 * 666643;
|
|
||||||
s5 += s16 * 470296;
|
|
||||||
s6 += s16 * 654183;
|
|
||||||
s7 -= s16 * 997805;
|
|
||||||
s8 += s16 * 136657;
|
|
||||||
s9 -= s16 * 683901;
|
|
||||||
s3 += s15 * 666643;
|
|
||||||
s4 += s15 * 470296;
|
|
||||||
s5 += s15 * 654183;
|
|
||||||
s6 -= s15 * 997805;
|
|
||||||
s7 += s15 * 136657;
|
|
||||||
s8 -= s15 * 683901;
|
|
||||||
s2 += s14 * 666643;
|
|
||||||
s3 += s14 * 470296;
|
|
||||||
s4 += s14 * 654183;
|
|
||||||
s5 -= s14 * 997805;
|
|
||||||
s6 += s14 * 136657;
|
|
||||||
s7 -= s14 * 683901;
|
|
||||||
s1 += s13 * 666643;
|
|
||||||
s2 += s13 * 470296;
|
|
||||||
s3 += s13 * 654183;
|
|
||||||
s4 -= s13 * 997805;
|
|
||||||
s5 += s13 * 136657;
|
|
||||||
s6 -= s13 * 683901;
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
s12 = 0;
|
|
||||||
carry0 = (s0 + (1 << 20)) >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry2 = (s2 + (1 << 20)) >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry4 = (s4 + (1 << 20)) >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry6 = (s6 + (1 << 20)) >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry8 = (s8 + (1 << 20)) >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry10 = (s10 + (1 << 20)) >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry1 = (s1 + (1 << 20)) >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry3 = (s3 + (1 << 20)) >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry5 = (s5 + (1 << 20)) >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry7 = (s7 + (1 << 20)) >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry9 = (s9 + (1 << 20)) >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry11 = (s11 + (1 << 20)) >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
s12 = 0;
|
|
||||||
carry0 = s0 >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry1 = s1 >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry2 = s2 >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry3 = s3 >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry4 = s4 >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry5 = s5 >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry6 = s6 >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry7 = s7 >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry8 = s8 >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry9 = s9 >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry10 = s10 >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry11 = s11 >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
carry0 = s0 >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry1 = s1 >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry2 = s2 >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry3 = s3 >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry4 = s4 >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry5 = s5 >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry6 = s6 >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry7 = s7 >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry8 = s8 >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry9 = s9 >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry10 = s10 >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
|
|
||||||
s[0] = (unsigned char)(s0 >> 0);
|
|
||||||
s[1] = (unsigned char)(s0 >> 8);
|
|
||||||
s[2] = (unsigned char)((s0 >> 16) | shl64(s1, 5));
|
|
||||||
s[3] = (unsigned char)(s1 >> 3);
|
|
||||||
s[4] = (unsigned char)(s1 >> 11);
|
|
||||||
s[5] = (unsigned char)((s1 >> 19) | shl64(s2, 2));
|
|
||||||
s[6] = (unsigned char)(s2 >> 6);
|
|
||||||
s[7] = (unsigned char)((s2 >> 14) | shl64(s3, 7));
|
|
||||||
s[8] = (unsigned char)(s3 >> 1);
|
|
||||||
s[9] = (unsigned char)(s3 >> 9);
|
|
||||||
s[10] = (unsigned char)((s3 >> 17) | shl64(s4, 4));
|
|
||||||
s[11] = (unsigned char)(s4 >> 4);
|
|
||||||
s[12] = (unsigned char)(s4 >> 12);
|
|
||||||
s[13] = (unsigned char)((s4 >> 20) | shl64(s5, 1));
|
|
||||||
s[14] = (unsigned char)(s5 >> 7);
|
|
||||||
s[15] = (unsigned char)((s5 >> 15) | shl64(s6, 6));
|
|
||||||
s[16] = (unsigned char)(s6 >> 2);
|
|
||||||
s[17] = (unsigned char)(s6 >> 10);
|
|
||||||
s[18] = (unsigned char)((s6 >> 18) | shl64(s7, 3));
|
|
||||||
s[19] = (unsigned char)(s7 >> 5);
|
|
||||||
s[20] = (unsigned char)(s7 >> 13);
|
|
||||||
s[21] = (unsigned char)(s8 >> 0);
|
|
||||||
s[22] = (unsigned char)(s8 >> 8);
|
|
||||||
s[23] = (unsigned char)((s8 >> 16) | shl64(s9, 5));
|
|
||||||
s[24] = (unsigned char)(s9 >> 3);
|
|
||||||
s[25] = (unsigned char)(s9 >> 11);
|
|
||||||
s[26] = (unsigned char)((s9 >> 19) | shl64(s10, 2));
|
|
||||||
s[27] = (unsigned char)(s10 >> 6);
|
|
||||||
s[28] = (unsigned char)((s10 >> 14) | shl64(s11, 7));
|
|
||||||
s[29] = (unsigned char)(s11 >> 1);
|
|
||||||
s[30] = (unsigned char)(s11 >> 9);
|
|
||||||
s[31] = (unsigned char)(s11 >> 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Input:
|
|
||||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
|
||||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
|
||||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
|
||||||
|
|
||||||
Output:
|
|
||||||
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
|
||||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
|
||||||
int64_t a0 = 2097151 & load_3(a);
|
|
||||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
|
||||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
|
||||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
|
||||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
|
||||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
|
||||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
|
||||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
|
||||||
int64_t a8 = 2097151 & load_3(a + 21);
|
|
||||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
|
||||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
|
||||||
int64_t a11 = (load_4(a + 28) >> 7);
|
|
||||||
int64_t b0 = 2097151 & load_3(b);
|
|
||||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
|
||||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
|
||||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
|
||||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
|
||||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
|
||||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
|
||||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
|
||||||
int64_t b8 = 2097151 & load_3(b + 21);
|
|
||||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
|
||||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
|
||||||
int64_t b11 = (load_4(b + 28) >> 7);
|
|
||||||
int64_t c0 = 2097151 & load_3(c);
|
|
||||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
|
||||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
|
||||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
|
||||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
|
||||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
|
||||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
|
||||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
|
||||||
int64_t c8 = 2097151 & load_3(c + 21);
|
|
||||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
|
||||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
|
||||||
int64_t c11 = (load_4(c + 28) >> 7);
|
|
||||||
int64_t s0;
|
|
||||||
int64_t s1;
|
|
||||||
int64_t s2;
|
|
||||||
int64_t s3;
|
|
||||||
int64_t s4;
|
|
||||||
int64_t s5;
|
|
||||||
int64_t s6;
|
|
||||||
int64_t s7;
|
|
||||||
int64_t s8;
|
|
||||||
int64_t s9;
|
|
||||||
int64_t s10;
|
|
||||||
int64_t s11;
|
|
||||||
int64_t s12;
|
|
||||||
int64_t s13;
|
|
||||||
int64_t s14;
|
|
||||||
int64_t s15;
|
|
||||||
int64_t s16;
|
|
||||||
int64_t s17;
|
|
||||||
int64_t s18;
|
|
||||||
int64_t s19;
|
|
||||||
int64_t s20;
|
|
||||||
int64_t s21;
|
|
||||||
int64_t s22;
|
|
||||||
int64_t s23;
|
|
||||||
int64_t carry0;
|
|
||||||
int64_t carry1;
|
|
||||||
int64_t carry2;
|
|
||||||
int64_t carry3;
|
|
||||||
int64_t carry4;
|
|
||||||
int64_t carry5;
|
|
||||||
int64_t carry6;
|
|
||||||
int64_t carry7;
|
|
||||||
int64_t carry8;
|
|
||||||
int64_t carry9;
|
|
||||||
int64_t carry10;
|
|
||||||
int64_t carry11;
|
|
||||||
int64_t carry12;
|
|
||||||
int64_t carry13;
|
|
||||||
int64_t carry14;
|
|
||||||
int64_t carry15;
|
|
||||||
int64_t carry16;
|
|
||||||
int64_t carry17;
|
|
||||||
int64_t carry18;
|
|
||||||
int64_t carry19;
|
|
||||||
int64_t carry20;
|
|
||||||
int64_t carry21;
|
|
||||||
int64_t carry22;
|
|
||||||
|
|
||||||
s0 = c0 + a0 * b0;
|
|
||||||
s1 = c1 + a0 * b1 + a1 * b0;
|
|
||||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
|
||||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
|
||||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
|
||||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
|
||||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
|
||||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
|
||||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
|
||||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
|
||||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
|
||||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
|
||||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
|
||||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
|
||||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
|
||||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
|
||||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
|
||||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
|
||||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
|
||||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
|
||||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
|
||||||
s21 = a10 * b11 + a11 * b10;
|
|
||||||
s22 = a11 * b11;
|
|
||||||
s23 = 0;
|
|
||||||
carry0 = (s0 + (1 << 20)) >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry2 = (s2 + (1 << 20)) >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry4 = (s4 + (1 << 20)) >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry6 = (s6 + (1 << 20)) >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry8 = (s8 + (1 << 20)) >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry10 = (s10 + (1 << 20)) >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry12 = (s12 + (1 << 20)) >> 21;
|
|
||||||
s13 += carry12;
|
|
||||||
s12 -= shl64(carry12, 21);
|
|
||||||
carry14 = (s14 + (1 << 20)) >> 21;
|
|
||||||
s15 += carry14;
|
|
||||||
s14 -= shl64(carry14, 21);
|
|
||||||
carry16 = (s16 + (1 << 20)) >> 21;
|
|
||||||
s17 += carry16;
|
|
||||||
s16 -= shl64(carry16, 21);
|
|
||||||
carry18 = (s18 + (1 << 20)) >> 21;
|
|
||||||
s19 += carry18;
|
|
||||||
s18 -= shl64(carry18, 21);
|
|
||||||
carry20 = (s20 + (1 << 20)) >> 21;
|
|
||||||
s21 += carry20;
|
|
||||||
s20 -= shl64(carry20, 21);
|
|
||||||
carry22 = (s22 + (1 << 20)) >> 21;
|
|
||||||
s23 += carry22;
|
|
||||||
s22 -= shl64(carry22, 21);
|
|
||||||
carry1 = (s1 + (1 << 20)) >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry3 = (s3 + (1 << 20)) >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry5 = (s5 + (1 << 20)) >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry7 = (s7 + (1 << 20)) >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry9 = (s9 + (1 << 20)) >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry11 = (s11 + (1 << 20)) >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
carry13 = (s13 + (1 << 20)) >> 21;
|
|
||||||
s14 += carry13;
|
|
||||||
s13 -= shl64(carry13, 21);
|
|
||||||
carry15 = (s15 + (1 << 20)) >> 21;
|
|
||||||
s16 += carry15;
|
|
||||||
s15 -= shl64(carry15, 21);
|
|
||||||
carry17 = (s17 + (1 << 20)) >> 21;
|
|
||||||
s18 += carry17;
|
|
||||||
s17 -= shl64(carry17, 21);
|
|
||||||
carry19 = (s19 + (1 << 20)) >> 21;
|
|
||||||
s20 += carry19;
|
|
||||||
s19 -= shl64(carry19, 21);
|
|
||||||
carry21 = (s21 + (1 << 20)) >> 21;
|
|
||||||
s22 += carry21;
|
|
||||||
s21 -= shl64(carry21, 21);
|
|
||||||
s11 += s23 * 666643;
|
|
||||||
s12 += s23 * 470296;
|
|
||||||
s13 += s23 * 654183;
|
|
||||||
s14 -= s23 * 997805;
|
|
||||||
s15 += s23 * 136657;
|
|
||||||
s16 -= s23 * 683901;
|
|
||||||
s10 += s22 * 666643;
|
|
||||||
s11 += s22 * 470296;
|
|
||||||
s12 += s22 * 654183;
|
|
||||||
s13 -= s22 * 997805;
|
|
||||||
s14 += s22 * 136657;
|
|
||||||
s15 -= s22 * 683901;
|
|
||||||
s9 += s21 * 666643;
|
|
||||||
s10 += s21 * 470296;
|
|
||||||
s11 += s21 * 654183;
|
|
||||||
s12 -= s21 * 997805;
|
|
||||||
s13 += s21 * 136657;
|
|
||||||
s14 -= s21 * 683901;
|
|
||||||
s8 += s20 * 666643;
|
|
||||||
s9 += s20 * 470296;
|
|
||||||
s10 += s20 * 654183;
|
|
||||||
s11 -= s20 * 997805;
|
|
||||||
s12 += s20 * 136657;
|
|
||||||
s13 -= s20 * 683901;
|
|
||||||
s7 += s19 * 666643;
|
|
||||||
s8 += s19 * 470296;
|
|
||||||
s9 += s19 * 654183;
|
|
||||||
s10 -= s19 * 997805;
|
|
||||||
s11 += s19 * 136657;
|
|
||||||
s12 -= s19 * 683901;
|
|
||||||
s6 += s18 * 666643;
|
|
||||||
s7 += s18 * 470296;
|
|
||||||
s8 += s18 * 654183;
|
|
||||||
s9 -= s18 * 997805;
|
|
||||||
s10 += s18 * 136657;
|
|
||||||
s11 -= s18 * 683901;
|
|
||||||
carry6 = (s6 + (1 << 20)) >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry8 = (s8 + (1 << 20)) >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry10 = (s10 + (1 << 20)) >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry12 = (s12 + (1 << 20)) >> 21;
|
|
||||||
s13 += carry12;
|
|
||||||
s12 -= shl64(carry12, 21);
|
|
||||||
carry14 = (s14 + (1 << 20)) >> 21;
|
|
||||||
s15 += carry14;
|
|
||||||
s14 -= shl64(carry14, 21);
|
|
||||||
carry16 = (s16 + (1 << 20)) >> 21;
|
|
||||||
s17 += carry16;
|
|
||||||
s16 -= shl64(carry16, 21);
|
|
||||||
carry7 = (s7 + (1 << 20)) >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry9 = (s9 + (1 << 20)) >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry11 = (s11 + (1 << 20)) >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
carry13 = (s13 + (1 << 20)) >> 21;
|
|
||||||
s14 += carry13;
|
|
||||||
s13 -= shl64(carry13, 21);
|
|
||||||
carry15 = (s15 + (1 << 20)) >> 21;
|
|
||||||
s16 += carry15;
|
|
||||||
s15 -= shl64(carry15, 21);
|
|
||||||
s5 += s17 * 666643;
|
|
||||||
s6 += s17 * 470296;
|
|
||||||
s7 += s17 * 654183;
|
|
||||||
s8 -= s17 * 997805;
|
|
||||||
s9 += s17 * 136657;
|
|
||||||
s10 -= s17 * 683901;
|
|
||||||
s4 += s16 * 666643;
|
|
||||||
s5 += s16 * 470296;
|
|
||||||
s6 += s16 * 654183;
|
|
||||||
s7 -= s16 * 997805;
|
|
||||||
s8 += s16 * 136657;
|
|
||||||
s9 -= s16 * 683901;
|
|
||||||
s3 += s15 * 666643;
|
|
||||||
s4 += s15 * 470296;
|
|
||||||
s5 += s15 * 654183;
|
|
||||||
s6 -= s15 * 997805;
|
|
||||||
s7 += s15 * 136657;
|
|
||||||
s8 -= s15 * 683901;
|
|
||||||
s2 += s14 * 666643;
|
|
||||||
s3 += s14 * 470296;
|
|
||||||
s4 += s14 * 654183;
|
|
||||||
s5 -= s14 * 997805;
|
|
||||||
s6 += s14 * 136657;
|
|
||||||
s7 -= s14 * 683901;
|
|
||||||
s1 += s13 * 666643;
|
|
||||||
s2 += s13 * 470296;
|
|
||||||
s3 += s13 * 654183;
|
|
||||||
s4 -= s13 * 997805;
|
|
||||||
s5 += s13 * 136657;
|
|
||||||
s6 -= s13 * 683901;
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
s12 = 0;
|
|
||||||
carry0 = (s0 + (1 << 20)) >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry2 = (s2 + (1 << 20)) >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry4 = (s4 + (1 << 20)) >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry6 = (s6 + (1 << 20)) >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry8 = (s8 + (1 << 20)) >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry10 = (s10 + (1 << 20)) >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry1 = (s1 + (1 << 20)) >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry3 = (s3 + (1 << 20)) >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry5 = (s5 + (1 << 20)) >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry7 = (s7 + (1 << 20)) >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry9 = (s9 + (1 << 20)) >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry11 = (s11 + (1 << 20)) >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
s12 = 0;
|
|
||||||
carry0 = s0 >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry1 = s1 >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry2 = s2 >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry3 = s3 >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry4 = s4 >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry5 = s5 >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry6 = s6 >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry7 = s7 >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry8 = s8 >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry9 = s9 >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry10 = s10 >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
carry11 = s11 >> 21;
|
|
||||||
s12 += carry11;
|
|
||||||
s11 -= shl64(carry11, 21);
|
|
||||||
s0 += s12 * 666643;
|
|
||||||
s1 += s12 * 470296;
|
|
||||||
s2 += s12 * 654183;
|
|
||||||
s3 -= s12 * 997805;
|
|
||||||
s4 += s12 * 136657;
|
|
||||||
s5 -= s12 * 683901;
|
|
||||||
carry0 = s0 >> 21;
|
|
||||||
s1 += carry0;
|
|
||||||
s0 -= shl64(carry0, 21);
|
|
||||||
carry1 = s1 >> 21;
|
|
||||||
s2 += carry1;
|
|
||||||
s1 -= shl64(carry1, 21);
|
|
||||||
carry2 = s2 >> 21;
|
|
||||||
s3 += carry2;
|
|
||||||
s2 -= shl64(carry2, 21);
|
|
||||||
carry3 = s3 >> 21;
|
|
||||||
s4 += carry3;
|
|
||||||
s3 -= shl64(carry3, 21);
|
|
||||||
carry4 = s4 >> 21;
|
|
||||||
s5 += carry4;
|
|
||||||
s4 -= shl64(carry4, 21);
|
|
||||||
carry5 = s5 >> 21;
|
|
||||||
s6 += carry5;
|
|
||||||
s5 -= shl64(carry5, 21);
|
|
||||||
carry6 = s6 >> 21;
|
|
||||||
s7 += carry6;
|
|
||||||
s6 -= shl64(carry6, 21);
|
|
||||||
carry7 = s7 >> 21;
|
|
||||||
s8 += carry7;
|
|
||||||
s7 -= shl64(carry7, 21);
|
|
||||||
carry8 = s8 >> 21;
|
|
||||||
s9 += carry8;
|
|
||||||
s8 -= shl64(carry8, 21);
|
|
||||||
carry9 = s9 >> 21;
|
|
||||||
s10 += carry9;
|
|
||||||
s9 -= shl64(carry9, 21);
|
|
||||||
carry10 = s10 >> 21;
|
|
||||||
s11 += carry10;
|
|
||||||
s10 -= shl64(carry10, 21);
|
|
||||||
|
|
||||||
s[0] = (unsigned char)(s0 >> 0);
|
|
||||||
s[1] = (unsigned char)(s0 >> 8);
|
|
||||||
s[2] = (unsigned char)((s0 >> 16) | shl64(s1, 5));
|
|
||||||
s[3] = (unsigned char)(s1 >> 3);
|
|
||||||
s[4] = (unsigned char)(s1 >> 11);
|
|
||||||
s[5] = (unsigned char)((s1 >> 19) | shl64(s2, 2));
|
|
||||||
s[6] = (unsigned char)(s2 >> 6);
|
|
||||||
s[7] = (unsigned char)((s2 >> 14) | shl64(s3, 7));
|
|
||||||
s[8] = (unsigned char)(s3 >> 1);
|
|
||||||
s[9] = (unsigned char)(s3 >> 9);
|
|
||||||
s[10] = (unsigned char)((s3 >> 17) | shl64(s4, 4));
|
|
||||||
s[11] = (unsigned char)(s4 >> 4);
|
|
||||||
s[12] = (unsigned char)(s4 >> 12);
|
|
||||||
s[13] = (unsigned char)((s4 >> 20) | shl64(s5, 1));
|
|
||||||
s[14] = (unsigned char)(s5 >> 7);
|
|
||||||
s[15] = (unsigned char)((s5 >> 15) | shl64(s6, 6));
|
|
||||||
s[16] = (unsigned char)(s6 >> 2);
|
|
||||||
s[17] = (unsigned char)(s6 >> 10);
|
|
||||||
s[18] = (unsigned char)((s6 >> 18) | shl64(s7, 3));
|
|
||||||
s[19] = (unsigned char)(s7 >> 5);
|
|
||||||
s[20] = (unsigned char)(s7 >> 13);
|
|
||||||
s[21] = (unsigned char)(s8 >> 0);
|
|
||||||
s[22] = (unsigned char)(s8 >> 8);
|
|
||||||
s[23] = (unsigned char)((s8 >> 16) | shl64(s9, 5));
|
|
||||||
s[24] = (unsigned char)(s9 >> 3);
|
|
||||||
s[25] = (unsigned char)(s9 >> 11);
|
|
||||||
s[26] = (unsigned char)((s9 >> 19) | shl64(s10, 2));
|
|
||||||
s[27] = (unsigned char)(s10 >> 6);
|
|
||||||
s[28] = (unsigned char)((s10 >> 14) | shl64(s11, 7));
|
|
||||||
s[29] = (unsigned char)(s11 >> 1);
|
|
||||||
s[30] = (unsigned char)(s11 >> 9);
|
|
||||||
s[31] = (unsigned char)(s11 >> 17);
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
#ifndef SC_H
|
|
||||||
#define SC_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
The set of scalars is \Z/l
|
|
||||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sc_reduce(unsigned char *s);
|
|
||||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,303 +0,0 @@
|
||||||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
|
||||||
*
|
|
||||||
* LibTomCrypt is a library that provides various cryptographic
|
|
||||||
* algorithms in a highly modular and flexible manner.
|
|
||||||
*
|
|
||||||
* The library is free for all purposes without any express
|
|
||||||
* guarantee it works.
|
|
||||||
*
|
|
||||||
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fixedint.h"
|
|
||||||
#include "sha512.h"
|
|
||||||
|
|
||||||
/* the K array */
|
|
||||||
static const uint64_t K[80] = {
|
|
||||||
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
|
||||||
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
|
||||||
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
|
||||||
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
|
||||||
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
|
||||||
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
|
||||||
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
|
||||||
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
|
||||||
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
|
||||||
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
|
||||||
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
|
||||||
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
|
||||||
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
|
||||||
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
|
||||||
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
|
||||||
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
|
||||||
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
|
||||||
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
|
||||||
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
|
|
||||||
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
|
|
||||||
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
|
|
||||||
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
|
|
||||||
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
|
|
||||||
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
|
||||||
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
|
||||||
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
|
||||||
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
|
||||||
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
|
||||||
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
|
||||||
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
|
||||||
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
|
||||||
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
|
||||||
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
|
||||||
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
|
||||||
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
|
||||||
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
|
||||||
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
|
||||||
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
|
||||||
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
|
||||||
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Various logical functions */
|
|
||||||
|
|
||||||
#define ROR64c(x, y) \
|
|
||||||
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
|
||||||
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
|
||||||
|
|
||||||
#define STORE64H(x, y) \
|
|
||||||
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
|
||||||
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
|
||||||
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
|
||||||
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
|
||||||
|
|
||||||
#define LOAD64H(x, y) \
|
|
||||||
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
|
||||||
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
|
||||||
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
|
||||||
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
|
||||||
|
|
||||||
|
|
||||||
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
|
||||||
#define Maj(x,y,z) (((x | y) & z) | (x & y))
|
|
||||||
#define S(x, n) ROR64c(x, n)
|
|
||||||
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
|
|
||||||
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
|
||||||
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
|
||||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
|
||||||
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* compress 1024-bits */
|
|
||||||
static int sha512_compress(sha512_context *md, const unsigned char *buf) {
|
|
||||||
uint64_t S[8], W[80], t0, t1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* copy state into S */
|
|
||||||
for(i = 0; i < 8; i++) {
|
|
||||||
S[i] = md->state[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy the state into 1024-bits into W[0..15] */
|
|
||||||
for(i = 0; i < 16; i++) {
|
|
||||||
LOAD64H(W[i], buf + (8 * i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill W[16..79] */
|
|
||||||
for(i = 16; i < 80; i++) {
|
|
||||||
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compress */
|
|
||||||
#define RND(a,b,c,d,e,f,g,h,i) \
|
|
||||||
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
|
||||||
t1 = Sigma0(a) + Maj(a, b, c);\
|
|
||||||
d += t0; \
|
|
||||||
h = t0 + t1;
|
|
||||||
|
|
||||||
for(i = 0; i < 80; i += 8) {
|
|
||||||
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
|
|
||||||
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
|
|
||||||
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
|
|
||||||
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
|
|
||||||
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
|
|
||||||
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
|
|
||||||
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
|
|
||||||
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef RND
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* feedback */
|
|
||||||
for(i = 0; i < 8; i++) {
|
|
||||||
md->state[i] = md->state[i] + S[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Initialize the hash state
|
|
||||||
@param md The hash state you wish to initialize
|
|
||||||
@return 0 if successful
|
|
||||||
*/
|
|
||||||
int sha512_init(sha512_context *md) {
|
|
||||||
if(md == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
md->curlen = 0;
|
|
||||||
md->length = 0;
|
|
||||||
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
|
||||||
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
|
||||||
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
|
||||||
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
|
||||||
md->state[4] = UINT64_C(0x510e527fade682d1);
|
|
||||||
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
|
||||||
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
|
||||||
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Process a block of memory though the hash
|
|
||||||
@param md The hash state
|
|
||||||
@param in The data to hash
|
|
||||||
@param inlen The length of the data (octets)
|
|
||||||
@return 0 if successful
|
|
||||||
*/
|
|
||||||
int sha512_update(sha512_context *md, const void *vin, size_t inlen) {
|
|
||||||
const unsigned char *in = vin;
|
|
||||||
size_t n;
|
|
||||||
size_t i;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if(md == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(in == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(md->curlen > sizeof(md->buf)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(inlen > 0) {
|
|
||||||
if(md->curlen == 0 && inlen >= 128) {
|
|
||||||
if((err = sha512_compress(md, in)) != 0) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
md->length += 128 * 8;
|
|
||||||
in += 128;
|
|
||||||
inlen -= 128;
|
|
||||||
} else {
|
|
||||||
n = MIN(inlen, (128 - md->curlen));
|
|
||||||
|
|
||||||
for(i = 0; i < n; i++) {
|
|
||||||
md->buf[i + md->curlen] = in[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
md->curlen += n;
|
|
||||||
in += n;
|
|
||||||
inlen -= n;
|
|
||||||
|
|
||||||
if(md->curlen == 128) {
|
|
||||||
if((err = sha512_compress(md, md->buf)) != 0) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
md->length += 8 * 128;
|
|
||||||
md->curlen = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Terminate the hash to get the digest
|
|
||||||
@param md The hash state
|
|
||||||
@param out [out] The destination of the hash (64 bytes)
|
|
||||||
@return 0 if successful
|
|
||||||
*/
|
|
||||||
int sha512_final(sha512_context *md, void *vout) {
|
|
||||||
int i;
|
|
||||||
unsigned char *out = vout;
|
|
||||||
|
|
||||||
if(md == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(out == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(md->curlen >= sizeof(md->buf)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* increase the length of the message */
|
|
||||||
md->length += md->curlen * UINT64_C(8);
|
|
||||||
|
|
||||||
/* append the '1' bit */
|
|
||||||
md->buf[md->curlen++] = (unsigned char)0x80;
|
|
||||||
|
|
||||||
/* if the length is currently above 112 bytes we append zeros
|
|
||||||
* then compress. Then we can fall back to padding zeros and length
|
|
||||||
* encoding like normal.
|
|
||||||
*/
|
|
||||||
if(md->curlen > 112) {
|
|
||||||
while(md->curlen < 128) {
|
|
||||||
md->buf[md->curlen++] = (unsigned char)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha512_compress(md, md->buf);
|
|
||||||
md->curlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pad up to 120 bytes of zeroes
|
|
||||||
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
|
|
||||||
* > 2^64 bits of data... :-)
|
|
||||||
*/
|
|
||||||
while(md->curlen < 120) {
|
|
||||||
md->buf[md->curlen++] = (unsigned char)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* store length */
|
|
||||||
STORE64H(md->length, md->buf + 120);
|
|
||||||
sha512_compress(md, md->buf);
|
|
||||||
|
|
||||||
/* copy output */
|
|
||||||
for(i = 0; i < 8; i++) {
|
|
||||||
STORE64H(md->state[i], out + (8 * i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sha512(const void *message, size_t message_len, void *out) {
|
|
||||||
sha512_context ctx;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if((ret = sha512_init(&ctx))) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((ret = sha512_update(&ctx, message, message_len))) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((ret = sha512_final(&ctx, out))) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#ifndef SHA512_H
|
|
||||||
#define SHA512_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "fixedint.h"
|
|
||||||
|
|
||||||
/* state */
|
|
||||||
typedef struct sha512_context_ {
|
|
||||||
uint64_t length, state[8];
|
|
||||||
size_t curlen;
|
|
||||||
unsigned char buf[128];
|
|
||||||
} sha512_context;
|
|
||||||
|
|
||||||
|
|
||||||
int sha512_init(sha512_context *md);
|
|
||||||
int sha512_final(sha512_context *md, void *out);
|
|
||||||
int sha512_update(sha512_context *md, const void *in, size_t inlen);
|
|
||||||
int sha512(const void *message, size_t message_len, void *out);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,31 +0,0 @@
|
||||||
#include "ed25519.h"
|
|
||||||
#include "sha512.h"
|
|
||||||
#include "ge.h"
|
|
||||||
#include "sc.h"
|
|
||||||
|
|
||||||
|
|
||||||
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
|
||||||
sha512_context hash;
|
|
||||||
unsigned char hram[64];
|
|
||||||
unsigned char r[64];
|
|
||||||
ge_p3 R;
|
|
||||||
|
|
||||||
|
|
||||||
sha512_init(&hash);
|
|
||||||
sha512_update(&hash, private_key + 32, 32);
|
|
||||||
sha512_update(&hash, message, message_len);
|
|
||||||
sha512_final(&hash, r);
|
|
||||||
|
|
||||||
sc_reduce(r);
|
|
||||||
ge_scalarmult_base(&R, r);
|
|
||||||
ge_p3_tobytes(signature, &R);
|
|
||||||
|
|
||||||
sha512_init(&hash);
|
|
||||||
sha512_update(&hash, signature, 32);
|
|
||||||
sha512_update(&hash, public_key, 32);
|
|
||||||
sha512_update(&hash, message, message_len);
|
|
||||||
sha512_final(&hash, hram);
|
|
||||||
|
|
||||||
sc_reduce(hram);
|
|
||||||
sc_muladd(signature + 32, hram, private_key, r);
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
#include "ed25519.h"
|
|
||||||
#include "sha512.h"
|
|
||||||
#include "ge.h"
|
|
||||||
#include "sc.h"
|
|
||||||
|
|
||||||
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
|
||||||
unsigned char r = 0;
|
|
||||||
|
|
||||||
r = x[0] ^ y[0];
|
|
||||||
#define F(i) r |= x[i] ^ y[i]
|
|
||||||
F(1);
|
|
||||||
F(2);
|
|
||||||
F(3);
|
|
||||||
F(4);
|
|
||||||
F(5);
|
|
||||||
F(6);
|
|
||||||
F(7);
|
|
||||||
F(8);
|
|
||||||
F(9);
|
|
||||||
F(10);
|
|
||||||
F(11);
|
|
||||||
F(12);
|
|
||||||
F(13);
|
|
||||||
F(14);
|
|
||||||
F(15);
|
|
||||||
F(16);
|
|
||||||
F(17);
|
|
||||||
F(18);
|
|
||||||
F(19);
|
|
||||||
F(20);
|
|
||||||
F(21);
|
|
||||||
F(22);
|
|
||||||
F(23);
|
|
||||||
F(24);
|
|
||||||
F(25);
|
|
||||||
F(26);
|
|
||||||
F(27);
|
|
||||||
F(28);
|
|
||||||
F(29);
|
|
||||||
F(30);
|
|
||||||
F(31);
|
|
||||||
#undef F
|
|
||||||
|
|
||||||
return !r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
|
||||||
unsigned char h[64];
|
|
||||||
unsigned char checker[32];
|
|
||||||
sha512_context hash;
|
|
||||||
ge_p3 A;
|
|
||||||
ge_p2 R;
|
|
||||||
|
|
||||||
if(signature[63] & 224) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha512_init(&hash);
|
|
||||||
sha512_update(&hash, signature, 32);
|
|
||||||
sha512_update(&hash, public_key, 32);
|
|
||||||
sha512_update(&hash, message, message_len);
|
|
||||||
sha512_final(&hash, h);
|
|
||||||
|
|
||||||
sc_reduce(h);
|
|
||||||
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
|
||||||
ge_tobytes(checker, &R);
|
|
||||||
|
|
||||||
if(!consttime_equal(checker, signature)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
60
src/edge.c
60
src/edge.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
edge.c -- edge tree management
|
edge.c -- edge tree management
|
||||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2000-2005 Ivo Timmermans
|
2000-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -20,8 +20,7 @@
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include "splay_tree.h"
|
#include "avl_tree.h"
|
||||||
#include "control_common.h"
|
|
||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "netutl.h"
|
#include "netutl.h"
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
||||||
splay_tree_t *edge_weight_tree;
|
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
|
||||||
|
|
||||||
static int edge_compare(const edge_t *a, const edge_t *b) {
|
static int edge_compare(const edge_t *a, const edge_t *b) {
|
||||||
return strcmp(a->to->name, b->to->name);
|
return strcmp(a->to->name, b->to->name);
|
||||||
|
@ -54,37 +53,36 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_edges(void) {
|
void init_edges(void) {
|
||||||
edge_weight_tree = splay_alloc_tree((splay_compare_t) edge_weight_compare, NULL);
|
edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
splay_tree_t *new_edge_tree(void) {
|
avl_tree_t *new_edge_tree(void) {
|
||||||
return splay_alloc_tree((splay_compare_t) edge_compare, (splay_action_t) free_edge);
|
return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_edge_tree(splay_tree_t *edge_tree) {
|
void free_edge_tree(avl_tree_t *edge_tree) {
|
||||||
splay_delete_tree(edge_tree);
|
avl_delete_tree(edge_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_edges(void) {
|
void exit_edges(void) {
|
||||||
splay_delete_tree(edge_weight_tree);
|
avl_delete_tree(edge_weight_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creation and deletion of connection elements */
|
/* Creation and deletion of connection elements */
|
||||||
|
|
||||||
edge_t *new_edge(void) {
|
edge_t *new_edge(void) {
|
||||||
return xzalloc(sizeof(edge_t));
|
return xmalloc_and_zero(sizeof(edge_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_edge(edge_t *e) {
|
void free_edge(edge_t *e) {
|
||||||
sockaddrfree(&e->address);
|
sockaddrfree(&e->address);
|
||||||
sockaddrfree(&e->local_address);
|
|
||||||
|
|
||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void edge_add(edge_t *e) {
|
void edge_add(edge_t *e) {
|
||||||
splay_insert(edge_weight_tree, e);
|
avl_insert(edge_weight_tree, e);
|
||||||
splay_insert(e->from->edge_tree, e);
|
avl_insert(e->from->edge_tree, e);
|
||||||
|
|
||||||
e->reverse = lookup_edge(e->to, e->from);
|
e->reverse = lookup_edge(e->to, e->from);
|
||||||
|
|
||||||
|
@ -98,8 +96,8 @@ void edge_del(edge_t *e) {
|
||||||
e->reverse->reverse = NULL;
|
e->reverse->reverse = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
splay_delete(edge_weight_tree, e);
|
avl_delete(edge_weight_tree, e);
|
||||||
splay_delete(e->from->edge_tree, e);
|
avl_delete(e->from->edge_tree, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
edge_t *lookup_edge(node_t *from, node_t *to) {
|
edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||||
|
@ -108,22 +106,28 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||||
v.from = from;
|
v.from = from;
|
||||||
v.to = to;
|
v.to = to;
|
||||||
|
|
||||||
return splay_search(from->edge_tree, &v);
|
return avl_search(from->edge_tree, &v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_edges(connection_t *c) {
|
void dump_edges(void) {
|
||||||
for splay_each(node_t, n, node_tree) {
|
avl_node_t *node, *node2;
|
||||||
for splay_each(edge_t, e, n->edge_tree) {
|
node_t *n;
|
||||||
char *address = sockaddr2hostname(&e->address);
|
edge_t *e;
|
||||||
char *local_address = sockaddr2hostname(&e->local_address);
|
char *address;
|
||||||
send_request(c, "%d %d %s %s %s %s %x %d",
|
|
||||||
CONTROL, REQ_DUMP_EDGES,
|
logger(LOG_DEBUG, "Edges:");
|
||||||
e->from->name, e->to->name, address,
|
|
||||||
local_address, e->options, e->weight);
|
for(node = node_tree->head; node; node = node->next) {
|
||||||
|
n = node->data;
|
||||||
|
|
||||||
|
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
||||||
|
e = node2->data;
|
||||||
|
address = sockaddr2hostname(&e->address);
|
||||||
|
logger(LOG_DEBUG, " %s to %s at %s options %x weight %d",
|
||||||
|
e->from->name, e->to->name, address, e->options, e->weight);
|
||||||
free(address);
|
free(address);
|
||||||
free(local_address);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_EDGES);
|
logger(LOG_DEBUG, "End of edges.");
|
||||||
}
|
}
|
||||||
|
|
21
src/edge.h
21
src/edge.h
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
edge.h -- header for edge.c
|
edge.h -- header for edge.c
|
||||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2001-2005 Ivo Timmermans
|
2001-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "splay_tree.h"
|
#include "avl_tree.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
@ -30,26 +30,25 @@ typedef struct edge_t {
|
||||||
struct node_t *from;
|
struct node_t *from;
|
||||||
struct node_t *to;
|
struct node_t *to;
|
||||||
sockaddr_t address;
|
sockaddr_t address;
|
||||||
sockaddr_t local_address;
|
|
||||||
|
|
||||||
uint32_t options; /* options turned on for this edge */
|
uint32_t options; /* options turned on for this edge */
|
||||||
int weight; /* weight of this edge */
|
int weight; /* weight of this edge */
|
||||||
|
|
||||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||||
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
||||||
} edge_t;
|
} edge_t;
|
||||||
|
|
||||||
extern splay_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
||||||
|
|
||||||
extern void init_edges(void);
|
extern void init_edges(void);
|
||||||
extern void exit_edges(void);
|
extern void exit_edges(void);
|
||||||
extern edge_t *new_edge(void) __attribute__((__malloc__));
|
extern edge_t *new_edge(void) __attribute__((__malloc__));
|
||||||
extern void free_edge(edge_t *e);
|
extern void free_edge(edge_t *e);
|
||||||
extern splay_tree_t *new_edge_tree(void) __attribute__((__malloc__));
|
extern avl_tree_t *new_edge_tree(void) __attribute__((__malloc__));
|
||||||
extern void free_edge_tree(splay_tree_t *edge_tree);
|
extern void free_edge_tree(avl_tree_t *edge_tree);
|
||||||
extern void edge_add(edge_t *e);
|
extern void edge_add(edge_t *e);
|
||||||
extern void edge_del(edge_t *e);
|
extern void edge_del(edge_t *e);
|
||||||
extern edge_t *lookup_edge(struct node_t *from, struct node_t *to);
|
extern edge_t *lookup_edge(struct node_t *from, struct node_t *to);
|
||||||
extern bool dump_edges(struct connection_t *c);
|
extern void dump_edges(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,15 +25,6 @@
|
||||||
#define ETH_ALEN 6
|
#define ETH_ALEN 6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ETH_HLEN
|
|
||||||
#define ETH_HLEN 14
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ETHER_TYPE_LEN
|
|
||||||
#define ETHER_TYPE_LEN 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ARPHRD_ETHER
|
#ifndef ARPHRD_ETHER
|
||||||
#define ARPHRD_ETHER 1
|
#define ARPHRD_ETHER 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,16 +45,12 @@
|
||||||
#define ETH_P_8021Q 0x8100
|
#define ETH_P_8021Q 0x8100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ETH_P_MAX
|
|
||||||
#define ETH_P_MAX 0xFFFF
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||||
struct ether_header {
|
struct ether_header {
|
||||||
uint8_t ether_dhost[ETH_ALEN];
|
uint8_t ether_dhost[ETH_ALEN];
|
||||||
uint8_t ether_shost[ETH_ALEN];
|
uint8_t ether_shost[ETH_ALEN];
|
||||||
uint16_t ether_type;
|
uint16_t ether_type;
|
||||||
} __attribute__((__gcc_struct__, __packed__));
|
} __attribute__((__packed__));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_STRUCT_ARPHDR
|
#ifndef HAVE_STRUCT_ARPHDR
|
||||||
|
@ -73,7 +60,7 @@ struct arphdr {
|
||||||
uint8_t ar_hln;
|
uint8_t ar_hln;
|
||||||
uint8_t ar_pln;
|
uint8_t ar_pln;
|
||||||
uint16_t ar_op;
|
uint16_t ar_op;
|
||||||
} __attribute__((__gcc_struct__, __packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
#define ARPOP_REQUEST 1
|
#define ARPOP_REQUEST 1
|
||||||
#define ARPOP_REPLY 2
|
#define ARPOP_REPLY 2
|
||||||
|
@ -91,7 +78,7 @@ struct ether_arp {
|
||||||
uint8_t arp_spa[4];
|
uint8_t arp_spa[4];
|
||||||
uint8_t arp_tha[ETH_ALEN];
|
uint8_t arp_tha[ETH_ALEN];
|
||||||
uint8_t arp_tpa[4];
|
uint8_t arp_tpa[4];
|
||||||
} __attribute__((__gcc_struct__, __packed__));
|
} __attribute__((__packed__));
|
||||||
#define arp_hrd ea_hdr.ar_hrd
|
#define arp_hrd ea_hdr.ar_hrd
|
||||||
#define arp_pro ea_hdr.ar_pro
|
#define arp_pro ea_hdr.ar_pro
|
||||||
#define arp_hln ea_hdr.ar_hln
|
#define arp_hln ea_hdr.ar_hln
|
||||||
|
|
484
src/event.c
484
src/event.c
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
event.c -- I/O, timeout and signal event handling
|
event.c -- event queue
|
||||||
Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
|
2002-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,471 +20,102 @@
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include "dropin.h"
|
#include "avl_tree.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "net.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
||||||
struct timeval now;
|
avl_tree_t *event_tree;
|
||||||
|
extern time_t now;
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
static int id;
|
||||||
static fd_set readfds;
|
|
||||||
static fd_set writefds;
|
|
||||||
#else
|
|
||||||
static const long READ_EVENTS = FD_READ | FD_ACCEPT | FD_CLOSE;
|
|
||||||
static const long WRITE_EVENTS = FD_WRITE | FD_CONNECT;
|
|
||||||
static DWORD event_count = 0;
|
|
||||||
#endif
|
|
||||||
static bool running;
|
|
||||||
|
|
||||||
static int io_compare(const io_t *a, const io_t *b) {
|
static int event_compare(const event_t *a, const event_t *b) {
|
||||||
#ifndef HAVE_MINGW
|
if(a->time > b->time) {
|
||||||
return a->fd - b->fd;
|
|
||||||
#else
|
|
||||||
|
|
||||||
if(a->event < b->event) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(a->event > b->event) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if(a->time < b->time) {
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timeout_compare(const timeout_t *a, const timeout_t *b) {
|
|
||||||
struct timeval diff;
|
|
||||||
timersub(&a->tv, &b->tv, &diff);
|
|
||||||
|
|
||||||
if(diff.tv_sec < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(diff.tv_sec > 0) {
|
return a->id - b->id;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(diff.tv_usec < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(diff.tv_usec > 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(a < b) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(a > b) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
|
void init_events(void) {
|
||||||
static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
|
event_tree = avl_alloc_tree((avl_compare_t) event_compare, (avl_action_t) free_event);
|
||||||
|
}
|
||||||
|
|
||||||
void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
|
void exit_events(void) {
|
||||||
if(io->cb) {
|
avl_delete_tree(event_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expire_events(void) {
|
||||||
|
avl_node_t *node;
|
||||||
|
event_t *event;
|
||||||
|
time_t diff;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make all events appear expired by subtracting the difference between
|
||||||
|
* the expiration time of the last event and the current time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!event_tree->tail) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
io->fd = fd;
|
event = event_tree->tail->data;
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
|
|
||||||
if(io->fd != -1) {
|
if(event->time <= now) {
|
||||||
io->event = WSACreateEvent();
|
|
||||||
|
|
||||||
if(io->event == WSA_INVALID_EVENT) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_count++;
|
|
||||||
#endif
|
|
||||||
io->cb = cb;
|
|
||||||
io->data = data;
|
|
||||||
io->node.data = io;
|
|
||||||
|
|
||||||
io_set(io, flags);
|
|
||||||
|
|
||||||
if(!splay_insert_node(&io_tree, &io->node)) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) {
|
|
||||||
io->event = event;
|
|
||||||
io_add(io, cb, data, -1, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void io_set(io_t *io, int flags) {
|
|
||||||
if(flags == io->flags) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
io->flags = flags;
|
diff = event->time - now;
|
||||||
|
|
||||||
if(io->fd == -1) {
|
for(node = event_tree->head; node; node = node->next) {
|
||||||
return;
|
event = node->data;
|
||||||
}
|
event->time -= diff;
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
|
||||||
|
|
||||||
if(flags & IO_READ) {
|
|
||||||
FD_SET(io->fd, &readfds);
|
|
||||||
} else {
|
|
||||||
FD_CLR(io->fd, &readfds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flags & IO_WRITE) {
|
|
||||||
FD_SET(io->fd, &writefds);
|
|
||||||
} else {
|
|
||||||
FD_CLR(io->fd, &writefds);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
long events = 0;
|
|
||||||
|
|
||||||
if(flags & IO_WRITE) {
|
|
||||||
events |= WRITE_EVENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flags & IO_READ) {
|
|
||||||
events |= READ_EVENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(WSAEventSelect(io->fd, io->event, events) != 0) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_del(io_t *io) {
|
|
||||||
if(!io->cb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_set(io, 0);
|
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
|
|
||||||
if(io->fd != -1 && WSACloseEvent(io->event) == FALSE) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
event_count--;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
splay_unlink_node(&io_tree, &io->node);
|
|
||||||
io->cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
|
|
||||||
timeout->cb = cb;
|
|
||||||
timeout->data = data;
|
|
||||||
timeout->node.data = timeout;
|
|
||||||
|
|
||||||
timeout_set(timeout, tv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timeout_set(timeout_t *timeout, struct timeval *tv) {
|
|
||||||
if(timerisset(&timeout->tv)) {
|
|
||||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!now.tv_sec) {
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeradd(&now, tv, &timeout->tv);
|
|
||||||
|
|
||||||
if(!splay_insert_node(&timeout_tree, &timeout->node)) {
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void timeout_del(timeout_t *timeout) {
|
event_t *new_event(void) {
|
||||||
if(!timeout->cb) {
|
return xmalloc_and_zero(sizeof(event_t));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
|
||||||
timeout->cb = 0;
|
|
||||||
timeout->tv = (struct timeval) {
|
|
||||||
0, 0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
void free_event(event_t *event) {
|
||||||
static int signal_compare(const signal_t *a, const signal_t *b) {
|
free(event);
|
||||||
return a->signum - b->signum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static io_t signalio;
|
void event_add(event_t *event) {
|
||||||
static int pipefd[2] = {-1, -1};
|
event->id = ++id;
|
||||||
static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare};
|
avl_insert(event_tree, event);
|
||||||
|
|
||||||
static void signal_handler(int signum) {
|
|
||||||
unsigned char num = signum;
|
|
||||||
write(pipefd[1], &num, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signalio_handler(void *data, int flags) {
|
void event_del(event_t *event) {
|
||||||
(void)data;
|
avl_delete(event_tree, event);
|
||||||
(void)flags;
|
|
||||||
unsigned char signum;
|
|
||||||
|
|
||||||
if(read(pipefd[0], &signum, 1) != 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
signal_t *sig = splay_search(&signal_tree, &((signal_t) {
|
|
||||||
.signum = signum
|
|
||||||
}));
|
|
||||||
|
|
||||||
if(sig) {
|
|
||||||
sig->cb(sig->data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pipe_init(void) {
|
event_t *get_expired_event(void) {
|
||||||
if(!pipe(pipefd)) {
|
event_t *event;
|
||||||
io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
|
if(event_tree->head) {
|
||||||
if(sig->cb) {
|
event = event_tree->head->data;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sig->cb = cb;
|
if(event->time <= now) {
|
||||||
sig->data = data;
|
avl_node_t *node = event_tree->head;
|
||||||
sig->signum = signum;
|
avl_unlink_node(event_tree, node);
|
||||||
sig->node.data = sig;
|
free(node);
|
||||||
|
return event;
|
||||||
if(pipefd[0] == -1) {
|
|
||||||
pipe_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
signal(sig->signum, signal_handler);
|
|
||||||
|
|
||||||
if(!splay_insert_node(&signal_tree, &sig->node)) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal_del(signal_t *sig) {
|
|
||||||
if(!sig->cb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
signal(sig->signum, SIG_DFL);
|
|
||||||
|
|
||||||
splay_unlink_node(&signal_tree, &sig->node);
|
|
||||||
sig->cb = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct timeval *get_time_remaining(struct timeval *diff) {
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
struct timeval *tv = NULL;
|
|
||||||
|
|
||||||
while(timeout_tree.head) {
|
|
||||||
timeout_t *timeout = timeout_tree.head->data;
|
|
||||||
timersub(&timeout->tv, &now, diff);
|
|
||||||
|
|
||||||
if(diff->tv_sec < 0) {
|
|
||||||
timeout->cb(timeout->data);
|
|
||||||
|
|
||||||
if(timercmp(&timeout->tv, &now, <)) {
|
|
||||||
timeout_del(timeout);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tv = diff;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tv;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool event_loop(void) {
|
event_t *peek_next_event(void) {
|
||||||
running = true;
|
if(event_tree->head) {
|
||||||
|
return event_tree->head->data;
|
||||||
#ifndef HAVE_MINGW
|
|
||||||
fd_set readable;
|
|
||||||
fd_set writable;
|
|
||||||
|
|
||||||
while(running) {
|
|
||||||
struct timeval diff;
|
|
||||||
struct timeval *tv = get_time_remaining(&diff);
|
|
||||||
memcpy(&readable, &readfds, sizeof(readable));
|
|
||||||
memcpy(&writable, &writefds, sizeof(writable));
|
|
||||||
|
|
||||||
int fds = 0;
|
|
||||||
|
|
||||||
if(io_tree.tail) {
|
|
||||||
io_t *last = io_tree.tail->data;
|
|
||||||
fds = last->fd + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = select(fds, &readable, &writable, NULL, tv);
|
|
||||||
|
|
||||||
if(n < 0) {
|
|
||||||
if(sockwouldblock(sockerrno)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!n) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int curgen = io_tree.generation;
|
|
||||||
|
|
||||||
for splay_each(io_t, io, &io_tree) {
|
|
||||||
if(FD_ISSET(io->fd, &writable)) {
|
|
||||||
io->cb(io->data, IO_WRITE);
|
|
||||||
} else if(FD_ISSET(io->fd, &readable)) {
|
|
||||||
io->cb(io->data, IO_READ);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
There are scenarios in which the callback will remove another io_t from the tree
|
|
||||||
(e.g. closing a double connection). Since splay_each does not support that, we
|
|
||||||
need to exit the loop if that happens. That's okay, since any remaining events will
|
|
||||||
get picked up by the next select() call.
|
|
||||||
*/
|
|
||||||
if(curgen != io_tree.generation) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
return NULL;
|
||||||
|
|
||||||
while(running) {
|
|
||||||
struct timeval diff;
|
|
||||||
struct timeval *tv = get_time_remaining(&diff);
|
|
||||||
DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
|
|
||||||
|
|
||||||
if(!event_count) {
|
|
||||||
Sleep(timeout_ms);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
For some reason, Microsoft decided to make the FD_WRITE event edge-triggered instead of level-triggered,
|
|
||||||
which is the opposite of what select() does. In practice, that means that if a FD_WRITE event triggers,
|
|
||||||
it will never trigger again until a send() returns EWOULDBLOCK. Since the semantics of this event loop
|
|
||||||
is that write events are level-triggered (i.e. they continue firing until the socket is full), we need
|
|
||||||
to emulate these semantics by making sure we fire each IO_WRITE that is still writeable.
|
|
||||||
|
|
||||||
Note that technically FD_CLOSE has the same problem, but it's okay because user code does not rely on
|
|
||||||
this event being fired again if ignored.
|
|
||||||
*/
|
|
||||||
unsigned int curgen = io_tree.generation;
|
|
||||||
|
|
||||||
for splay_each(io_t, io, &io_tree) {
|
|
||||||
if(io->flags & IO_WRITE && send(io->fd, NULL, 0, 0) == 0) {
|
|
||||||
io->cb(io->data, IO_WRITE);
|
|
||||||
|
|
||||||
if(curgen != io_tree.generation) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event_count > WSA_MAXIMUM_WAIT_EVENTS) {
|
|
||||||
WSASetLastError(WSA_INVALID_PARAMETER);
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];
|
|
||||||
io_t *io_map[WSA_MAXIMUM_WAIT_EVENTS];
|
|
||||||
DWORD event_index = 0;
|
|
||||||
|
|
||||||
for splay_each(io_t, io, &io_tree) {
|
|
||||||
events[event_index] = io->event;
|
|
||||||
io_map[event_index] = io;
|
|
||||||
event_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the generation number changes due to event addition
|
|
||||||
* or removal by a callback we restart the loop.
|
|
||||||
*/
|
|
||||||
curgen = io_tree.generation;
|
|
||||||
|
|
||||||
for(DWORD event_offset = 0; event_offset < event_count;) {
|
|
||||||
DWORD result = WSAWaitForMultipleEvents(event_count - event_offset, &events[event_offset], FALSE, timeout_ms, FALSE);
|
|
||||||
|
|
||||||
if(result == WSA_WAIT_TIMEOUT) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result < WSA_WAIT_EVENT_0 || result >= WSA_WAIT_EVENT_0 + event_count - event_offset) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look up io in the map by index. */
|
|
||||||
event_index = result - WSA_WAIT_EVENT_0 + event_offset;
|
|
||||||
io_t *io = io_map[event_index];
|
|
||||||
|
|
||||||
if(io->fd == -1) {
|
|
||||||
io->cb(io->data, 0);
|
|
||||||
|
|
||||||
if(curgen != io_tree.generation) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WSANETWORKEVENTS network_events;
|
|
||||||
|
|
||||||
if(WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(network_events.lNetworkEvents & READ_EVENTS) {
|
|
||||||
io->cb(io->data, IO_READ);
|
|
||||||
|
|
||||||
if(curgen != io_tree.generation) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The fd might be available for write too. However, if we already fired the read callback, that
|
|
||||||
callback might have deleted the io (e.g. through terminate_connection()), so we can't fire the
|
|
||||||
write callback here. Instead, we loop back and let the writable io loop above handle it.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Continue checking the rest of the events. */
|
|
||||||
event_offset = event_index + 1;
|
|
||||||
|
|
||||||
/* Just poll the next time through. */
|
|
||||||
timeout_ms = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void event_exit(void) {
|
|
||||||
running = false;
|
|
||||||
}
|
}
|
||||||
|
|
69
src/event.h
69
src/event.h
|
@ -2,8 +2,9 @@
|
||||||
#define TINC_EVENT_H
|
#define TINC_EVENT_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
event.h -- I/O, timeout and signal event handling
|
event.h -- header for event.c
|
||||||
Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
|
2002-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,57 +21,27 @@
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "splay_tree.h"
|
#include "avl_tree.h"
|
||||||
|
|
||||||
#define IO_READ 1
|
extern avl_tree_t *event_tree;
|
||||||
#define IO_WRITE 2
|
|
||||||
|
|
||||||
typedef void (*io_cb_t)(void *data, int flags);
|
typedef void (*event_handler_t)(void *);
|
||||||
typedef void (*timeout_cb_t)(void *data);
|
|
||||||
typedef void (*signal_cb_t)(void *data);
|
|
||||||
|
|
||||||
typedef struct io_t {
|
typedef struct event {
|
||||||
int fd;
|
time_t time;
|
||||||
int flags;
|
int id;
|
||||||
#ifdef HAVE_MINGW
|
event_handler_t handler;
|
||||||
WSAEVENT event;
|
|
||||||
#endif
|
|
||||||
io_cb_t cb;
|
|
||||||
void *data;
|
void *data;
|
||||||
splay_node_t node;
|
} event_t;
|
||||||
} io_t;
|
|
||||||
|
|
||||||
typedef struct timeout_t {
|
extern void init_events(void);
|
||||||
struct timeval tv;
|
extern void exit_events(void);
|
||||||
timeout_cb_t cb;
|
extern void expire_events(void);
|
||||||
void *data;
|
extern event_t *new_event(void) __attribute__((__malloc__));
|
||||||
splay_node_t node;
|
extern void free_event(event_t *event);
|
||||||
} timeout_t;
|
extern void event_add(event_t *event);
|
||||||
|
extern void event_del(event_t *event);
|
||||||
typedef struct signal_t {
|
extern event_t *get_expired_event(void);
|
||||||
int signum;
|
extern event_t *peek_next_event(void);
|
||||||
signal_cb_t cb;
|
|
||||||
void *data;
|
|
||||||
splay_node_t node;
|
|
||||||
} signal_t;
|
|
||||||
|
|
||||||
extern struct timeval now;
|
|
||||||
|
|
||||||
extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags);
|
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
extern void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event);
|
|
||||||
#endif
|
|
||||||
extern void io_del(io_t *io);
|
|
||||||
extern void io_set(io_t *io, int flags);
|
|
||||||
|
|
||||||
extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
|
|
||||||
extern void timeout_del(timeout_t *timeout);
|
|
||||||
extern void timeout_set(timeout_t *timeout, struct timeval *tv);
|
|
||||||
|
|
||||||
extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
|
|
||||||
extern void signal_del(signal_t *sig);
|
|
||||||
|
|
||||||
extern bool event_loop(void);
|
|
||||||
extern void event_exit(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
108
src/fake-getaddrinfo.c
Normal file
108
src/fake-getaddrinfo.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* fake library for ssh
|
||||||
|
*
|
||||||
|
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
|
||||||
|
* These functions are defined in rfc2133.
|
||||||
|
*
|
||||||
|
* But these functions are not implemented correctly. The minimum subset
|
||||||
|
* is implemented for ssh use only. For example, 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 = xmalloc_and_zero(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 */
|
57
src/fake-getaddrinfo.h
Normal file
57
src/fake-getaddrinfo.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef TINC_FAKE_GETADDRINFO_H
|
||||||
|
#define TINC_FAKE_GETADDRINFO_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 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
|
64
src/fake-getnameinfo.c
Normal file
64
src/fake-getnameinfo.c
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* fake library for ssh
|
||||||
|
*
|
||||||
|
* This file includes getnameinfo().
|
||||||
|
* These functions are defined in rfc2133.
|
||||||
|
*
|
||||||
|
* But these functions are not implemented correctly. The minimum subset
|
||||||
|
* is implemented for ssh use only. For example, 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 */
|
16
src/fake-getnameinfo.h
Normal file
16
src/fake-getnameinfo.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef TINC_FAKE_GETNAMEINFO_H
|
||||||
|
#define TINC_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
|
125
src/fd_device.c
125
src/fd_device.c
|
@ -1,125 +0,0 @@
|
||||||
/*
|
|
||||||
fd_device.c -- Interaction with Android tun fd
|
|
||||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
|
||||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
|
||||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
|
||||||
2016 Pacien TRAN-GIRARD <pacien@pacien.net>
|
|
||||||
|
|
||||||
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 "device.h"
|
|
||||||
#include "ethernet.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "net.h"
|
|
||||||
#include "route.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static inline bool check_config(void) {
|
|
||||||
if(routing_mode == RMODE_SWITCH) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Switch mode not supported (requires unsupported TAP device)!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!get_config_int(lookup_config(config_tree, "Device"), &device_fd)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not read fd from configuration!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool setup_device(void) {
|
|
||||||
if(!check_config()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(device_fd < 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s!", device, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "fd/%d adapter set up.", device_fd);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_device(void) {
|
|
||||||
close(device_fd);
|
|
||||||
device_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t get_ip_ethertype(vpn_packet_t *packet) {
|
|
||||||
switch(DATA(packet)[ETH_HLEN] >> 4) {
|
|
||||||
case 4:
|
|
||||||
return ETH_P_IP;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
return ETH_P_IPV6;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ETH_P_MAX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void set_etherheader(vpn_packet_t *packet, uint16_t ethertype) {
|
|
||||||
memset(DATA(packet), 0, ETH_HLEN - ETHER_TYPE_LEN);
|
|
||||||
|
|
||||||
DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN] = (ethertype >> 8) & 0xFF;
|
|
||||||
DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN + 1] = ethertype & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_packet(vpn_packet_t *packet) {
|
|
||||||
int lenin = read(device_fd, DATA(packet) + ETH_HLEN, MTU - ETH_HLEN);
|
|
||||||
|
|
||||||
if(lenin <= 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from fd/%d: %s!", device_fd, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ethertype = get_ip_ethertype(packet);
|
|
||||||
|
|
||||||
if(ethertype == ETH_P_MAX) {
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version while reading packet from fd/%d!", device_fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_etherheader(packet, ethertype);
|
|
||||||
packet->len = lenin + ETH_HLEN;
|
|
||||||
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from fd/%d.", packet->len, device_fd);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write_packet(vpn_packet_t *packet) {
|
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to fd/%d.", packet->len, device_fd);
|
|
||||||
|
|
||||||
if(write(device_fd, DATA(packet) + ETH_HLEN, packet->len - ETH_HLEN) < 0) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to fd/%d: %s!", device_fd, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const devops_t fd_devops = {
|
|
||||||
.setup = setup_device,
|
|
||||||
.close = close_device,
|
|
||||||
.read = read_packet,
|
|
||||||
.write = write_packet,
|
|
||||||
};
|
|
603
src/fsck.c
603
src/fsck.c
|
@ -1,603 +0,0 @@
|
||||||
/*
|
|
||||||
fsck.c -- Check the configuration files for problems
|
|
||||||
Copyright (C) 2014 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 "crypto.h"
|
|
||||||
#include "ecdsa.h"
|
|
||||||
#include "ecdsagen.h"
|
|
||||||
#include "fsck.h"
|
|
||||||
#include "names.h"
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
#include "rsa.h"
|
|
||||||
#include "rsagen.h"
|
|
||||||
#endif
|
|
||||||
#include "tincctl.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
static bool ask_fix(void) {
|
|
||||||
if(force) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!tty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
again:
|
|
||||||
fprintf(stderr, "Fix y/n? ");
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
if(!fgets(buf, sizeof(buf), stdin)) {
|
|
||||||
tty = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buf[0] == 'y' || buf[0] == 'Y') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(buf[0] == 'n' || buf[0] == 'N') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_tinc_cmd(const char *argv0, const char *format, ...) {
|
|
||||||
if(confbasegiven) {
|
|
||||||
fprintf(stderr, "%s -c %s ", argv0, confbase);
|
|
||||||
} else if(netname) {
|
|
||||||
fprintf(stderr, "%s -n %s ", argv0, netname);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "%s ", argv0);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
vfprintf(stderr, format, va);
|
|
||||||
va_end(va);
|
|
||||||
fputc('\n', stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int strtailcmp(const char *str, const char *tail) {
|
|
||||||
size_t slen = strlen(str);
|
|
||||||
size_t tlen = strlen(tail);
|
|
||||||
|
|
||||||
if(tlen > slen) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return memcmp(str + slen - tlen, tail, tlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_conffile(const char *fname, bool server) {
|
|
||||||
(void)server;
|
|
||||||
|
|
||||||
FILE *f = fopen(fname, "r");
|
|
||||||
|
|
||||||
if(!f) {
|
|
||||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char line[2048];
|
|
||||||
int lineno = 0;
|
|
||||||
bool skip = false;
|
|
||||||
const int maxvariables = 50;
|
|
||||||
int count[maxvariables];
|
|
||||||
memset(count, 0, sizeof(count));
|
|
||||||
|
|
||||||
while(fgets(line, sizeof(line), f)) {
|
|
||||||
if(skip) {
|
|
||||||
if(!strncmp(line, "-----END", 8)) {
|
|
||||||
skip = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if(!strncmp(line, "-----BEGIN", 10)) {
|
|
||||||
skip = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
char *variable, *value, *eol;
|
|
||||||
variable = value = line;
|
|
||||||
|
|
||||||
lineno++;
|
|
||||||
|
|
||||||
eol = line + strlen(line);
|
|
||||||
|
|
||||||
while(strchr("\t \r\n", *--eol)) {
|
|
||||||
*eol = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!line[0] || line[0] == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strcspn(value, "\t =");
|
|
||||||
value += len;
|
|
||||||
value += strspn(value, "\t ");
|
|
||||||
|
|
||||||
if(*value == '=') {
|
|
||||||
value++;
|
|
||||||
value += strspn(value, "\t ");
|
|
||||||
}
|
|
||||||
|
|
||||||
variable[len] = '\0';
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for(int i = 0; variables[i].name; i++) {
|
|
||||||
if(strcasecmp(variables[i].name, variable)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
if(variables[i].type & VAR_OBSOLETE) {
|
|
||||||
fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n", variable, fname, lineno);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(i < maxvariables) {
|
|
||||||
count[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found) {
|
|
||||||
fprintf(stderr, "WARNING: unknown variable %s in %s line %d\n", variable, fname, lineno);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!*value) {
|
|
||||||
fprintf(stderr, "ERROR: no value for variable %s in %s line %d\n", variable, fname, lineno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; variables[i].name && i < maxvariables; i++) {
|
|
||||||
if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) {
|
|
||||||
fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n", variables[i].name, fname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ferror(f)) {
|
|
||||||
fprintf(stderr, "ERROR: while reading %s: %s\n", fname, strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsck(const char *argv0) {
|
|
||||||
#ifdef HAVE_MINGW
|
|
||||||
int uid = 0;
|
|
||||||
#else
|
|
||||||
uid_t uid = getuid();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check that tinc.conf is readable.
|
|
||||||
|
|
||||||
if(access(tinc_conf, R_OK)) {
|
|
||||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
|
|
||||||
|
|
||||||
if(errno == ENOENT) {
|
|
||||||
fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
|
|
||||||
print_tinc_cmd(argv0, "init");
|
|
||||||
} else if(errno == EACCES) {
|
|
||||||
if(uid != 0) {
|
|
||||||
fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *name = get_my_name(true);
|
|
||||||
|
|
||||||
if(!name) {
|
|
||||||
fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for private keys.
|
|
||||||
// TODO: use RSAPrivateKeyFile and Ed25519PrivateKeyFile variables if present.
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
char fname[PATH_MAX];
|
|
||||||
char dname[PATH_MAX];
|
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
rsa_t *rsa_priv = NULL;
|
|
||||||
snprintf(fname, sizeof(fname), "%s/rsa_key.priv", confbase);
|
|
||||||
|
|
||||||
if(stat(fname, &st)) {
|
|
||||||
if(errno != ENOENT) {
|
|
||||||
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
|
|
||||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
|
||||||
fprintf(stderr, "Please correct this error.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FILE *f = fopen(fname, "r");
|
|
||||||
|
|
||||||
if(!f) {
|
|
||||||
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rsa_priv = rsa_read_pem_private_key(f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
if(!rsa_priv) {
|
|
||||||
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
|
|
||||||
fprintf(stderr, "You can generate a new RSA key with:\n\n");
|
|
||||||
print_tinc_cmd(argv0, "generate-rsa-keys");
|
|
||||||
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) {
|
|
||||||
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
|
|
||||||
} else if(ask_fix()) {
|
|
||||||
if(chmod(fname, st.st_mode & ~077)) {
|
|
||||||
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa_priv = NULL;
|
|
||||||
snprintf(fname, sizeof(fname), "%s/ed25519_key.priv", confbase);
|
|
||||||
|
|
||||||
if(stat(fname, &st)) {
|
|
||||||
if(errno != ENOENT) {
|
|
||||||
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
|
|
||||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
|
||||||
fprintf(stderr, "Please correct this error.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FILE *f = fopen(fname, "r");
|
|
||||||
|
|
||||||
if(!f) {
|
|
||||||
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ecdsa_priv = ecdsa_read_pem_private_key(f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
if(!ecdsa_priv) {
|
|
||||||
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
|
|
||||||
fprintf(stderr, "You can generate a new Ed25519 key with:\n\n");
|
|
||||||
print_tinc_cmd(argv0, "generate-ed25519-keys");
|
|
||||||
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) {
|
|
||||||
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
|
|
||||||
} else if(ask_fix()) {
|
|
||||||
if(chmod(fname, st.st_mode & ~077)) {
|
|
||||||
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DISABLE_LEGACY
|
|
||||||
|
|
||||||
if(!ecdsa_priv) {
|
|
||||||
fprintf(stderr, "ERROR: No Ed25519 private key found.\n");
|
|
||||||
#else
|
|
||||||
|
|
||||||
if(!rsa_priv && !ecdsa_priv) {
|
|
||||||
fprintf(stderr, "ERROR: Neither RSA or Ed25519 private key found.\n");
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "You can generate new keys with:\n\n");
|
|
||||||
print_tinc_cmd(argv0, "generate-keys");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for public keys.
|
|
||||||
// TODO: use RSAPublicKeyFile variable if present.
|
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, name);
|
|
||||||
|
|
||||||
if(access(fname, R_OK)) {
|
|
||||||
fprintf(stderr, "WARNING: cannot read %s\n", fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
#ifndef DISABLE_LEGACY
|
|
||||||
rsa_t *rsa_pub = NULL;
|
|
||||||
|
|
||||||
f = fopen(fname, "r");
|
|
||||||
|
|
||||||
if(f) {
|
|
||||||
rsa_pub = rsa_read_pem_public_key(f);
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rsa_priv) {
|
|
||||||
if(!rsa_pub) {
|
|
||||||
fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
|
|
||||||
|
|
||||||
if(ask_fix()) {
|
|
||||||
FILE *f = fopen(fname, "a");
|
|
||||||
|
|
||||||
if(f) {
|
|
||||||
if(rsa_write_pem_public_key(rsa_priv, f)) {
|
|
||||||
fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: suggest remedies
|
|
||||||
size_t len = rsa_size(rsa_priv);
|
|
||||||
|
|
||||||
if(len != rsa_size(rsa_pub)) {
|
|
||||||
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf1[len], buf2[len], buf3[len];
|
|
||||||
randomize(buf1, sizeof(buf1));
|
|
||||||
buf1[0] &= 0x7f;
|
|
||||||
memset(buf2, 0, sizeof(buf2));
|
|
||||||
memset(buf3, 0, sizeof(buf2));
|
|
||||||
|
|
||||||
if(!rsa_public_encrypt(rsa_pub, buf1, sizeof(buf1), buf2)) {
|
|
||||||
fprintf(stderr, "ERROR: public RSA key does not work.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!rsa_private_decrypt(rsa_priv, buf2, sizeof(buf2), buf3)) {
|
|
||||||
fprintf(stderr, "ERROR: private RSA key does not work.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(memcmp(buf1, buf3, sizeof(buf1))) {
|
|
||||||
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(rsa_pub) {
|
|
||||||
fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ecdsa_t *ecdsa_pub = NULL;
|
|
||||||
|
|
||||||
f = fopen(fname, "r");
|
|
||||||
|
|
||||||
if(f) {
|
|
||||||
ecdsa_pub = get_pubkey(f);
|
|
||||||
|
|
||||||
if(!ecdsa_pub) {
|
|
||||||
rewind(f);
|
|
||||||
ecdsa_pub = ecdsa_read_pem_public_key(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ecdsa_priv) {
|
|
||||||
if(!ecdsa_pub) {
|
|
||||||
fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
|
|
||||||
|
|
||||||
if(ask_fix()) {
|
|
||||||
FILE *f = fopen(fname, "a");
|
|
||||||
|
|
||||||
if(f) {
|
|
||||||
if(ecdsa_write_pem_public_key(ecdsa_priv, f)) {
|
|
||||||
fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: suggest remedies
|
|
||||||
char *key1 = ecdsa_get_base64_public_key(ecdsa_pub);
|
|
||||||
|
|
||||||
if(!key1) {
|
|
||||||
fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *key2 = ecdsa_get_base64_public_key(ecdsa_priv);
|
|
||||||
|
|
||||||
if(!key2) {
|
|
||||||
free(key1);
|
|
||||||
fprintf(stderr, "ERROR: private Ed25519 key does not work.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = strcmp(key1, key2);
|
|
||||||
free(key1);
|
|
||||||
free(key2);
|
|
||||||
|
|
||||||
if(result) {
|
|
||||||
fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(ecdsa_pub) {
|
|
||||||
fprintf(stderr, "WARNING: A public Ed25519 key was found but no private key is known.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether scripts are executable
|
|
||||||
|
|
||||||
struct dirent *ent;
|
|
||||||
DIR *dir = opendir(confbase);
|
|
||||||
|
|
||||||
if(!dir) {
|
|
||||||
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((ent = readdir(dir))) {
|
|
||||||
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(fname, ent->d_name, sizeof(fname));
|
|
||||||
char *dash = strrchr(fname, '-');
|
|
||||||
|
|
||||||
if(!dash) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dash = 0;
|
|
||||||
|
|
||||||
if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
|
|
||||||
static bool explained = false;
|
|
||||||
fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
|
|
||||||
|
|
||||||
if(!explained) {
|
|
||||||
fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
|
|
||||||
fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
|
|
||||||
explained = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
|
|
||||||
|
|
||||||
if(access(fname, R_OK | X_OK)) {
|
|
||||||
if(errno != EACCES) {
|
|
||||||
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
|
|
||||||
|
|
||||||
if(ask_fix()) {
|
|
||||||
if(chmod(fname, 0755)) {
|
|
||||||
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
snprintf(dname, sizeof(dname), "%s" SLASH "hosts", confbase);
|
|
||||||
dir = opendir(dname);
|
|
||||||
|
|
||||||
if(!dir) {
|
|
||||||
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", dname, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((ent = readdir(dir))) {
|
|
||||||
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(fname, ent->d_name, sizeof(fname));
|
|
||||||
char *dash = strrchr(fname, '-');
|
|
||||||
|
|
||||||
if(!dash) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dash = 0;
|
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
|
||||||
|
|
||||||
if(access(fname, R_OK | X_OK)) {
|
|
||||||
if(errno != EACCES) {
|
|
||||||
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
|
|
||||||
|
|
||||||
if(ask_fix()) {
|
|
||||||
if(chmod(fname, 0755)) {
|
|
||||||
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
// Check for obsolete / unsafe / unknown configuration variables.
|
|
||||||
|
|
||||||
check_conffile(tinc_conf, true);
|
|
||||||
|
|
||||||
dir = opendir(dname);
|
|
||||||
|
|
||||||
if(dir) {
|
|
||||||
while((ent = readdir(dir))) {
|
|
||||||
if(!check_id(ent->d_name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
|
||||||
check_conffile(fname, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
25
src/fsck.h
25
src/fsck.h
|
@ -1,25 +0,0 @@
|
||||||
#ifndef TINC_FSCK_H
|
|
||||||
#define TINC_FSCK_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
fsck.h -- header for fsck.c.
|
|
||||||
Copyright (C) 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern int fsck(const char *argv0);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,284 +0,0 @@
|
||||||
/*
|
|
||||||
cipher.c -- Symmetric block cipher handling
|
|
||||||
Copyright (C) 2007-2012 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 "cipher.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
const char *name;
|
|
||||||
int algo;
|
|
||||||
int mode;
|
|
||||||
int nid;
|
|
||||||
} ciphertable[] = {
|
|
||||||
{"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
|
|
||||||
|
|
||||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
|
|
||||||
{"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
|
|
||||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
|
|
||||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
|
|
||||||
|
|
||||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
|
|
||||||
{"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
|
|
||||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
|
|
||||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
|
|
||||||
|
|
||||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
|
|
||||||
{"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
|
|
||||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
|
|
||||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
|
|
||||||
|
|
||||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
|
|
||||||
{"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
|
|
||||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
|
|
||||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool nametocipher(const char *name, int *algo, int *mode) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
|
||||||
if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
|
|
||||||
*algo = ciphertable[i].algo;
|
|
||||||
*mode = ciphertable[i].mode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool nidtocipher(int nid, int *algo, int *mode) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
|
||||||
if(nid == ciphertable[i].nid) {
|
|
||||||
*algo = ciphertable[i].algo;
|
|
||||||
*mode = ciphertable[i].mode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ciphertonid(int algo, int mode, int *nid) {
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
|
||||||
if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
|
|
||||||
*nid = ciphertable[i].nid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cipher_open(cipher_t *cipher, int algo, int mode) {
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
if(!ciphertonid(algo, mode, &cipher->nid)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unable to initialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cipher->keylen = gcry_cipher_get_algo_keylen(algo);
|
|
||||||
cipher->blklen = gcry_cipher_get_algo_blklen(algo);
|
|
||||||
cipher->key = xmalloc(cipher->keylen + cipher->blklen);
|
|
||||||
cipher->padding = mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
|
||||||
int algo, mode;
|
|
||||||
|
|
||||||
if(!nametocipher(name, &algo, &mode)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher name '%s'!", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cipher_open(cipher, algo, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
|
||||||
int algo, mode;
|
|
||||||
|
|
||||||
if(!nidtocipher(nid, &algo, &mode)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher ID %d!", nid);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cipher_open(cipher, algo, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_open_blowfish_ofb(cipher_t *cipher) {
|
|
||||||
return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cipher_close(cipher_t *cipher) {
|
|
||||||
if(cipher->handle) {
|
|
||||||
gcry_cipher_close(cipher->handle);
|
|
||||||
cipher->handle = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cipher->key);
|
|
||||||
cipher->key = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cipher_keylength(const cipher_t *cipher) {
|
|
||||||
return cipher->keylen + cipher->blklen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cipher_get_key(const cipher_t *cipher, void *key) {
|
|
||||||
memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
|
||||||
memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
|
|
||||||
|
|
||||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
|
||||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
|
|
||||||
memcpy(cipher->key, key + len - cipher->keylen, cipher->keylen + cipher->blklen);
|
|
||||||
memcpy(cipher->key + cipher->keylen, key + len - cipher->keylen - cipher->blklen, cipher->blklen);
|
|
||||||
|
|
||||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
|
||||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
|
|
||||||
gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
|
|
||||||
|
|
||||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
|
||||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
|
||||||
gcry_error_t err;
|
|
||||||
uint8_t pad[cipher->blklen];
|
|
||||||
|
|
||||||
if(cipher->padding) {
|
|
||||||
if(!oneshot) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t reqlen = ((inlen + cipher->blklen) / cipher->blklen) * cipher->blklen;
|
|
||||||
|
|
||||||
if(*outlen < reqlen) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: not enough room for padding");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t padbyte = reqlen - inlen;
|
|
||||||
inlen = reqlen - cipher->blklen;
|
|
||||||
|
|
||||||
for(int i = 0; i < cipher->blklen; i++)
|
|
||||||
if(i < cipher->blklen - padbyte) {
|
|
||||||
pad[i] = ((uint8_t *)indata)[inlen + i];
|
|
||||||
} else {
|
|
||||||
pad[i] = padbyte;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(oneshot) {
|
|
||||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cipher->padding) {
|
|
||||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata + inlen, cipher->blklen, pad, cipher->blklen))) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inlen += cipher->blklen;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outlen = inlen;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
if(oneshot) {
|
|
||||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((err = gcry_cipher_decrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cipher->padding) {
|
|
||||||
if(!oneshot) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t padbyte = ((uint8_t *)outdata)[inlen - 1];
|
|
||||||
|
|
||||||
if(padbyte == 0 || padbyte > cipher->blklen || padbyte > inlen) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t origlen = inlen - padbyte;
|
|
||||||
|
|
||||||
for(int i = inlen - 1; i >= origlen; i--)
|
|
||||||
if(((uint8_t *)outdata)[i] != padbyte) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outlen = origlen;
|
|
||||||
} else {
|
|
||||||
*outlen = inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cipher_get_nid(const cipher_t *cipher) {
|
|
||||||
return cipher->nid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cipher_active(const cipher_t *cipher) {
|
|
||||||
return cipher->nid != 0;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
|
||||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "system.h"
|
|
||||||
|
|
||||||
#include <gcrypt.h>
|
|
||||||
|
|
||||||
#include "crypto.h"
|
|
||||||
|
|
||||||
void crypto_init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void crypto_exit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void randomize(void *out, size_t outlen) {
|
|
||||||
gcry_create_nonce(out, outlen);
|
|
||||||
}
|
|
|
@ -1,182 +0,0 @@
|
||||||
/*
|
|
||||||
digest.c -- Digest handling
|
|
||||||
Copyright (C) 2007-2012 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 "digest.h"
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
const char *name;
|
|
||||||
int algo;
|
|
||||||
int nid;
|
|
||||||
} digesttable[] = {
|
|
||||||
{"none", GCRY_MD_NONE, 0},
|
|
||||||
{"sha1", GCRY_MD_SHA1, 64},
|
|
||||||
{"sha256", GCRY_MD_SHA256, 672},
|
|
||||||
{"sha384", GCRY_MD_SHA384, 673},
|
|
||||||
{"sha512", GCRY_MD_SHA512, 674},
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool nametodigest(const char *name, int *algo) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
|
||||||
if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
|
|
||||||
*algo = digesttable[i].algo;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool nidtodigest(int nid, int *algo) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
|
||||||
if(nid == digesttable[i].nid) {
|
|
||||||
*algo = digesttable[i].algo;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool digesttonid(int algo, int *nid) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
|
||||||
if(algo == digesttable[i].algo) {
|
|
||||||
*nid = digesttable[i].nid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool digest_open(digest_t *digest, int algo, int maclength) {
|
|
||||||
if(!digesttonid(algo, &digest->nid)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int len = gcry_md_get_algo_dlen(algo);
|
|
||||||
|
|
||||||
if(maclength > len || maclength < 0) {
|
|
||||||
digest->maclength = len;
|
|
||||||
} else {
|
|
||||||
digest->maclength = maclength;
|
|
||||||
}
|
|
||||||
|
|
||||||
digest->algo = algo;
|
|
||||||
digest->hmac = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
|
|
||||||
int algo;
|
|
||||||
|
|
||||||
if(!nametodigest(name, &algo)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return digest_open(digest, algo, maclength);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
|
|
||||||
int algo;
|
|
||||||
|
|
||||||
if(!nidtodigest(nid, &algo)) {
|
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest ID %d!", nid);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return digest_open(digest, algo, maclength);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_open_sha1(digest_t *digest, int maclength) {
|
|
||||||
return digest_open(digest, GCRY_MD_SHA1, maclength);
|
|
||||||
}
|
|
||||||
|
|
||||||
void digest_close(digest_t *digest) {
|
|
||||||
if(digest->hmac) {
|
|
||||||
gcry_md_close(digest->hmac);
|
|
||||||
}
|
|
||||||
|
|
||||||
digest->hmac = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
|
|
||||||
if(!digest->hmac) {
|
|
||||||
gcry_md_open(&digest->hmac, digest->algo, GCRY_MD_FLAG_HMAC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!digest->hmac) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !gcry_md_setkey(digest->hmac, key, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
|
|
||||||
unsigned int len = gcry_md_get_algo_dlen(digest->algo);
|
|
||||||
|
|
||||||
if(digest->hmac) {
|
|
||||||
char *tmpdata;
|
|
||||||
gcry_md_reset(digest->hmac);
|
|
||||||
gcry_md_write(digest->hmac, indata, inlen);
|
|
||||||
tmpdata = gcry_md_read(digest->hmac, digest->algo);
|
|
||||||
|
|
||||||
if(!tmpdata) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(outdata, tmpdata, digest->maclength);
|
|
||||||
} else {
|
|
||||||
char tmpdata[len];
|
|
||||||
gcry_md_hash_buffer(digest->algo, tmpdata, indata, inlen);
|
|
||||||
memcpy(outdata, tmpdata, digest->maclength);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
|
|
||||||
unsigned int len = digest->maclength;
|
|
||||||
char outdata[len];
|
|
||||||
|
|
||||||
return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int digest_get_nid(const digest_t *digest) {
|
|
||||||
return digest->nid;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t digest_length(const digest_t *digest) {
|
|
||||||
return digest->maclength;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool digest_active(const digest_t *digest) {
|
|
||||||
return digest->algo != GCRY_MD_NONE;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue