Import Debian changes 1.1~pre3-1

tinc (1.1~pre3-1) experimental; urgency=low

  * New upstream release.
  * Bump Standards-Version.
  * Enable parallel builds.
  * Bump debian/compat to 9, so tinc gets build with hardening flags.
  * Move tinc-gui to its own package.
This commit is contained in:
Guus Sliepen 2012-10-14 23:51:21 +02:00
commit cfba637f96
143 changed files with 13983 additions and 4872 deletions

View file

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

1976
ChangeLog

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
@ -226,6 +226,11 @@ order to use an ANSI C compiler:
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended

View file

@ -1,9 +1,9 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@ -42,7 +59,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@ -60,6 +78,11 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
install-pdf-recursive install-ps-recursive install-recursive \
installcheck-recursive installdirs-recursive pdf-recursive \
ps-recursive uninstall-recursive
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@ -72,9 +95,11 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d "$(distdir)" \
|| { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr "$(distdir)"; }; }
if test -d "$(distdir)"; then \
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
@ -103,6 +128,8 @@ am__relativize = \
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@ -152,6 +179,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -214,7 +242,7 @@ all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
.SUFFIXES:
am--refresh:
am--refresh: Makefile
@:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
@ -250,10 +278,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
config.h: stamp-h1
@if test ! -f $@; then \
rm -f stamp-h1; \
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
else :; fi
@if test ! -f $@; then rm -f stamp-h1; else :; fi
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
@ -435,13 +461,10 @@ distdir: $(DISTFILES)
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d "$(distdir)/$$subdir" \
$(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
@ -473,7 +496,11 @@ dist-gzip: distdir
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-lzip: distdir
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
$(am__remove_distdir)
dist-lzma: distdir
@ -481,7 +508,7 @@ dist-lzma: distdir
$(am__remove_distdir)
dist-xz: distdir
tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__remove_distdir)
dist-tarZ: distdir
@ -512,6 +539,8 @@ distcheck: dist
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lzma*) \
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \
@ -521,7 +550,7 @@ distcheck: dist
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
chmod -R a-w $(distdir); chmod u+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
@ -531,6 +560,7 @@ distcheck: dist
&& am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
@ -559,8 +589,16 @@ distcheck: dist
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@$(am__cd) '$(distuninstallcheck_dir)' \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
@test -n '$(distuninstallcheck_dir)' || { \
echo 'ERROR: trying to run $@ with an empty' \
'$$(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
$(am__cd) '$(distuninstallcheck_dir)' || { \
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
@ -591,10 +629,15 @@ install-am: all-am
installcheck: installcheck-recursive
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
@ -681,17 +724,18 @@ uninstall-am:
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
all all-am am--refresh check check-am clean clean-generic \
ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \
distclean distclean-generic distclean-hdr distclean-tags \
distcleancheck distdir distuninstallcheck dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs installdirs-am maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
distcheck distclean distclean-generic distclean-hdr \
distclean-tags distcleancheck distdir distuninstallcheck dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs installdirs-am \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \
uninstall uninstall-am
ChangeLog:

70
NEWS
View file

@ -1,4 +1,28 @@
Version 1.1pre2 Juli 17 2011
Version 1.1pre3 October 14 2012
* New experimental protocol:
* Uses 521 bit ECDSA keys for authentication.
* Uses AES-256-CTR and HMAC-SHA256.
* Always provides perfect forward secrecy.
* Used for both meta-connections and VPN packets.
* VPN packets are encrypted end-to-end.
* Many improvements to tincctl:
* "config" command shows/adds/changes configuration variables.
* "export" and "import" commands help exchange configuration files.
* "init" command sets up initial configuration files.
* "info" command shows details about a node, subnet or address.
* "log" command shows live log messages.
* Without a command it acts as a shell, with history and TAB completion.
* Improved starting/stopping tincd.
* Improved graph output.
* When trying to directly send UDP packets to a node for which multiple
addresses are known, all of them are tried.
* Many small fixes, code cleanups and documentation updates.
Version 1.1pre2 July 17 2011
* .cookie files are renamed to .pid files, which are compatible with 1.0.x.
@ -28,6 +52,50 @@ Version 1.1pre1 June 25 2011
Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
version of tinc.
Version 1.0.19 June 25 2012
* Allow :: notation in IPv6 Subnets.
* Add support for systemd style socket activation.
* Allow environment variables to be used for the Name option.
* Add basic support for SOCKS proxies, HTTP proxies, and proxying through an
external command.
Version 1.0.18 March 25 2012
* Fixed IPv6 in switch mode by turning off DecrementTTL by default.
* Allow a port number to be specified in BindToAddress, which also allows tinc
to listen on multiple ports.
* Add support for multicast communication with UML/QEMU/KVM.
Version 1.0.17 March 10 2012
* The DeviceType option can now be used to select dummy, raw socket, UML and
VDE devices without needing to recompile tinc.
* Allow multiple BindToAddress statements.
* Decrement TTL value of IPv4 and IPv6 packets.
* Add LocalDiscovery option allowing tinc to detect peers that are behind the
same NAT.
* Accept Subnets passed with the -o option when StrictSubnets = yes.
* Disabling old RSA keys when generating new ones now also works properly on
Windows.
Version 1.0.16 July 23 2011
* Fixed a performance issue with TCP communication under Windows.
* Fixed code that, during network outages, would cause tinc to exit when it
thought two nodes with identical Names were on the VPN.
Version 1.0.15 June 24 2011
* Improved logging to file.

88
README
View file

@ -1,7 +1,7 @@
This is the README file for tinc version 1.1pre2. Installation
This is the README file for tinc version 1.1pre3. Installation
instructions may be found in the INSTALL file.
tinc is Copyright (C) 1998-2011 by:
tinc is Copyright (C) 1998-2012 by:
Ivo Timmermans,
Guus Sliepen <guus@tinc-vpn.org>,
@ -29,82 +29,66 @@ protocol is not fixed yet.
Security statement
------------------
This version uses an experimental and unfinished cryptographic protocol. Use
it at your own risk.
This version uses an experimental and unfinished cryptographic protocol. Use it
at your own risk.
Compatibility
-------------
Version 1.1pre2 is compatible with 1.0pre8, 1.0 and later, but not with older
Version 1.1pre3 is compatible with 1.0pre8, 1.0 and later, but not with older
versions of tinc.
When the ExperimentalProtocol option is used, tinc is still compatible with
1.0.X and 1.1pre2 itself, but not with any other 1.1preX version.
1.0.X and 1.1pre3 itself, but not with any other 1.1preX version.
Requirements
------------
Either OpenSSL (http://www.openssl.org/) or libgcrypt
(http://www.gnupg.org/download/#libgcrypt).
The zlib library is used for optional compression. You can find it at
http://www.gzip.org/zlib/.
The lzo library is also used for optional compression. You can find it at
http://www.oberhumer.com/opensource/lzo/.
Since 1.1, the libevent library is used for the main event loop. You can find
it at http://monkey.org/~provos/libevent/.
In order to compile tinc, you will need a GNU C compiler environment. Please
ensure you have the latest stable versions of all the required libraries.
ensure you have the latest stable versions of all the required libraries:
- OpenSSL (http://www.openssl.org/) version 1.0.0 or later.
- Libevent (http://monkey.org/~provos/libevent/)
The following libraries are used by default, but can be disabled if necessary:
- zlib (http://www.gzip.org/zlib/)
- lzo (http://www.oberhumer.com/opensource/lzo/)
- ncurses (http://invisible-island.net/ncurses/)
- readline (ftp://ftp.gnu.org/pub/gnu/readline/)
Features
--------
This version of tinc supports multiple virtual networks at once. To
use this feature, you may supply a netname via the -n or --net
options. The standard locations for the config files will then be
/etc/tinc/<net>/.
Tinc is a peer-to-peer VPN daemon that supports VPNs with an arbitrary number
of nodes. Instead of configuring tunnels, you give tinc the location and
public key of a few nodes in the VPN. After making the initial connections to
those nodes, tinc will learn about all other nodes on the VPN, and will make
connections automatically. When direct connections are not possible, data will
be forwarded by intermediate nodes.
tincd regenerates its encryption key pairs. It does this on the first
activity after the keys have expired. This period is adjustable in the
configuration file, and the default time is 3600 seconds (one hour).
By default, nodes authenticate each other using 2048 bit RSA (or 521 bit
ECDSA*) keys. Traffic is encrypted using Blowfish in CBC mode (or AES-256 in
CTR mode*), authenticated using HMAC-SHA1 (or HMAC-SHA-256*), and is protected
against replay attacks.
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.
*) When using the ExperimentalProtocol option.
Since pre5, tinc can operate in several routing modes. The default mode,
"router", works exactly like the older version, and uses Subnet lines to
determine the destination of packets. The other two modes, "switch" and "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.
Tinc fully supports IPv6.
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", etcetera. Useful digests are "sha1" (default), "md5",
etcetera.
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, if you need
it use radvd or zebra.
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.
Tinc can operate in several routing modes. In the default mode, "router", every
node is associated with one or more IPv4 and/or IPv6 Subnets. The other two
modes, "switch" and "hub", let the tinc daemons work together to form a virtual
Ethernet network switch or hub.
Normally, when started tinc will detach and run in the background. In a native
Windows environment this means tinc will intall itself as a service, which will
restart after reboots. To prevent tinc from detaching or running as a service,
use the -D option.
The status of the VPN can be queried using the "tincctl" tool, which connects
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.

7
THANKS
View file

@ -3,12 +3,14 @@ We would like to thank the following people for their contributions to tinc:
* Alexander Reil and Gemeinde Berg
* Allesandro Gatti
* Andreas van Cranenburgh
* Anthony G. Basile
* Armijn Hemel
* Brandon Black
* Cris van Pelt
* Delf Eldkraft
* dnk
* Enrique Zanardi
* Erik Tews
* Flynn Marquardt
* Grzegorz Dymarek
* Hans Bayle
@ -26,13 +28,17 @@ We would like to thank the following people for their contributions to tinc:
* Mark Glines
* Markus Goetz
* Martin Kihlgren
* Martin Schürrer
* Matias Carrasco
* Max Rijevski
* Menno Smits
* Mesar Hameed
* Michael Tokarev
* Miles Nordin
* Nick Hibma
* Nick Patavalis
* Paul Littlefield
* Philipp Babel
* Robert van der Meulen
* Rumko
* Scott Lamb
@ -40,6 +46,7 @@ We would like to thank the following people for their contributions to tinc:
* Teemu Kiviniemi
* Timothy Redaelli
* Tonnerre Lombard
* Vil Brekin
* Wessel Dankers
* Wouter van Heyst

79
aclocal.m4 vendored
View file

@ -1,7 +1,8 @@
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
# Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -13,8 +14,8 @@
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
[m4_warning([this file was generated for autoconf 2.68.
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
[m4_warning([this file was generated for autoconf 2.69.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically `autoreconf'.])])
@ -143,12 +144,15 @@ AC_DEFUN([AM_PATH_LIBGCRYPT],
AC_SUBST(LIBGCRYPT_LIBS)
])
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
# Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 1
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been
@ -158,7 +162,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.11'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.11.1], [],
m4_if([$1], [1.11.6], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@ -174,19 +178,21 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.11.1])dnl
[AM_AUTOMAKE_VERSION([1.11.6])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 1
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
@ -268,14 +274,14 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
# Free Software Foundation, Inc.
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
# 2010, 2011 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 10
# serial 12
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
@ -315,6 +321,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
# instance it was reported that on HP-UX the gcc test will end up
# making a dummy file named `D' -- because `-MD' means `put the output
# in D'.
rm -rf conftest.dir
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory.
@ -379,7 +386,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
break
fi
;;
msvisualcpp | msvcmsys)
msvc7 | msvc7msys | msvisualcpp | msvcmsys)
# This compiler won't grok `-c -o', but also, the minuso test has
# not run yet. These depmodes are late enough in the game, and
# so weak that their functioning should not be impacted.
@ -444,10 +451,13 @@ AC_DEFUN([AM_DEP_TRACK],
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
am__nodep='_no'
fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])dnl
_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
AC_SUBST([am__nodep])dnl
_AM_SUBST_NOTMAKE([am__nodep])dnl
])
# Generate code to set up dependency tracking. -*- Autoconf -*-
@ -669,12 +679,15 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
# Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
@ -714,8 +727,8 @@ AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
# Free Software Foundation, Inc.
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
# 2011 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -735,7 +748,7 @@ AC_DEFUN([AM_MAINTAINER_MODE],
[disable], [m4_define([am_maintainer_other], [enable])],
[m4_define([am_maintainer_other], [enable])
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode],
[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
@ -846,12 +859,15 @@ else
fi
])
# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
# Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_MKDIR_P
# ---------------
# Check for `mkdir -p'.
@ -874,13 +890,14 @@ esac
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
# Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# serial 5
# _AM_MANGLE_OPTION(NAME)
# -----------------------
@ -888,13 +905,13 @@ AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME)
# ------------------------------
# --------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# ------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
@ -970,12 +987,14 @@ Check your system clock])
fi
AC_MSG_RESULT(yes)])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
@ -998,13 +1017,13 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# serial 3
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
@ -1013,13 +1032,13 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
AC_DEFUN([_AM_SUBST_NOTMAKE])
# AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# --------------------------
# Public sister of _AM_SUBST_NOTMAKE.
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -1041,10 +1060,11 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# a tarball read from stdin.
# $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
[# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AC_SUBST([AMTAR], ['$${TAR-tar}'])
m4_if([$1], [v7],
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
[am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
[m4_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
@ -1118,4 +1138,5 @@ m4_include([m4/curses.m4])
m4_include([m4/libevent.m4])
m4_include([m4/lzo.m4])
m4_include([m4/openssl.m4])
m4_include([m4/readline.m4])
m4_include([m4/zlib.m4])

49
config.guess vendored
View file

@ -2,9 +2,9 @@
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011 Free Software Foundation, Inc.
# 2011, 2012 Free Software Foundation, Inc.
timestamp='2011-05-11'
timestamp='2012-02-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -17,9 +17,7 @@ timestamp='2011-05-11'
# 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.
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@ -57,8 +55,8 @@ GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
Software Foundation, Inc.
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -145,7 +143,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@ -792,13 +790,12 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
case ${UNAME_MACHINE} in
pc98)
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
@ -807,6 +804,9 @@ EOF
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
i*:MSYS*:*)
echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
# uname -m includes "-pc" on this system.
echo ${UNAME_MACHINE}-mingw32
@ -861,6 +861,13 @@ EOF
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
@ -895,13 +902,16 @@ EOF
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
echo cris-axis-linux-gnu
echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
echo crisv32-axis-linux-gnu
echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
frv:Linux:*:*)
echo frv-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
hexagon:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
i*86:Linux:*:*)
LIBC=gnu
@ -943,7 +953,7 @@ EOF
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
or32:Linux:*:*)
echo or32-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
padre:Linux:*:*)
echo sparc-unknown-linux-gnu
@ -978,13 +988,13 @@ EOF
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
tile*:Linux:*:*)
echo ${UNAME_MACHINE}-tilera-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
echo x86_64-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@ -1315,6 +1325,9 @@ EOF
i*86:AROS:*:*)
echo ${UNAME_MACHINE}-pc-aros
exit ;;
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2

View file

@ -6,6 +6,12 @@
/* Support for tunemu */
#undef ENABLE_TUNEMU
/* Support for UML */
#undef ENABLE_UML
/* Support for VDE */
#undef ENABLE_VDE
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
@ -52,6 +58,12 @@
/* DragonFly */
#undef HAVE_DRAGONFLY
/* Define to 1 if you have the `ECDH_compute_key' function. */
#undef HAVE_ECDH_COMPUTE_KEY
/* Define to 1 if you have the `ECDSA_verify' function. */
#undef HAVE_ECDSA_VERIFY
/* Define to 1 if you have the <event.h> header file. */
#undef HAVE_EVENT_H
@ -88,6 +100,9 @@
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the <libvdeplug_dyn.h> header file. */
#undef HAVE_LIBVDEPLUG_DYN_H
/* Linux */
#undef HAVE_LINUX
@ -148,6 +163,9 @@
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H
/* Define to 1 if you have the <netpacket/packet.h> header file. */
#undef HAVE_NETPACKET_PACKET_H
/* Define to 1 if you have the <net/ethernet.h> header file. */
#undef HAVE_NET_ETHERNET_H
@ -175,6 +193,12 @@
/* OpenBSD */
#undef HAVE_OPENBSD
/* Define to 1 if you have the <openssl/ecdh.h> header file. */
#undef HAVE_OPENSSL_ECDH_H
/* Define to 1 if you have the <openssl/ec.h> header file. */
#undef HAVE_OPENSSL_EC_H
/* Define to 1 if you have the <openssl/engine.h> header file. */
#undef HAVE_OPENSSL_ENGINE_H
@ -205,6 +229,15 @@
/* Define to 1 if you have the `RAND_pseudo_bytes' function. */
#undef HAVE_RAND_PSEUDO_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 `select' function. */
#undef HAVE_SELECT

74
config.sub vendored
View file

@ -2,9 +2,9 @@
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011 Free Software Foundation, Inc.
# 2011, 2012 Free Software Foundation, Inc.
timestamp='2011-03-23'
timestamp='2012-04-18'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@ -21,9 +21,7 @@ timestamp='2011-03-23'
# 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.
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@ -76,8 +74,8 @@ version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
Software Foundation, Inc.
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -132,6 +130,10 @@ case $maybe_os in
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
android-linux)
os=-linux-android
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
@ -223,6 +225,12 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-lynx*178)
os=-lynxos178
;;
-lynx*5)
os=-lynxos5
;;
-lynx*)
os=-lynxos
;;
@ -247,17 +255,22 @@ case $basic_machine in
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
| aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| be32 | be64 \
| bfin \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
| epiphany \
| fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | mcore | mep | metag \
@ -291,7 +304,7 @@ case $basic_machine in
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
| rx \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
@ -300,7 +313,7 @@ case $basic_machine in
| spu \
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@ -315,8 +328,7 @@ case $basic_machine in
c6x)
basic_machine=tic6x-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12 | picochip)
# Motorola 68HC11/12.
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@ -329,7 +341,10 @@ case $basic_machine in
strongarm | thumb | xscale)
basic_machine=arm-unknown
;;
xgate)
basic_machine=$basic_machine-unknown
os=-none
;;
xscaleeb)
basic_machine=armeb-unknown
;;
@ -352,11 +367,13 @@ case $basic_machine in
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| clipper-* | craynv-* | cydra-* \
@ -365,8 +382,10 @@ case $basic_machine in
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
@ -400,7 +419,7 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| romp-* | rs6000-* | rx-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
@ -408,10 +427,11 @@ case $basic_machine in
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile-* | tilegx-* \
| tile*-* \
| tron-* \
| ubicom32-* \
| v850-* | v850e-* | vax-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@ -711,7 +731,6 @@ case $basic_machine in
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
@ -808,10 +827,18 @@ case $basic_machine in
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
basic_machine=i386-pc
os=-msys
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
nacl)
basic_machine=le32-unknown
os=-nacl
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@ -1120,13 +1147,8 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
# This must be matched before tile*.
tilegx*)
basic_machine=tilegx-unknown
os=-linux-gnu
;;
tile*)
basic_machine=tile-unknown
basic_machine=$basic_machine-unknown
os=-linux-gnu
;;
tx39)
@ -1336,7 +1358,7 @@ case $os in
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
@ -1521,6 +1543,9 @@ case $basic_machine in
c4x-* | tic4x-*)
os=-coff
;;
hexagon-*)
os=-elf
;;
tic54x-*)
os=-coff
;;
@ -1548,9 +1573,6 @@ case $basic_machine in
;;
m68000-sun)
os=-sunos3
# This also exists in the configure program, but was not the
# default.
# os=-sunos4
;;
m68*-cisco)
os=-aout

459
configure vendored
View file

@ -1,11 +1,9 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.68.
# Generated by GNU Autoconf 2.69.
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
# Foundation, Inc.
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
@ -134,6 +132,31 @@ export LANGUAGE
# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# Use a proper internal environment variable to ensure we don't fall
# into an infinite loop, continuously re-executing ourselves.
if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
_as_can_reexec=no; export _as_can_reexec;
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
*v*x* | *x*v* ) as_opts=-vx ;;
*v* ) as_opts=-v ;;
*x* ) as_opts=-x ;;
* ) as_opts= ;;
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
{ _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
else
exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1"
test x\$exitcode = x0 || exit 1
test -x / || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@ -212,21 +236,25 @@ IFS=$as_save_IFS
if test "x$CONFIG_SHELL" != x; then :
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
export CONFIG_SHELL
case $- in # ((((
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
BASH_ENV=/dev/null
ENV=/dev/null
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
case $- in # ((((
*v*x* | *x*v* ) as_opts=-vx ;;
*v* ) as_opts=-v ;;
*x* ) as_opts=-x ;;
* ) as_opts= ;;
esac
exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi
if test x$as_have_required = xno; then :
@ -328,6 +356,14 @@ $as_echo X"$as_dir" |
} # as_fn_mkdir_p
# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
test -f "$1" && test -x "$1"
} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
@ -449,6 +485,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
chmod +x "$as_me.lineno" ||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
# already done that, so ensure we don't try to do so again and fall
# in an infinite loop. This has already happened in practice.
_as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
@ -483,16 +523,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
# In both cases, we have to default to `cp -p'.
# In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
as_ln_s='cp -p'
as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
as_ln_s='cp -p'
as_ln_s='cp -pR'
fi
else
as_ln_s='cp -p'
as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@ -504,28 +544,8 @@ else
as_mkdir_p=false
fi
if test -x / >/dev/null 2>&1; then
as_test_x='test -x'
else
if ls -dL / >/dev/null 2>&1; then
as_ls_L_option=L
else
as_ls_L_option=
fi
as_test_x='
eval sh -c '\''
if test -d "$1"; then
test -d "$1/.";
else
case $1 in #(
-*)set "./$1";;
esac;
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
???[sx]*):;;*)false;;esac;fi
'\'' sh
'
fi
as_executable_p=$as_test_x
as_test_x='test -x'
as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@ -607,9 +627,14 @@ INCLUDES
LIBGCRYPT_LIBS
LIBGCRYPT_CFLAGS
LIBGCRYPT_CONFIG
READLINE_LIBS
CURSES_LIBS
TUNEMU_FALSE
TUNEMU_TRUE
VDE_FALSE
VDE_TRUE
UML_FALSE
UML_TRUE
host_os
host_vendor
host_cpu
@ -626,6 +651,7 @@ MAINTAINER_MODE_TRUE
am__fastdepCC_FALSE
am__fastdepCC_TRUE
CCDEPMODE
am__nodep
AMDEPBACKSLASH
AMDEP_FALSE
AMDEP_TRUE
@ -708,6 +734,8 @@ ac_user_opts='
enable_option_checking
enable_dependency_tracking
enable_maintainer_mode
enable_uml
enable_vde
enable_tunemu
with_windows2000
with_libgcrypt
@ -715,6 +743,10 @@ enable_curses
with_curses
with_curses_include
with_curses_lib
enable_readline
with_readline
with_readline_include
with_readline_lib
with_libevent
with_libevent_include
with_libevent_lib
@ -1196,8 +1228,6 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
$as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
If a cross compiler is detected then cross compile mode will be used" >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@ -1363,23 +1393,30 @@ Optional Features:
--enable-dependency-tracking do not reject slow dependency extractors
--enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer
--enable-tunemu enable support for the tunemu driver
--disable-uml enable support for User Mode Linux
--disable-vde enable support for Virtual Distributed Ethernet
--disable-tunemu enable support for the tunemu driver
--disable-curses disable curses support
--disable-readline disable readline support
--disable-zlib disable zlib compression support
--disable-lzo disable lzo compression support
--enable-jumbograms enable support for jumbograms (packets up to 9000
--disable-jumbograms enable support for jumbograms (packets up to 9000
bytes)
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-windows2000 compile with support for Windows 2000. This disables
--without-windows2000 compile with support for Windows 2000. This disables
support for tunneling over existing IPv6 networks.
--with-libgcrypt enable use of libgcrypt instead of OpenSSL]
--with-curses=DIR curses base directory, or:
--with-curses-include=DIR
curses headers directory
--with-curses-lib=DIR curses library directory
--with-readline=DIR readline base directory, or:
--with-readline-include=DIR
readline headers directory
--with-readline-lib=DIR readline library directory
--with-libevent=DIR libevent base directory, or:
--with-libevent-include=DIR
libevent headers directory
@ -1475,9 +1512,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
configure
generated by GNU Autoconf 2.68
generated by GNU Autoconf 2.69
Copyright (C) 2010 Free Software Foundation, Inc.
Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@ -1804,7 +1841,7 @@ $as_echo "$ac_try_echo"; } >&5
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
$as_test_x conftest$ac_exeext
test -x conftest$ac_exeext
}; then :
ac_retval=0
else
@ -1940,7 +1977,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was
generated by GNU Autoconf 2.68. Invocation command line was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2310,7 +2347,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -2350,7 +2387,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -2403,7 +2440,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -2444,7 +2481,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
@ -2502,7 +2539,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -2546,7 +2583,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -2992,8 +3029,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
struct stat;
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
@ -3233,7 +3269,7 @@ do
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
{ test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
as_fn_executable_p "$ac_path_GREP" || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
@ -3299,7 +3335,7 @@ do
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
{ test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
as_fn_executable_p "$ac_path_EGREP" || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
@ -3606,7 +3642,7 @@ case $as_dir/ in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
if test $ac_prog = install &&
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
@ -3775,7 +3811,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -3815,7 +3851,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_STRIP="strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -3866,7 +3902,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; do
{ test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
'mkdir (GNU coreutils) '* | \
'mkdir (coreutils) '* | \
@ -3919,7 +3955,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -4035,6 +4071,7 @@ fi
if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\'
am__nodep='_no'
fi
if test "x$enable_dependency_tracking" != xno; then
AMDEP_TRUE=
@ -4067,7 +4104,7 @@ fi
# Define the identity of the package.
PACKAGE=tinc
VERSION=1.1pre2
VERSION=1.1pre3
cat >>confdefs.h <<_ACEOF
@ -4097,11 +4134,11 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
# Always define AMTAR for backward compatibility.
# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AMTAR='$${TAR-tar}'
AMTAR=${AMTAR-"${am_missing_run}tar"}
am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
@ -4119,6 +4156,7 @@ else
# instance it was reported that on HP-UX the gcc test will end up
# making a dummy file named `D' -- because `-MD' means `put the output
# in D'.
rm -rf conftest.dir
mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory.
@ -4178,7 +4216,7 @@ else
break
fi
;;
msvisualcpp | msvcmsys)
msvc7 | msvc7msys | msvisualcpp | msvcmsys)
# This compiler won't grok `-c -o', but also, the minuso test has
# not run yet. These depmodes are late enough in the game, and
# so weak that their functioning should not be impacted.
@ -4414,7 +4452,7 @@ main ()
return 0;
}
_ACEOF
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"; then :
@ -4611,7 +4649,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -4651,7 +4689,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -4829,13 +4867,70 @@ $as_echo "#define HAVE_MINGW 1" >>confdefs.h
;;
esac
# Check whether --enable-uml was given.
if test "${enable_uml+set}" = set; then :
enableval=$enable_uml; if test "x$enable_uml" = "xyes"; then :
$as_echo "#define ENABLE_UML 1" >>confdefs.h
uml=true
else
uml=false
fi
else
uml=false
fi
# Check whether --enable-vde was given.
if test "${enable_vde+set}" = set; then :
enableval=$enable_vde; if test "x$enable_vde" = "xyes"; then :
for ac_header in libvdeplug_dyn.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "libvdeplug_dyn.h" "ac_cv_header_libvdeplug_dyn_h" "$ac_includes_default"
if test "x$ac_cv_header_libvdeplug_dyn_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBVDEPLUG_DYN_H 1
_ACEOF
else
as_fn_error $? "VDE plug header files not found." "$LINENO" 5; break
fi
done
$as_echo "#define ENABLE_VDE 1" >>confdefs.h
vde=true
else
vde=false
fi
else
vde=false
fi
# Check whether --enable-tunemu was given.
if test "${enable_tunemu+set}" = set; then :
enableval=$enable_tunemu;
enableval=$enable_tunemu; if test "x$enable_tunemu" = "xyes"; then :
$as_echo "#define ENABLE_TUNEMU 1" >>confdefs.h
tunemu=true
else
tunemu=false
fi
else
tunemu=false
fi
@ -4843,13 +4938,32 @@ fi
# Check whether --with-windows2000 was given.
if test "${with_windows2000+set}" = set; then :
withval=$with_windows2000;
withval=$with_windows2000; if test "x$with_windows2000" = "xyes"; then :
$as_echo "#define WITH_WINDOWS2000 1" >>confdefs.h
fi
fi
if test "$uml" = true; then
UML_TRUE=
UML_FALSE='#'
else
UML_TRUE='#'
UML_FALSE=
fi
if test "$vde" = true; then
VDE_TRUE=
VDE_FALSE='#'
else
VDE_TRUE='#'
VDE_FALSE=
fi
if test "$tunemu" = true; then
TUNEMU_TRUE=
TUNEMU_FALSE='#'
@ -5078,7 +5192,7 @@ fi
done
for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h
for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"have.h\"
@ -5135,11 +5249,11 @@ else
int
main ()
{
/* FIXME: Include the comments suggested by Paul. */
#ifndef __cplusplus
/* Ultrix mips cc rejects this. */
/* Ultrix mips cc rejects this sort of thing. */
typedef int charset[2];
const charset cs;
const charset cs = { 0, 0 };
/* SunOS 4.1.1 cc rejects this. */
char const *const *pcpcc;
char **ppc;
@ -5156,8 +5270,9 @@ main ()
++pcpcc;
ppc = (char**) pcpcc;
pcpcc = (char const *const *) ppc;
{ /* SCO 3.2v4 cc rejects this. */
char *t;
{ /* SCO 3.2v4 cc rejects this sort of thing. */
char tx;
char *t = &tx;
char const *s = 0 ? (char *) 0 : (char const *) 0;
*t++ = 0;
@ -5173,10 +5288,10 @@ main ()
iptr p = 0;
++p;
}
{ /* AIX XL C 1.02.0.0 rejects this saying
{ /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
struct s { int j; const int *ap[3]; };
struct s *b; b->j = 5;
struct s { int j; const int *ap[3]; } bx;
struct s *b = &bx; b->j = 5;
}
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10;
@ -5925,6 +6040,111 @@ fi
# Check whether --enable-readline was given.
if test "${enable_readline+set}" = set; then :
enableval=$enable_readline;
fi
if test "x$enable_readline" != "xno"; then :
$as_echo "#define HAVE_READLINE 1" >>confdefs.h
readline=true
# Check whether --with-readline was given.
if test "${with_readline+set}" = set; then :
withval=$with_readline; readline="$withval"
CPPFLAGS="$CPPFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
fi
# Check whether --with-readline-include was given.
if test "${with_readline_include+set}" = set; then :
withval=$with_readline_include; readline_include="$withval"
CPPFLAGS="$CPPFLAGS -I$withval"
fi
# Check whether --with-readline-lib was given.
if test "${with_readline_lib+set}" = set; then :
withval=$with_readline_lib; readline_lib="$withval"
LDFLAGS="$LDFLAGS -L$withval"
fi
for ac_header in readline/readline.h readline/history.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
else
as_fn_error $? "\"readline header files not found.\"" "$LINENO" 5; break
fi
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
$as_echo_n "checking for readline in -lreadline... " >&6; }
if ${ac_cv_lib_readline_readline+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lreadline $CURSES_LIBS
$LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char readline ();
int
main ()
{
return readline ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_readline_readline=yes
else
ac_cv_lib_readline_readline=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
$as_echo "$ac_cv_lib_readline_readline" >&6; }
if test "x$ac_cv_lib_readline_readline" = xyes; then :
READLINE_LIBS="-lreadline"
else
as_fn_error $? "\"readline library not found.\"" "$LINENO" 5
fi
fi
# Check whether --with-libevent was given.
if test "${with_libevent+set}" = set; then :
@ -6326,7 +6546,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -6369,7 +6589,7 @@ do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
@ -6596,7 +6816,7 @@ if test "${with_openssl_lib+set}" = set; then :
fi
for ac_header in openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h
for ac_header in openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h openssl/ecdh.h openssl/ec.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@ -6657,7 +6877,7 @@ else
fi
for ac_func in RAND_pseudo_bytes EVP_EncryptInit_ex
for ac_func in RAND_pseudo_bytes EVP_EncryptInit_ex ECDH_compute_key ECDSA_verify
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -6688,9 +6908,12 @@ fi
# Check whether --enable-jumbograms was given.
if test "${enable_jumbograms+set}" = set; then :
enableval=$enable_jumbograms;
enableval=$enable_jumbograms; if test "x$enable_jumbograms" = "xyes"; then :
$as_echo "#define ENABLE_JUMBOGRAMS 1" >>confdefs.h
fi
fi
@ -6829,6 +7052,14 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${UML_TRUE}" && test -z "${UML_FALSE}"; then
as_fn_error $? "conditional \"UML\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${VDE_TRUE}" && test -z "${VDE_FALSE}"; then
as_fn_error $? "conditional \"VDE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${TUNEMU_TRUE}" && test -z "${TUNEMU_FALSE}"; then
as_fn_error $? "conditional \"TUNEMU\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@ -7131,16 +7362,16 @@ if (echo >conf$$.file) 2>/dev/null; then
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
# In both cases, we have to default to `cp -p'.
# In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
as_ln_s='cp -p'
as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
as_ln_s='cp -p'
as_ln_s='cp -pR'
fi
else
as_ln_s='cp -p'
as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
@ -7200,28 +7431,16 @@ else
as_mkdir_p=false
fi
if test -x / >/dev/null 2>&1; then
as_test_x='test -x'
else
if ls -dL / >/dev/null 2>&1; then
as_ls_L_option=L
else
as_ls_L_option=
fi
as_test_x='
eval sh -c '\''
if test -d "$1"; then
test -d "$1/.";
else
case $1 in #(
-*)set "./$1";;
esac;
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
???[sx]*):;;*)false;;esac;fi
'\'' sh
'
fi
as_executable_p=$as_test_x
# as_fn_executable_p FILE
# -----------------------
# Test if FILE is an executable regular file.
as_fn_executable_p ()
{
test -f "$1" && test -x "$1"
} # as_fn_executable_p
as_test_x='test -x'
as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@ -7243,7 +7462,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by $as_me, which was
generated by GNU Autoconf 2.68. Invocation command line was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@ -7309,10 +7528,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
config.status
configured by $0, generated by GNU Autoconf 2.68,
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
Copyright (C) 2010 Free Software Foundation, Inc.
Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@ -7403,7 +7622,7 @@ fi
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'

View file

@ -4,7 +4,7 @@ AC_PREREQ(2.61)
AC_INIT
AC_CONFIG_SRCDIR([src/tincd.c])
AC_GNU_SOURCE
AM_INIT_AUTOMAKE(tinc, 1.1pre2)
AM_INIT_AUTOMAKE(tinc, 1.1pre3)
AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE
@ -73,18 +73,49 @@ case $host_os in
;;
esac
AC_ARG_ENABLE(uml,
AS_HELP_STRING([--disable-uml], [enable support for User Mode Linux]),
[ AS_IF([test "x$enable_uml" = "xyes"],
[ AC_DEFINE(ENABLE_UML, 1, [Support for UML])
uml=true
],
[uml=false])
],
[uml=false]
)
AC_ARG_ENABLE(vde,
AS_HELP_STRING([--disable-vde], [enable support for Virtual Distributed Ethernet]),
[ AS_IF([test "x$enable_vde" = "xyes"],
[ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break])
AC_DEFINE(ENABLE_VDE, 1, [Support for VDE])
vde=true
],
[vde=false])
],
[vde=false]
)
AC_ARG_ENABLE(tunemu,
AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]),
AS_HELP_STRING([--disable-tunemu], [enable support for the tunemu driver]),
[ AS_IF([test "x$enable_tunemu" = "xyes"],
[ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
tunemu=true
]
],
[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.]),
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])]
AS_HELP_STRING([--without-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])])
]
)
AM_CONDITIONAL(UML, test "$uml" = true)
AM_CONDITIONAL(VDE, test "$vde" = true)
AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
AC_CACHE_SAVE
@ -101,7 +132,7 @@ dnl We do this in multiple stages, because unlike Linux all the other operating
AC_HEADER_STDC
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
[], [], [#include "have.h"]
)
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
@ -151,6 +182,7 @@ dnl These are defined in files in m4/
AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
tinc_CURSES
tinc_READLINE
tinc_LIBEVENT
tinc_ZLIB
tinc_LZO
@ -166,8 +198,10 @@ fi
dnl Check if support for jumbograms is requested
AC_ARG_ENABLE(jumbograms,
AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ]
AS_HELP_STRING([--disable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
[ AS_IF([test "x$enable_jumbograms" = "xyes"],
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ])
]
)
AC_SUBST(INCLUDES)

2
debian/NEWS vendored
View file

@ -1,6 +1,6 @@
tinc (1.1~pre2-1) experimental; urgency=low
* tinc-1.1 has separate control utility, tincctl, which is now used
tinc-1.1 has separate control utility, tincctl, which is now used
to start/stop tinc instances, to reload configuration, to get
various information about running tincd (including dump of nodes
and connections) and so on. tincd still reacts to some signals

10
debian/changelog vendored
View file

@ -1,3 +1,13 @@
tinc (1.1~pre3-1) experimental; urgency=low
* New upstream release.
* Bump Standards-Version.
* Enable parallel builds.
* Bump debian/compat to 9, so tinc gets build with hardening flags.
* Move tinc-gui to its own package.
-- Guus Sliepen <guus@debian.org> Sun, 14 Oct 2012 23:51:21 +0200
tinc (1.1~pre2-2) experimental; urgency=low
* add forgotten build-depend on libncurses5-dev for new `tincctl top'

2
debian/compat vendored
View file

@ -1 +1 @@
7
9

16
debian/control vendored
View file

@ -2,8 +2,8 @@ Source: tinc
Section: net
Priority: optional
Maintainer: Guus Sliepen <guus@debian.org>
Standards-Version: 3.9.2
Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 7.0.50~), texi2html, texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libevent-dev
Standards-Version: 3.9.3
Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 9), texi2html, texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libevent-dev, libreadline-dev
Homepage: http://www.tinc-vpn.org/
Package: tinc
@ -14,3 +14,15 @@ Description: Virtual Private Network daemon
(VPN). One daemon can handle multiple connections, so you can
create an entire (moderately sized) VPN with only one daemon per
participating computer.
Package: tinc-gui
Architecture: all
Depends: ${misc:Depends}, python, python-wxgtk2.8, tinc (>= 1.1~pre3-1)
Description: graphical user interface for tinc
tinc is a daemon with which you can create a virtual private network
(VPN). One daemon can handle multiple connections, so you can
create an entire (moderately sized) VPN with only one daemon per
participating computer.
.
This package contains a GUI that can interact with a running tinc daemon,
showing the known nodes, edges and subnets of a VPN.

7
debian/rules vendored
View file

@ -9,8 +9,13 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
#include /usr/share/dpkg/buildflags.mk
%:
dh $@
dh $@ --parallel
override_dh_auto_configure:
dh_auto_configure -- --disable-uml --disable-vde
override_dh_auto_build:
dh_auto_build

2
debian/tinc-gui.install vendored Normal file
View file

@ -0,0 +1,2 @@
usr/bin/tinc-gui
usr/share/man/man8/tinc-gui.*

6
debian/tinc.install vendored Normal file
View file

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

190
depcomp
View file

@ -1,10 +1,10 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2009-04-28.21; # UTC
scriptversion=2012-03-27.16; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
# Software Foundation, Inc.
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# 2011, 2012 Free Software Foundation, Inc.
# 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
@ -28,7 +28,7 @@ scriptversion=2009-04-28.21; # UTC
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
@ -40,11 +40,11 @@ as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputing dependencies.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
@ -57,6 +57,12 @@ EOF
;;
esac
# A tabulation character.
tab=' '
# A newline character.
nl='
'
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
@ -90,10 +96,24 @@ if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u="sed s,\\\\\\\\,/,g"
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
@ -148,20 +168,21 @@ gcc)
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
tr ' ' "$nl" < "$tmpdepfile" |
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well.
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@ -193,18 +214,15 @@ sgi)
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> "$depfile"
tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
@ -216,10 +234,17 @@ sgi)
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
@ -249,12 +274,11 @@ aix)
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Each line is of the form 'foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
@ -265,23 +289,26 @@ aix)
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
# However on
# $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# which is wrong. We want
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# and will wrap long lines using '\':
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
# tcc 0.9.26 (FIXME still under development at the moment of writing)
# will emit a similar output, but also prepend the continuation lines
# with horizontal tabulation characters.
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
@ -290,15 +317,21 @@ icc)
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Each line is of the form 'foo.o: dependent.h',
# or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
# '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
< "$tmpdepfile" > "$depfile"
sed '
s/[ '"$tab"'][ '"$tab"']*/ /g
s/^ *//
s/ *\\*$//
s/^[^:]*: *//
/^$/d
/:$/d
s/$/ :/
' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
@ -334,7 +367,7 @@ hp2)
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add `dependent.h:' lines.
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
@ -349,9 +382,9 @@ hp2)
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
@ -397,14 +430,59 @@ tru64)
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test "$stat" = 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
@ -422,7 +500,7 @@ dashmstdout)
shift
fi
# Remove `-o $object'.
# Remove '-o $object'.
IFS=" "
for arg
do
@ -442,15 +520,14 @@ dashmstdout)
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
tr ' ' "$nl" < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@ -503,9 +580,10 @@ makedepend)
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@ -525,7 +603,7 @@ cpp)
shift
fi
# Remove `-o $object'.
# Remove '-o $object'.
IFS=" "
for arg
do
@ -594,8 +672,8 @@ msvisualcpp)
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;

View file

@ -23,16 +23,16 @@ texi2html: tinc.texi
texi2html -split=chapter tinc.texi
tincd.8.html: tincd.8
w3mman2html $< > $@
w3mman2html $? > $@
tincctl.8.html: tincctl.8
w3mman2html $< > $@
w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8
w3mman2html $< > $@
w3mman2html $? > $@
tinc.conf.5.html: tinc.conf.5
w3mman2html $< > $@
w3mman2html $? > $@
substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
@ -41,18 +41,18 @@ substitute = sed \
-e s,'@localstatedir\@',"$(localstatedir)",g
tincd.8: tincd.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tincctl.8: tincctl.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc.conf.5: tinc.conf.5.in
$(substitute) $< > $@
$(substitute) $? > $@
tincinclude.texi: tincinclude.texi.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc.texi: tincinclude.texi

View file

@ -1,9 +1,9 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@ -38,7 +55,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@ -59,6 +77,11 @@ TEXI2PDF = $(TEXI2DVI) --pdf --batch
MAKEINFOHTML = $(MAKEINFO) --html
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
DVIPS = dvips
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man5dir)" \
"$(DESTDIR)$(man8dir)"
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@ -82,6 +105,12 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
man5dir = $(mandir)/man5
man8dir = $(mandir)/man8
NROFF = nroff
@ -140,6 +169,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -304,9 +334,7 @@ uninstall-html-am:
uninstall-info-am:
@$(PRE_UNINSTALL)
@if test -d '$(DESTDIR)$(infodir)' && \
(install-info --version && \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
@if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
@ -379,11 +407,18 @@ maintainer-clean-aminfo:
done
install-man5: $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
@list=''; test -n "$(man5dir)" || exit 0; \
{ for i in $$list; do echo "$$i"; done; \
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
sed -n '/\.5[a-z]*$$/p'; \
@list1=''; \
list2='$(man_MANS)'; \
test -n "$(man5dir)" \
&& test -n "`echo $$list1$$list2`" \
|| exit 0; \
echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
$(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
{ for i in $$list1; do echo "$$i"; done; \
if test -n "$$list2"; then \
for i in $$list2; do echo "$$i"; done \
| sed -n '/\.5[a-z]*$$/p'; \
fi; \
} | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \
@ -412,16 +447,21 @@ uninstall-man5:
sed -n '/\.5[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
test -z "$$files" || { \
echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
install-man8: $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
@list=''; test -n "$(man8dir)" || exit 0; \
{ for i in $$list; do echo "$$i"; done; \
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
sed -n '/\.8[a-z]*$$/p'; \
@list1=''; \
list2='$(man_MANS)'; \
test -n "$(man8dir)" \
&& test -n "`echo $$list1$$list2`" \
|| exit 0; \
echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
$(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
{ for i in $$list1; do echo "$$i"; done; \
if test -n "$$list2"; then \
for i in $$list2; do echo "$$i"; done \
| sed -n '/\.8[a-z]*$$/p'; \
fi; \
} | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \
@ -450,9 +490,7 @@ uninstall-man8:
sed -n '/\.8[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
test -z "$$files" || { \
echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(man8dir)" && rm -f $$files; }
dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
tags: TAGS
TAGS:
@ -523,10 +561,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
@ -565,8 +608,11 @@ install-dvi: install-dvi-am
install-dvi-am: $(DVIS)
@$(NORMAL_INSTALL)
test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)"
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
$(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@ -581,18 +627,22 @@ install-html: install-html-am
install-html-am: $(HTMLS)
@$(NORMAL_INSTALL)
test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)"
@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
$(am__strip_dir) \
if test -d "$$d$$p"; then \
d2=$$d$$p; \
if test -d "$$d2"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
else \
list2="$$list2 $$d$$p"; \
list2="$$list2 $$d2"; \
fi; \
done; \
test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
@ -604,9 +654,12 @@ install-info: install-info-am
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
$(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
fi; \
for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
@ -624,8 +677,7 @@ install-info-am: $(INFO_DEPS)
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
@$(POST_INSTALL)
@if (install-info --version && \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
@if $(am__can_run_installinfo); then \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
@ -639,8 +691,11 @@ install-pdf: install-pdf-am
install-pdf-am: $(PDFS)
@$(NORMAL_INSTALL)
test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)"
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@ -652,8 +707,11 @@ install-ps: install-ps-am
install-ps-am: $(PSS)
@$(NORMAL_INSTALL)
test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)"
@list='$(PSS)'; test -n "$(psdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@ -713,31 +771,31 @@ texi2html: tinc.texi
texi2html -split=chapter tinc.texi
tincd.8.html: tincd.8
w3mman2html $< > $@
w3mman2html $? > $@
tincctl.8.html: tincctl.8
w3mman2html $< > $@
w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8
w3mman2html $< > $@
w3mman2html $? > $@
tinc.conf.5.html: tinc.conf.5
w3mman2html $< > $@
w3mman2html $? > $@
tincd.8: tincd.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tincctl.8: tincctl.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc.conf.5: tinc.conf.5.in
$(substitute) $< > $@
$(substitute) $? > $@
tincinclude.texi: tincinclude.texi.in
$(substitute) $< > $@
$(substitute) $? > $@
tinc.texi: tincinclude.texi

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
.Dd 2010-01-16
.Dd 2012-09-27
.Dt TINC.CONF 5
.\" Manual page created by:
.\" Ivo Timmermans
@ -14,22 +14,12 @@ The files in the
directory contain runtime and security information for the tinc daemon.
.Sh NETWORKS
It is perfectly ok for you to run more than one tinc daemon.
However, in its default form,
you will soon notice that you can't use two different configuration files without the
.Fl c
option.
.Pp
We have thought of another way of dealing with this: network names.
This means that you call
.Nm
with the
To distinguish multiple instances of tinc running on one computer,
you can use the
.Fl n
option, which will assign a name to this daemon.
option to assign a network name to each tinc daemon.
.Pp
The effect of this is that the daemon will set its configuration root to
The effect of this option is that the daemon will set its configuration root to
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
where
.Ar NETNAME
@ -37,14 +27,14 @@ is your argument to the
.Fl n
option.
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
However, it is not strictly necessary that you call tinc with the
It is recommended that you use network names even if you run only one instance of tinc.
However, you can choose not to use the
.Fl n
option.
In this case, the network name would just be empty,
and it will be used as such.
In this case, the network name would just be empty, and
.Nm tinc
now looks for files in
.Pa @sysconfdir@/tinc/ ,
@ -55,12 +45,6 @@ the configuration file should be
and the host configuration files are now expected to be in
.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
Each tinc daemon should 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.
@ -72,25 +56,38 @@ file.
To make things easy,
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.
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 tincctl Fl n Ar NETNAME Li init Ar NAME
.Ed
.Pp
You can further change the configuration as needed either by manually editing the configuration files,
or by using
.Xr tincctl 8 .
.Sh PUBLIC/PRIVATE KEYS
You should use
.Ic tincd -K
to generate public/private keypairs.
It will generate two keys.
The private key should be stored in a separate file
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv
\-\- where
.Ar NETNAME
stands for the network (see
.Sx NETWORKS )
above.
The public key should be stored in the host configuration file
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME
\-\- where
.Va NAME
stands for the name of the local tinc daemon (see
.Sx NAMES ) .
The
.Nm tincctl Li init
command will have generated both RSA and ECDSA public/private keypairs.
The private keys should be stored in files named
.Pa rsa_key.priv
and
.Pa ecdsa_key.priv
in the directory
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /
The public keys should be stored in the host configuration file
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME .
The RSA keys are used for backwards compatibility with tinc version 1.0.
If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files,
but you will need to create ECDSA keys using the following command:
.Bd -literal -offset indent
.Nm tincctl Fl n Ar NETNAME Li generate-ecdsa-keys
.Ed
.Sh SERVER CONFIGURATION
The server configuration of the daemon is done in the file
@ -117,6 +114,11 @@ 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,
as this makes it easy to exchange with other nodes.
.Pp
You can edit the config file manually, but it is recommended that you use
.Xr tincctl 8
to change configuration variables for you.
.Pp
Here are all valid variables, listed in alphabetical order.
The default value is given between parentheses.
@ -129,14 +131,24 @@ If
is selected, then depending on the operating system both IPv4 and IPv6 or just
IPv6 listening sockets will be created.
.It Va BindToAddress Li = Ar address Bq experimental
.It Va BindToAddress Li = Ar address Op Ar port
If your computer has more than one IPv4 or IPv6 address,
.Nm tinc
will by default listen on all of them for incoming connections.
It is possible to bind only to a single address with this variable.
Multiple
.Va BindToAddress
variables may be specified,
in which case listening sockets for each specified address are made.
.Pp
This option may not work on all platforms.
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 .
.It Va BindToInterface Li = Ar interface Bq experimental
If your computer has more than one network interface,
@ -146,6 +158,28 @@ It is possible to bind only to a single interface with this variable.
.Pp
This option may not work on all platforms.
Also, on some platforms it will not actually bind to an interface,
but rather to the address that the interface has at the moment a socket is created.
.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
This option selects the way broadcast packets are sent to other daemons.
NOTE: all nodes in a VPN must use the same
.Va Broadcast
mode, otherwise routing loops can form.
.Bl -tag -width indent
.It no
Broadcast packets are never sent to other nodes.
.It mst
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
This ensures broadcast packets reach all nodes.
.It direct
Broadcast packets are sent directly to all nodes that can be reached directly.
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.
.El
.It Va ConnectTo Li = Ar name
Specifies which other tinc daemon to connect to on startup.
@ -165,6 +199,16 @@ If you don't specify a host with
won't try to connect to other daemons at all,
and will instead just listen for incoming connections.
.It Va DecrementTTL Li = yes | no Po no Pc Bq experimental
When enabled,
.Nm tinc
will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
before forwarding a received packet to the virtual network device or to another node,
and will drop packets that have a TTL value of zero,
in which case it will send an ICMP Time Exceeded packet back.
.Pp
Do not use this option if you use switch mode and want to use IPv6.
.It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
The virtual network device to use.
.Nm tinc
@ -177,30 +221,75 @@ instead of
The info pages of the tinc package contain more information
about configuring the virtual network device.
.It Va DeviceType Li = tun | tunnohead | tunifhead | tap Po only supported on BSD platforms Pc
.It Va DeviceType Li = Ar type Pq platform dependent
The type of the virtual network device.
Tinc will normally automatically select the right type, and this option should not be used.
However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
using this option might help.
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
However, this option can be used to select one of the special interface types, if support for them is compiled in.
.Bl -tag -width indent
.It tun
.It dummy
Use a dummy interface.
No packets are ever read or written to a virtual network device.
Useful for testing, or when setting up a node that only forwards packets for other nodes.
.It raw_socket
Open a raw socket, and bind it to a pre-existing
.Va Interface
(eth0 by default).
All packets are read from this interface.
Packets received for the local node are written to the raw socket.
However, at least on Linux, the operating system does not process IP packets destined for the local host.
.It multicast
Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using
.Va Device .
Packets are read from and written to this multicast socket.
This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address.
Do NOT connect multiple
.Nm tinc
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.
.It uml Pq not compiled in by default
Create a UNIX socket with the filename specified by
.Va Device ,
or
.Pa @localstatedir@/run/ Ns Ar NETNAME Ns Pa .umlsocket
if not specified.
.Nm tinc
will wait for a User Mode Linux instance to connect to this socket.
.It vde Pq not compiled in by default
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
using the UNIX socket specified by
.Va Device ,
or
.Pa @localstatedir@/run/vde.ctl
if not specified.
.El
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
it can be used to change the way packets are interpreted:
.Bl -tag -width indent
.It tun Pq BSD and Linux
Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below).
.It tunnohead
.It tunnohead Pq BSD
Set type to tun without an address family header.
Tinc will expect packets read from the virtual network device to start with an IP header.
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
.It tunifhead
.It tunifhead Pq BSD
Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
.It tap
.It tap Pq BSD and Linux
Set type to tap.
Tinc will expect packets read from the virtual network device
to start with an Ethernet header.
@ -247,7 +336,7 @@ This is less efficient, but allows the kernel to apply its routing and firewall
and can also help debugging.
.El
.It Va GraphDumpFile Li = Ar filename Bq experimental
.It Va GraphDumpFile Li = Ar filename
If this option is present,
.Nm tinc
will dump the current network graph to the file
@ -268,7 +357,7 @@ a lookup if your DNS server is not responding.
.Pp
This does not affect resolving hostnames to IP addresses from the
host configuration files.
host configuration files, but whether hostnames should be resolved while logging.
.It Va IffOneQueue Li = yes | no Po no Pc Bq experimental
(Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices.
@ -286,6 +375,18 @@ This option controls the period the encryption keys used to encrypt the data are
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.
.It Va LocalDiscovery Li = yes | no Pq no
When enabled,
.Nm tinc
will try to detect peers that are on the same local network.
This will allow direct communication using LAN addresses, even if both peers are behind a NAT
and they only ConnectTo a third node outside the NAT,
which normally would prevent the peers from learning each other's LAN address.
.Pp
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
This feature may not work in all possible situations.
.It Va MACExpire Li = Ar seconds Pq 600
This option controls the amount of time MAC addresses are kept before they are removed.
This only has effect when
@ -327,6 +428,19 @@ while no routing table is managed.
.It Va Name Li = Ar name Bq required
This is the name which identifies this tinc daemon.
It must be unique for the virtual private network this daemon will connect to.
The Name may only consist of alphanumeric and underscore characters.
If
.Va Name
starts with a
.Li $ ,
then the contents of the environment variable that follows will be used.
In that case, invalid characters will be converted to underscores.
If
.Va Name
is
.Li $HOST ,
but no such environment variable exist, the hostname will be read using the gethostnname() system call.
.It Va PingInterval Li = Ar seconds Pq 60
The number of seconds of inactivity that
@ -356,11 +470,46 @@ or
specified in the configuration file.
.It Va ProcessPriority Li = low | normal | high
When this option is used the priority of the tincd process will be adjusted.
When this option is used the priority of the
.Nm tincd
process will be adjusted.
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
Use a proxy when making outgoing connections.
The following proxy types are currently supported:
.Bl -tag -width indent
.It socks4 Ar address Ar port Op Ar username
Connects to the proxy using the SOCKS version 4 protocol.
Optionally, a
.Ar username
can be supplied which will be passed on to the proxy server.
Only IPv4 connections can be proxied using SOCKS 4.
.It socks5 Ar address Ar port Op Ar username Ar password
Connect to the proxy using the SOCKS version 5 protocol.
If a
.Ar username
and
.Ar password
are given, basic username/password authentication will be used,
otherwise no authentication will be used.
.It http Ar address Ar port
Connects to the proxy and sends a HTTP CONNECT request.
.It exec Ar command
Executes the given
.Ar command
which should set up the outgoing connection.
The environment variables
.Ev NAME ,
.Ev NODE ,
.Ev REMOTEADDRES
and
.Ev REMOTEPORT
are available.
.El
.It Va ReplayWindow Li = Ar bytes Pq 16
This is the size of the replay tracking window for each remote node, in bytes.
vhis 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 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
@ -406,7 +555,7 @@ Since host configuration files only contain public keys,
no secrets are revealed by sending out this information.
.Bl -tag -width indent
.It Va Address Li = Ar address Oo port Oc Bq recommended
.It Va Address Li = Ar address Oo Ar port Oc Bq recommended
The IP address or hostname of this tinc daemon on the real network.
This will only be used when trying to make an outgoing connection to this tinc daemon.
Optionally, a port can be specified to use for this address.
@ -497,12 +646,11 @@ variables can be specified.
Subnets can either be single MAC, IPv4 or IPv6 addresses,
in which case a subnet consisting of only that single address is assumed,
or they can be a IPv4 or IPv6 network address with a prefixlength.
Shorthand notations are not supported.
For example, IPv4 subnets must be in a form like 192.168.1.0/24,
where 192.168.1.0 is the network address and 24 is the number of bits set in the netmask.
Note that subnets like 192.168.1.1/24 are invalid!
Read a networking HOWTO/FAQ/guide if you don't understand this.
IPv6 subnets are notated like fec0:0:0:1:0:0:0:0/64.
IPv6 subnets are notated like fec0:0:0:1::/64.
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
.Pp
@ -609,6 +757,10 @@ When a subnet becomes (un)reachable, this is set to the subnet.
When a subnet becomes (un)reachable, this is set to the subnet weight.
.El
.Pp
Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command
.Nm chmod Li a+x Pa script .
.Sh FILES
The most important files are:
.Bl -tag -width indent
@ -636,8 +788,9 @@ its connection to the virtual network device.
.Sh SEE ALSO
.Xr tincd 8 ,
.Xr tincctl 8 ,
.Pa http://www.tinc-vpn.org/ ,
.Pa http://www.linuxdoc.org/LDP/nag2/ .
.Pa http://www.tldp.org/LDP/nag2/ .
.Pp
The full documentation for

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
Copyright @copyright{} 1998-2011 Ivo Timmermans,
Copyright @copyright{} 1998-2012 Ivo Timmermans,
Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>.
@ -39,7 +39,7 @@ permission notice identical to this one.
@vskip 0pt plus 1filll
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
Copyright @copyright{} 1998-2011 Ivo Timmermans,
Copyright @copyright{} 1998-2012 Ivo Timmermans,
Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>.
@ -187,7 +187,7 @@ packets.
@cindex release
For an up to date list of supported platforms, please check the list on
our website:
@uref{http://www.tinc-vpn.org/platforms}.
@uref{http://www.tinc-vpn.org/platforms/}.
@c
@c
@ -262,7 +262,7 @@ alias char-major-10-200 tun
@subsection Configuration of FreeBSD kernels
For FreeBSD version 4.1 and higher, tun and tap drivers are included in the default kernel configuration.
Using tap devices is recommended.
The tap driver can be loaded with @code{kldload if_tap}, or by adding @code{if_tap_load="YES"} to @file{/boot/loader.conf}.
@c ==================================================================
@ -276,6 +276,7 @@ which adds a tap device to OpenBSD which should work with tinc,
but with recent versions of OpenBSD,
a tun device can act as a tap device by setting the link0 option with ifconfig.
@c ==================================================================
@node Configuration of NetBSD kernels
@subsection Configuration of NetBSD kernels
@ -466,7 +467,7 @@ available. Make sure you install the development AND runtime versions
of this package.
If you have to install libevent manually, you can get the source code
from @url{http://monkey.org/~provos/libevent/}. Instructions on how to configure,
from @url{http://libevent.org/}. Instructions on how to configure,
build and install this package are included within the package. Please
make sure you build development and runtime libraries (which is the
default).
@ -492,7 +493,7 @@ system startup scripts and sample configurations.
If you cannot use one of the precompiled packages, or you want to compile tinc
for yourself, you can use the source. The source is distributed under
the GNU General Public License (GPL). Download the source from the
@uref{http://www.tinc-vpn.org/download, download page}, which has
@uref{http://www.tinc-vpn.org/download/, download page}, which has
the checksums of these files listed; you may wish to check these with
md5sum before continuing.
@ -533,7 +534,7 @@ The documentation that comes along with your distribution will tell you how to d
In order to build tinc on Darwin, you need to install the MacOS/X Developer Tools
from @uref{http://developer.apple.com/tools/macosxtools.html} and
a recent version of Fink from @uref{http://fink.sourceforge.net/}.
a recent version of Fink from @uref{http://www.finkproject.org/}.
After installation use fink to download and install the following packages:
autoconf25, automake, dlcompat, m4, openssl, zlib and lzo.
@ -638,7 +639,6 @@ tinc 655/udp TINC
* Multiple networks::
* How connections work::
* Configuration files::
* Generating keypairs::
* Network interfaces::
* Example configuration::
@end menu
@ -661,13 +661,19 @@ you will not find the answers in this documentation.
Make sure you have an adequate understanding of networks in general.
@cindex Network Administrators Guide
A good resource on networking is the
@uref{http://www.linuxdoc.org/LDP/nag2/, Linux Network Administrators Guide}.
@uref{http://www.tldp.org/LDP/nag2/, Linux Network Administrators Guide}.
If you have everything clearly pictured in your mind,
proceed in the following order:
First, generate the configuration files (@file{tinc.conf}, your host configuration file, @file{tinc-up} and perhaps @file{tinc-down}).
Then generate the keypairs.
Finally, distribute the host configuration files.
First, create the initial configuration files and public/private keypairs using the following command:
@example
tincctl -n @var{NETNAME} init @var{NAME}
@end example
Second, use @samp{tincctl -n @var{NETNAME} config ...} to further configure tinc.
Finally, export your host configuration file using @samp{tincctl -n @var{NETNAME} export} and send it to those
people or computers you want tinc to connect to.
They should send you their host configuration file back, which you can import using @samp{tincctl -n @var{NETNAME} import}.
These steps are described in the subsections below.
@ -677,30 +683,29 @@ These steps are described in the subsections below.
@cindex multiple networks
@cindex netname
In order to allow you to run more than one tinc daemon on one computer,
for instance if your computer is part of more than one VPN,
you can assign a @var{netname} to your VPN.
It is not required if you only run one tinc daemon,
it doesn't even have to be the same on all the sites of your VPN,
it doesn't even have to be the same on all the nodes of your VPN,
but it is recommended that you choose one anyway.
We will asume you use a netname throughout this document.
This means that you call tincd with the -n argument,
which will assign a netname to this daemon.
This means that you call tincctl with the -n argument,
which will specify the netname.
The effect of this is that the daemon will set its configuration
root to @file{@value{sysconfdir}/tinc/@var{netname}/}, where @var{netname} is your argument to the -n
option. You'll notice that it appears in syslog as @file{tinc.@var{netname}}.
The effect of this option is that tinc will set its configuration
root to @file{@value{sysconfdir}/tinc/@var{netname}/}, where @var{netname} is your argument to the -n option.
You will also notice that log messages it appears in syslog as coming from @file{tinc.@var{netname}},
and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name.
However, it is not strictly necessary that you call tinc with the -n
option. In this case, the network name would just be empty, and it will
be used as such. tinc now looks for files in @file{@value{sysconfdir}/tinc/}, instead of
@file{@value{sysconfdir}/tinc/@var{netname}/}; the configuration file should be @file{@value{sysconfdir}/tinc/tinc.conf},
and the host configuration files are now expected to be in @file{@value{sysconfdir}/tinc/hosts/}.
But it is highly recommended that you use this feature of tinc, because
it will be so much clearer whom your daemon talks to. Hence, we will
assume that you use it.
option. If you don not use it, the network name will just be empty, and
tinc will look for files in @file{@value{sysconfdir}/tinc/} instead of
@file{@value{sysconfdir}/tinc/@var{netname}/};
the configuration file will then be @file{@value{sysconfdir}/tinc/tinc.conf},
and the host configuration files are expected to be in @file{@value{sysconfdir}/tinc/hosts/}.
@c ==================================================================
@ -727,6 +732,25 @@ If you wish, you can view a tinc daemon without a `ConnectTo' value as a server,
and one which does specify such a value as a client.
It does not matter if two tinc daemons have a `ConnectTo' value pointing to each other however.
Connections specified using `ConnectTo' are so-called meta-connections.
Tinc daemons exchange information about all other daemon they know about via these meta-connections.
After learning about all the daemons in the VPN,
tinc will create other connections as necessary in order to communicate with them.
For example, if there are three daemons named A, B and C, and A has @samp{ConnectTo = B} in its tinc.conf file,
and C has @samp{ConnectTo = B} in its tinc.conf file, then A will learn about C from B,
and will be able to exchange VPN packets with C without the need to have @samp{ConnectTo = C} in its tinc.conf file.
It could be that some daemons are located behind a Network Address Translation (NAT) device, or behind a firewall.
In the above scenario with three daemons, if A and C are behind a NAT,
B will automatically help A and C punch holes through their NAT,
in a way similar to the STUN protocol, so that A and C can still communicate with each other directly.
It is not always possible to do this however, and firewalls might also prevent direct communication.
In that case, VPN packets between A and C will be forwarded by B.
In effect, all nodes in the VPN will be able to talk to each other, as long as
their is a path of meta-connections between them, and whenever possible, two
nodes will communicate with each other directly.
@c ==================================================================
@node Configuration files
@ -755,7 +779,10 @@ listed in this document can also be put in
put host specific configuration options in the host configuration file, as this
makes it easy to exchange with other nodes.
In this section all valid variables are listed in alphabetical order.
You can edit the config file manually, but it is recommended that you use
tincctl to change configuration variables for you.
In the following two subsections all valid variables are listed in alphabetical order.
The default value is given between parentheses,
other comments are between square brackets.
@ -779,12 +806,15 @@ If any is selected, then depending on the operating system
both IPv4 and IPv6 or just IPv6 listening sockets will be created.
@cindex BindToAddress
@item BindToAddress = <@var{address}> [experimental]
@item BindToAddress = <@var{address}> [<@var{port}>]
If your computer has more than one IPv4 or IPv6 address, tinc
will by default listen on all of them for incoming connections.
It is possible to bind only to a single address with this variable.
Multiple BindToAddress variables may be specified,
in which case listening sockets for each specified address are made.
This option may not work on all platforms.
If no @var{port} is specified, the socket will be bound to the port specified by the Port option,
or to port 655 if neither is given.
To only bind to a specific port but not to a specific address, use "*" for the @var{address}.
@cindex BindToInterface
@item BindToInterface = <@var{interface}> [experimental]
@ -794,6 +824,27 @@ possible to bind tinc to a single interface like eth0 or ppp0 with this
variable.
This option may not work on all platforms.
Also, on some platforms it will not actually bind to an interface,
but rather to the address that the interface has at the moment a socket is created.
@cindex Broadcast
@item Broadcast = <no | mst | direct> (mst) [experimental]
This option selects the way broadcast packets are sent to other daemons.
@emph{NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form.}
@table @asis
@item no
Broadcast packets are never sent to other nodes.
@item mst
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
This ensures broadcast packets reach all nodes.
@item direct
Broadcast packets are sent directly to all nodes that can be reached directly.
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.
@end table
@cindex ConnectTo
@item ConnectTo = <@var{name}>
@ -807,6 +858,15 @@ If you don't specify a host with ConnectTo,
tinc won't try to connect to other daemons at all,
and will instead just listen for incoming connections.
@cindex DecrementTTL
@item DecrementTTL = <yes | no> (no) [experimental]
When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
before forwarding a received packet to the virtual network device or to another node,
and will drop packets that have a TTL value of zero,
in which case it will send an ICMP Time Exceeded packet back.
Do not use this option if you use switch mode and want to use IPv6.
@cindex Device
@item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
The virtual network device to use.
@ -817,32 +877,72 @@ Note that you can only use one device per daemon.
See also @ref{Device files}.
@cindex DeviceType
@item DeviceType = <tun|tunnohead|tunifhead|tap> (only supported on BSD platforms)
@item DeviceType = <@var{type}> (platform dependent)
The type of the virtual network device.
Tinc will normally automatically select the right type, and this option should not be used.
However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
using this option might help.
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
However, this option can be used to select one of the special interface types, if support for them is compiled in.
@table @asis
@item tun
@cindex dummy
@item dummy
Use a dummy interface.
No packets are ever read or written to a virtual network device.
Useful for testing, or when setting up a node that only forwards packets for other nodes.
@cindex raw_socket
@item raw_socket
Open a raw socket, and bind it to a pre-existing
@var{Interface} (eth0 by default).
All packets are read from this interface.
Packets received for the local node are written to the raw socket.
However, at least on Linux, the operating system does not process IP packets destined for the local host.
@cindex multicast
@item multicast
Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using @var{Device}.
Packets are read from and written to this multicast socket.
This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address.
Do NOT connect multiple tinc 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.
@cindex UML
@item uml (not compiled in by default)
Create a UNIX socket with the filename specified by
@var{Device}, or @file{@value{localstatedir}/run/@var{netname}.umlsocket}
if not specified.
Tinc will wait for a User Mode Linux instance to connect to this socket.
@cindex VDE
@item vde (not compiled in by default)
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
using the UNIX socket specified by
@var{Device}, or @file{@value{localstatedir}/run/vde.ctl}
if not specified.
@end table
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
it can be used to change the way packets are interpreted:
@table @asis
@item tun (BSD and Linux)
Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below).
@cindex tunnohead
@item tunnohead
@item tunnohead (BSD)
Set type to tun without an address family header.
Tinc will expect packets read from the virtual network device to start with an IP header.
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
@cindex tunifhead
@item tunifhead
@item tunifhead (BSD)
Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family,
followed by an IP header.
This mode should support both IPv4 and IPv6 packets.
@item tap
@item tap (BSD and Linux)
Set type to tap.
Tinc will expect packets read from the virtual network device
to start with an Ethernet header.
@ -891,7 +991,7 @@ and can also help debugging.
@end table
@cindex GraphDumpFile
@item GraphDumpFile = <@var{filename}> [experimental]
@item GraphDumpFile = <@var{filename}>
If this option is present,
tinc will dump the current network graph to the file @var{filename}
every minute, unless there were no changes to the graph.
@ -908,7 +1008,7 @@ tinc's efficiency, even stopping the daemon for a few seconds everytime
it does a lookup if your DNS server is not responding.
This does not affect resolving hostnames to IP addresses from the
configuration file.
configuration file, but whether hostnames should be resolved while logging.
@cindex Interface
@item Interface = <@var{interface}>
@ -917,6 +1017,16 @@ Depending on the operating system and the type of device this may or may not act
Under Windows, this variable is used to select which network interface will be used.
If you specified a Device, this variable is almost always already correctly set.
@cindex LocalDiscovery
@item LocalDiscovery = <yes | no> (no)
When enabled, tinc will try to detect peers that are on the same local network.
This will allow direct communication using LAN addresses, even if both peers are behind a NAT
and they only ConnectTo a third node outside the NAT,
which normally would prevent the peers from learning each other's LAN address.
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
This feature may not work in all possible situations.
@cindex Mode
@item Mode = <router|switch|hub> (router)
This option selects the way packets are routed to other daemons.
@ -963,6 +1073,11 @@ This only has effect when Mode is set to "switch".
This is a symbolic name for this connection.
The name should consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _).
If Name starts with a $, then the contents of the environment variable that follows will be used.
In that case, invalid characters will be converted to underscores.
If Name is $HOST, but no such environment variable exist,
the hostname will be read using the gethostnname() system call.
@cindex PingInterval
@item PingInterval = <@var{seconds}> (60)
The number of seconds of inactivity that tinc will wait before sending a
@ -1000,6 +1115,33 @@ specified in the configuration file.
When this option is used the priority of the tincd process will be adjusted.
Increasing the priority may help to reduce latency and packet loss on the VPN.
@cindex Proxy
@item Proxy = socks4 | socks4 | http | exec @var{...} [experimental]
Use a proxy when making outgoing connections.
The following proxy types are currently supported:
@table @asis
@cindex socks4
@item socks4 <@var{address}> <@var{port}> [<@var{username}>]
Connects to the proxy using the SOCKS version 4 protocol.
Optionally, a @var{username} can be supplied which will be passed on to the proxy server.
@cindex socks5
@item socks4 <@var{address}> <@var{port}> [<@var{username}> <@var{password}>]
Connect to the proxy using the SOCKS version 5 protocol.
If a @var{username} and @var{password} are given, basic username/password authentication will be used,
otherwise no authentication will be used.
@cindex http
@item http <@var{address}> <@var{port}>
Connects to the proxy and sends a HTTP CONNECT request.
@cindex exec
@item exec <@var{command}>
Executes the given command which should set up the outgoing connection.
The environment variables @env{NAME}, @env{NODE}, @env{REMOTEADDRES} and @env{REMOTEPORT} are available.
@end table
@cindex ReplayWindow
@item ReplayWindow = <bytes> (16)
This is the size of the replay tracking window for each remote node, in bytes.
@ -1132,19 +1274,18 @@ Multiple subnet lines can be specified for each daemon.
Subnets can either be single MAC, IPv4 or IPv6 addresses,
in which case a subnet consisting of only that single address is assumed,
or they can be a IPv4 or IPv6 network address with a prefixlength.
Shorthand notations are not supported.
For example, IPv4 subnets must be in a form like 192.168.1.0/24,
where 192.168.1.0 is the network address and 24 is the number of bits set in the netmask.
Note that subnets like 192.168.1.1/24 are invalid!
Read a networking HOWTO/FAQ/guide if you don't understand this.
IPv6 subnets are notated like fec0:0:0:1:0:0:0:0/64.
IPv6 subnets are notated like fec0:0:0:1::/64.
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
@cindex CIDR notation
Prefixlength is the number of bits set to 1 in the netmask part; for
example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes
/22. This conforms to standard CIDR notation as described in
@uref{ftp://ftp.isi.edu/in-notes/rfc1519.txt, RFC1519}
@uref{http://www.ietf.org/rfc/rfc1519.txt, RFC1519}
A Subnet can be given a weight to indicate its priority over identical Subnets
owned by different nodes. The default weight is 10. Lower values indicate
@ -1254,50 +1395,115 @@ When a subnet becomes (un)reachable, this is set to the subnet.
@node How to configure
@subsection How to configure
@subsubheading Step 1. Creating the main configuration file
@subsubheading Step 1. Creating initial configuration files.
The main configuration file will be called @file{@value{sysconfdir}/tinc/@var{netname}/tinc.conf}.
Adapt the following example to create a basic configuration file:
The initial directory structure, configuration files and public/private keypairs are created using the following command:
@example
Name = @var{yourname}
Device = @file{/dev/tap0}
tincctl -n @var{netname} init @var{name}
@end example
Then, if you know to which other tinc daemon(s) yours is going to connect,
add `ConnectTo' values.
@subsubheading Step 2. Creating your host configuration file
If you added a line containing `Name = yourname' in the main configuarion file,
you will need to create a host configuration file @file{@value{sysconfdir}/tinc/@var{netname}/hosts/yourname}.
Adapt the following example to create a host configuration file:
(You will need to run this as root, or use "sudo".)
This will create the configuration directory @file{@value{sysconfdir}/tinc/@var{netname}.},
and inside it will create another directory named @file{hosts/}.
In the configuration directory, it will create the file @file{tinc.conf} with the following contents:
@example
Address = your.real.hostname.org
Subnet = 192.168.1.0/24
Name = @var{name}
@end example
You can also use an IP address instead of a hostname.
The `Subnet' specifies the address range that is local for @emph{your part of the VPN only}.
If you have multiple address ranges you can specify more than one `Subnet'.
You might also need to add a `Port' if you want your tinc daemon to run on a different port number than the default (655).
It will also create private RSA and ECDSA keys, which will be stored in the files @file{rsa_key.priv} and @file{ecdsa_key.priv}.
It will also create a host configuration file @file{hosts/@var{name}},
which will contain the corresponding public RSA and ECDSA keys.
Finally, on UNIX operating systems, it will create an executable script @file{tinc-up},
which will initially not do anything except warning that you should edit it.
@c ==================================================================
@node Generating keypairs
@section Generating keypairs
@subsubheading Step 2. Modifying the initial configuration.
@cindex key generation
Now that you have already created the main configuration file and your host configuration file,
you can easily create a public/private keypair by entering the following command:
Unless you want to use tinc in switch mode,
you should now configure which range of addresses you will use on the VPN.
Let's assume you will be part of a VPN which uses the address range 192.168.0.0/16,
and you yourself have a smaller portion of that range: 192.168.2.0/24.
Then you should run the following command:
@example
tincctl -n @var{netname} generate-keys
tincctl -n @var{netname} config add subnet 192.168.2.0/24
@end example
Tinc will generate a public and a private key and ask you where to put them.
Just press enter to accept the defaults.
This will add a Subnet statement to your host configuration file.
Try opening the file @file{@value{sysconfdir}/tinc/@var{netname}/hosts/@var{name}} in an editor.
You should now see a file containing the public RSA and ECDSA keys (which looks like a bunch of random characters),
and the following line at the bottom:
@example
Subnet = 192.168.2.0/24
@end example
If you will use more than one address range, you can add more Subnets.
For example, if you also use the IPv6 subnet fec0:0:0:2::/64, you can add it as well:
@example
tincctl -n @var{netname} config add subnet fec0:0:0:2::/24
@end example
This will add another line to the file @file{hosts/@var{name}}.
If you make a mistake, you can undo it by simply using @samp{config del} instead of @samp{config add}.
If you want other tinc daemons to create meta-connections to your daemon,
you should add your public IP address or hostname to your host configuration file.
For example, if your hostname is foo.example.org, run:
@example
tincctl -n @var{netname} config add address foo.example.org
@end example
If you already know to which daemons your daemon should make meta-connections,
you should configure that now as well.
Suppose you want to connect to a daemon named "bar", run:
@example
tincctl -n @var{netname} config add connectto bar
@end example
Note that you specify the Name of the other daemon here, not an IP address or hostname!
When you start tinc, and it tries to make a connection to "bar",
it will look for a host configuration file named @file{hosts/bar},
and will read Address statements and public keys from that file.
@subsubheading Step 2. Exchanging configuration files.
If your daemon has a ConnectTo = bar statement in its @file{tinc.conf} file,
or if bar has a ConnectTo your daemon, then you both need each other's host configuration files.
You should send @file{hosts/@var{name}} to bar, and bar should send you his file which you should move to @file{hosts/bar}.
If you are on a UNIX platform, you can easily send an email containing the necessary information using the following command
(assuming the owner of bar has the email address bar@@example.org):
@example
tincctl -n @var{netname} export | mail -s "My config file" bar@@example.org
@end example
If the owner of bar does the same to send his host configuration file to you,
you can probably pipe his email through the following command,
or you can just start this command in a terminal and copy&paste the email:
@example
tincctl -n @var{netname} import
@end example
If you are the owner of bar yourself, and you have SSH access to that computer,
you can also swap the host configuration files using the following commands:
@example
tincctl -n @var{netname} export | ssh bar.example.org tincctl -n @var{netname} import
ssh bar.example.org tincctl -n @var{netname} export | tincctl -n @var{netname} import
@end example
You should repeat this for all nodes you ConnectTo, or which ConnectTo you.
However, remember that you do not need to ConnectTo all nodes in the VPN;
it is only necessary to create one or a few meta-connections,
after the connections are made tinc will learn about all the other nodes in the VPN,
and will automatically make other connections as necessary.
@c ==================================================================
@ -1320,21 +1526,31 @@ You can configure the network interface by putting ordinary ifconfig, route, and
to a script named @file{@value{sysconfdir}/tinc/@var{netname}/tinc-up}.
When tinc starts, this script will be executed. When tinc exits, it will execute the script named
@file{@value{sysconfdir}/tinc/@var{netname}/tinc-down}, but normally you don't need to create that script.
You can manually open the script in an editor, or use the following command:
An example @file{tinc-up} script:
@example
tincctl -n @var{netname} edit tinc-up
@end example
An example @file{tinc-up} script, that would be appropriate for the scenario in the previous section, is:
@example
#!/bin/sh
ifconfig $INTERFACE 192.168.1.1 netmask 255.255.0.0
ifconfig $INTERFACE 192.168.2.1 netmask 255.255.0.0
ip addr add fec0:0:0:2::/48 dev $INTERFACE
@end example
This script gives the interface an IP address and a netmask.
The kernel will also automatically add a route to this interface, so normally you don't need
The first command gives the interface an IPv4 address and a netmask.
The kernel will also automatically add an IPv4 route to this interface, so normally you don't need
to add route commands to the @file{tinc-up} script.
The kernel will also bring the interface up after this command.
@cindex netmask
The netmask is the mask of the @emph{entire} VPN network, not just your
own subnet.
The second command gives the interface an IPv6 address and netmask,
which will also automatically add an IPv6 route.
If you only want to use "ip addr" commands on Linux, don't forget that it doesn't bring the interface up, unlike ifconfig,
so you need to add @samp{ip link set $INTERFACE up} in that case.
The exact syntax of the ifconfig and route commands differs from platform to platform.
You can look up the commands for setting addresses and adding routes in @ref{Platform specific information},
@ -1374,6 +1590,9 @@ the real interface is also shown as a comment, to give you an idea of
how these example host is set up. All branches use the netname `company'
for this particular VPN.
Each branch is set up using the @samp{tincctl init} and @samp{tincctl config} commands,
here we just show the end results:
@subsubheading For Branch A
@emph{BranchA} would be configured like this:
@ -1381,6 +1600,8 @@ for this particular VPN.
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example
#!/bin/sh
# Real interface of internal network:
# ifconfig eth0 10.1.54.1 netmask 255.255.0.0
@ -1391,7 +1612,6 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
@example
Name = BranchA
Device = /dev/tap0
@end example
On all hosts, @file{@value{sysconfdir}/tinc/company/hosts/BranchA} contains:
@ -1405,9 +1625,9 @@ Address = 1.2.3.4
-----END RSA PUBLIC KEY-----
@end example
Note that the IP addresses of eth0 and tap0 are the same.
Note that the IP addresses of eth0 and the VPN interface are the same.
This is quite possible, if you make sure that the netmasks of the interfaces are different.
It is in fact recommended to give both real internal network interfaces and tap interfaces the same IP address,
It is in fact recommended to give both real internal network interfaces and VPN interfaces the same IP address,
since that will make things a lot easier to remember and set up.
@ -1416,6 +1636,8 @@ since that will make things a lot easier to remember and set up.
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example
#!/bin/sh
# Real interface of internal network:
# ifconfig eth0 10.2.43.8 netmask 255.255.0.0
@ -1430,7 +1652,7 @@ ConnectTo = BranchA
@end example
Note here that the internal address (on eth0) doesn't have to be the
same as on the tap0 device. Also, ConnectTo is given so that this node will
same as on the VPN interface. Also, ConnectTo is given so that this node will
always try to connect to BranchA.
On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchB}:
@ -1450,6 +1672,8 @@ Address = 2.3.4.5
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example
#!/bin/sh
# Real interface of internal network:
# ifconfig eth0 10.3.69.254 netmask 255.255.0.0
@ -1461,7 +1685,6 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
@example
Name = BranchC
ConnectTo = BranchA
Device = /dev/tap1
@end example
C already has another daemon that runs on port 655, so they have to
@ -1486,6 +1709,8 @@ Port = 2000
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example
#!/bin/sh
# Real interface of internal network:
# ifconfig eth0 10.4.3.32 netmask 255.255.0.0
@ -1497,14 +1722,10 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
@example
Name = BranchD
ConnectTo = BranchC
Device = /dev/net/tun
@end example
D will be connecting to C, which has a tincd running for this network on
port 2000. It knows the port number from the host configuration file.
Also note that since D uses the tun/tap driver, the network interface
will not be called `tun' or `tap0' or something like that, but will
have the same name as netname.
On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchD}:
@ -1519,16 +1740,11 @@ Address = 4.5.6.7
@subsubheading Key files
A, B, C and D all have generated a public/private keypair with the following command:
A, B, C and D all have their own public/private keypairs:
@example
tincctl -n company generate-keys
@end example
The private key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
the public key is put into the host configuration file in the @file{@value{sysconfdir}/tinc/company/hosts/} directory.
During key generation, tinc automatically guesses the right filenames based on the -n option and
the Name directive in the @file{tinc.conf} file (if it is available).
The private RSA key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
the private ECDSA key is stored in @file{@value{sysconfdir}/tinc/company/ecdsa_key.priv},
and the public RSA and ECDSA keys are put into the host configuration file in the @file{@value{sysconfdir}/tinc/company/hosts/} directory.
@subsubheading Starting
@ -1545,7 +1761,7 @@ their daemons, tinc will try connecting until they are available.
If everything else is done, you can start tinc by typing the following command:
@example
tincd -n @var{netname}
tincctl -n @var{netname} start
@end example
@cindex daemon
@ -1600,6 +1816,12 @@ Store a cookie in @var{filename} which allows tincctl to authenticate.
If unspecified, the default is
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
@item -o, --option=[@var{HOST}.]@var{KEY}=@var{VALUE}
Without specifying a @var{HOST}, this will set server configuration variable @var{KEY} to @var{VALUE}.
If specified as @var{HOST}.@var{KEY}=@var{VALUE},
this will set the host configuration variable @var{KEY} of the host named @var{HOST} to @var{VALUE}.
This option can be used more than once to specify multiple configuration variables.
@item -L, --mlock
Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
@ -1868,6 +2090,7 @@ tincctl -n @var{netname} reload
@menu
* tincctl runtime options::
* tincctl environment variables::
* tincctl commands::
* tincctl examples::
* tincctl top::
@ -1900,6 +2123,16 @@ Output version information and exit.
@end table
@c ==================================================================
@node tincctl environment variables
@section tincctl environment variables
@table @env
@cindex NETNAME
@item NETNAME
If no netname is specified on the command line with the @option{-n} option,
the value of this environment variable is used.
@end table
@c ==================================================================
@node tincctl commands
@ -1908,8 +2141,43 @@ Output version information and exit.
@c from the manpage
@table @code
@item start
Start @samp{tincd}.
@item init [@var{name}]
Create initial configuration files and RSA and ECDSA keypairs with default length.
If no @var{name} for this node is given, it will be asked for.
@item config [get] @var{variable}
Print the current value of configuration variable @var{variable}.
If more than one variable with the same name exists,
the value of each of them will be printed on a separate line.
@item config [set] @var{variable} @var{value}
Set configuration variable @var{variable} to the given @var{value}.
All previously existing configuration variables with the same name are removed.
To set a variable for a specific host, use the notation @var{host}.@var{variable}.
@item config add @var{variable} @var{value}
As above, but without removing any previously existing configuration variables.
@item config del @var{variable} [@var{value}]
Remove configuration variables with the same name and @var{value}.
If no @var{value} is given, all configuration variables with the same name will be removed.
@item edit @var{filename}
Start an editor for the given configuration file.
You do not need to specify the full path to the file.
@item export
Export the host configuration file of the local node to standard output.
@item export-all
Export all host configuration files to standard output.
@item import [--force]
Import host configuration file(s) from standard input.
Already existing host configuration files are not overwritten unless the option --force is used.
@item start [tincd options]
Start @samp{tincd}, optionally with the given extra options.
@item stop
Stop @samp{tincd}.
@ -1943,8 +2211,15 @@ Dump a list of all known subnets in the VPN.
@item dump connections
Dump a list of all meta connections with ourself.
@item dump graph
@item dump graph | digraph
Dump a graph of the VPN in dotty 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.
@item info @var{node} | @var{subnet} | @var{address}
Show information about a particular @var{node}, @var{subnet} or @var{address}.
If an @var{address} is given, any matching subnet will be shown.
@item purge
Purges all information remembered about unreachable nodes.
@ -1952,6 +2227,10 @@ Purges all information remembered about unreachable nodes.
@item debug @var{level}
Sets debug level to @var{level}.
@item log [@var{level}]
Capture log messages from a running tinc daemon.
An optional debug level can be given that will be applied only for log messages sent to tincctl.
@item retry
Forces tinc to try to connect to all uplinks immediately.
Usually tinc attempts to do this itself,
@ -1986,6 +2265,16 @@ tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top
@end example
Example of configuring tinc using tincctl:
@example
tincctl -n vpn init foo
tincctl -n vpn config Subnet 192.168.1.0/24
tincctl -n vpn config bar.Address bar.example.com
tincctl -n vpn config ConnectTo bar
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
@end example
@c ==================================================================
@node tincctl top
@section tincctl top
@ -2531,7 +2820,6 @@ For IPv4 addresses:
@tab @code{netsh interface ip set address} @var{interface} @code{static} @var{address} @var{netmask}
@end multitable
For IPv6 addresses:
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
@ -2553,6 +2841,22 @@ For IPv6 addresses:
@tab @code{netsh interface ipv6 add address} @var{interface} @code{static} @var{address}/@var{prefixlength}
@end multitable
On some platforms, when running tinc in switch mode, the VPN interface must be set to tap mode with an ifconfig command:
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
@item OpenBSD
@tab @code{ifconfig} @var{interface} @code{link0}
@end multitable
On Linux, it is possible to create a persistent tun/tap interface which will
continue to exist even if tinc quit, although this is normally not required.
It can be useful to set up a tun/tap interface owned by a non-root user, so
tinc can be started without needing any root privileges at all.
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
@item Linux
@tab @code{ip tuntap add dev} @var{interface} @code{mode} @var{tun|tap} @code{user} @var{username}
@end multitable
@c ==================================================================
@node Routes

View file

@ -1,4 +1,4 @@
.Dd 2011-06-25
.Dd 2012-10-14
.Dt TINCCTL 8
.\" Manual page created by:
.\" Scott Lamb
@ -37,12 +37,58 @@ 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
.zZ
.Bl -tag -width indent
.It start
.It init Op Ar name
Create initial configuration files and RSA and ECDSA keypairs with default length.
If no
.Ar name
for this node is given, it will be asked for.
.It config Oo get Oc Ar variable
Print the current value of configuration variable
.Ar variable .
If more than one variable with the same name exists,
the value of each of them will be printed on a separate line.
.It config Oo set Oc Ar variable Ar value
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 config add Ar variable Ar value
As above, but without removing any previously existing configuration variables.
.It config 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 Op Fl -force
Import host configuration file(s) from standard input.
Already existing host configuration files are not overwritten unless the option
.Fl -force
is used.
.It start Op tincd options
Start
.Xr tincd 8 .
.Xr tincd 8 ,
optionally with the given extra options.
.It stop
Stop
.Xr tincd 8 .
@ -69,6 +115,7 @@ If
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 nodes
Dump a list of all known nodes in the VPN.
.It dump edges
@ -77,15 +124,25 @@ Dump a list of all known connections in the VPN.
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
.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 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 tincctl .
.It retry
Forces
.Xr tincd 8
@ -123,7 +180,16 @@ Examples of some commands:
tincctl -n vpn dump graph | circo -Txlib
tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top
.Pp
.Ed
Example of configuring tinc using
.Nm :
.Bd -literal -offset indent
tincctl -n vpn init foo
tincctl -n vpn config Subnet 192.168.1.0/24
tincctl -n vpn config bar.Address bar.example.com
tincctl -n vpn config ConnectTo bar
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
.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,
@ -172,7 +238,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
.Xr tincd 8 ,
.Xr tinc.conf 5 ,
.Xr dotty 1 ,
.Xr pcap-savefile 7 ,
.Xr pcap-savefile 5 ,
.Xr tcpdump 8 ,
.Xr top 1 ,
.Pa http://www.tinc-vpn.org/ ,

View file

@ -1,4 +1,4 @@
.Dd 2011-06-25
.Dd 2012-02-22
.Dt TINCD 8
.\" Manual page created by:
.\" Ivo Timmermans
@ -8,11 +8,12 @@
.Nd tinc VPN daemon
.Sh SYNOPSIS
.Nm
.Op Fl cdDKnLRU
.Op Fl cdDKnoLRU
.Op Fl -config Ns = Ns Ar DIR
.Op Fl -no-detach
.Op Fl -debug Ns Op = Ns Ar LEVEL
.Op Fl -net Ns = Ns Ar NETNAME
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
.Op Fl -mlock
.Op Fl -logfile Ns Op = Ns Ar FILE
.Op Fl -bypass-security
@ -61,6 +62,22 @@ for
.Ar NETNAME
is the same as not specifying any
.Ar NETNAME .
.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
Without specifying a
.Ar HOST ,
this will set server configuration variable
.Ar KEY
to
.Ar VALUE .
If specified as
.Ar HOST.KEY=VALUE ,
this will set the host configuration variable
.Ar KEY
of the host named
.Ar HOST
to
.Ar VALUE .
This option can be used more than once to specify multiple configuration variables.
.It Fl L, -mlock
Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.

View file

@ -1,9 +1,9 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -16,6 +16,23 @@
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@ -41,7 +58,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@ -69,10 +87,21 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(bindir)"
SCRIPTS = $(dist_bin_SCRIPTS)
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@ -122,6 +151,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -213,8 +243,11 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-dist_binSCRIPTS: $(dist_bin_SCRIPTS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
@ -242,9 +275,7 @@ uninstall-dist_binSCRIPTS:
@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 's,.*/,,;$(transform)'`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
tags: TAGS
TAGS:
@ -299,10 +330,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:

View file

@ -1,12 +1,35 @@
#!/usr/bin/python
# tinc-gui -- GUI for controlling a running tincd
# Copyright (C) 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.
import string
import socket
import wx
import sys
import os
import platform
import time
from wx.lib.mixins.listctrl import ColumnSorterMixin
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
if platform.system == 'Windows':
import _winreg
# Classes to interface with a running tinc daemon
REQ_STOP = 0
@ -30,34 +53,32 @@ CONTROL = 18
class Node:
def parse(self, args):
self.name = args[0]
self.address = args[2]
if args[3] != 'port':
args.insert(3, 'port')
args.insert(4, '')
self.port = args[4]
self.cipher = int(args[6])
self.digest = int(args[8])
self.maclength = int(args[10])
self.compression = int(args[12])
self.options = int(args[14], 0x10)
self.status = int(args[16], 0x10)
self.nexthop = args[18]
self.via = args[20]
self.distance = int(args[22])
self.pmtu = int(args[24])
self.minmtu = int(args[26])
self.maxmtu = int(args[28][:-1])
self.address = args[1]
self.port = args[3]
self.cipher = int(args[4])
self.digest = int(args[5])
self.maclength = int(args[6])
self.compression = int(args[7])
self.options = int(args[8], 0x10)
self.status = int(args[9], 0x10)
self.nexthop = args[10]
self.via = args[11]
self.distance = int(args[12])
self.pmtu = int(args[13])
self.minmtu = int(args[14])
self.maxmtu = int(args[15])
self.last_state_change = float(args[16])
self.subnets = {}
class Edge:
def parse(self, args):
self.fr = args[0]
self.to = args[2]
self.address = args[4]
self.port = args[6]
self.options = int(args[8], 16)
self.weight = int(args[10])
self.to = args[1]
self.address = args[2]
self.port = args[4]
self.options = int(args[5], 16)
self.weight = int(args[6])
class Subnet:
def parse(self, args):
@ -73,19 +94,16 @@ class Subnet:
self.address = address
self.prefixlen = '48'
self.owner = args[2]
self.owner = args[1]
class Connection:
def parse(self, args):
self.name = args[0]
self.address = args[2]
if args[3] != 'port':
args.insert(3, 'port')
args.insert(4, '')
self.port = args[4]
self.options = int(args[6], 0x10)
self.socket = int(args[8])
self.status = int(args[10], 0x10)
self.address = args[1]
self.port = args[3]
self.options = int(args[4], 0x10)
self.socket = int(args[5])
self.status = int(args[6], 0x10)
self.weight = 123
class VPN:
@ -132,34 +150,34 @@ class VPN:
if resp[0] != '18':
break
if resp[1] == '3':
if len(resp) < 3:
if len(resp) < 19:
continue
node = self.nodes.get(resp[2]) or Node()
node.parse(resp[2:])
node.visited = True
self.nodes[resp[2]] = node
elif resp[1] == '4':
if len(resp) < 5:
if len(resp) < 9:
continue
edge = self.nodes.get((resp[2], resp[4])) or Edge()
edge = self.nodes.get((resp[2], resp[3])) or Edge()
edge.parse(resp[2:])
edge.visited = True
self.edges[(resp[2], resp[4])] = edge
self.edges[(resp[2], resp[3])] = edge
elif resp[1] == '5':
if len(resp) < 5:
if len(resp) < 4:
continue
subnet = self.subnets.get((resp[2], resp[4])) or Subnet()
subnet = self.subnets.get((resp[2], resp[3])) or Subnet()
subnet.parse(resp[2:])
subnet.visited = True
self.subnets[(resp[2], resp[4])] = subnet
self.subnets[(resp[2], resp[3])] = subnet
self.nodes[subnet.owner].subnets[resp[2]] = subnet
elif resp[1] == '6':
if len(resp) < 5:
if len(resp) < 9:
break
connection = self.connections.get((resp[2], resp[4])) or Connection()
connection = self.connections.get((resp[2], resp[3], resp[5])) or Connection()
connection.parse(resp[2:])
connection.visited = True
self.connections[(resp[2], resp[4])] = connection
self.connections[(resp[2], resp[3], resp[5])] = connection
else:
break
@ -198,27 +216,38 @@ class VPN:
return int(resp[2])
def __init__(self, netname = None, pidfile = None):
self.tincconf = VPN.confdir + '/'
if platform.system == 'Windows':
try:
reg = _winreg.ConnectRegistry(None, HKEY_LOCAL_MACHINE)
key = _winreg.OpenKey(reg, "SOFTWARE\\tinc")
VPN.confdir = _winreg.QueryValue(key, None)
except WindowsError:
pass
if netname:
self.netname = netname
self.tincconf += netname + '/'
self.confbase = os.path.join(VPN.confdir, netname)
else:
self.confbase = VPN.confdir
self.tincconf += 'tinc.conf'
self.tincconf = os.path.join(self.confbase, 'tinc.conf')
if pidfile is not None:
if pidfile != None:
self.pidfile = pidfile
else:
self.pidfile = VPN.piddir + 'tinc.'
if platform.system == 'Windows':
self.pidfile = os.path.join(self.confbase, 'pid')
else:
if netname:
self.pidfile += netname + '.'
self.pidfile += 'pid'
self.pidfile = os.path.join(VPN.piddir, 'tinc.' + netname + '.pid')
else:
self.pidfile = os.path.join(VPN.piddir, 'tinc.pid')
# GUI starts here
argv0 = sys.argv[0]
del sys.argv[0]
net = None
netname = None
pidfile = None
def usage(exitcode = 0):
@ -230,10 +259,10 @@ def usage(exitcode = 0):
print('\nReport bugs to tinc@tinc-vpn.org.')
sys.exit(exitcode)
while len(sys.argv):
while sys.argv:
if sys.argv[0] in ('-n', '--net'):
del sys.argv[0]
net = sys.argv[0]
netname = sys.argv[0]
elif sys.argv[0] in ('--pidfile'):
del sys.argv[0]
pidfile = sys.argv[0]
@ -245,14 +274,20 @@ while len(sys.argv):
del sys.argv[0]
vpn = VPN(net, pidfile)
if netname == None:
netname = os.getenv("NETNAME")
if netname == ".":
netname = None
vpn = VPN(netname, pidfile)
vpn.connect()
class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin):
def __init__(self, parent, style):
wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
ListCtrlAutoWidthMixin.__init__(self)
ColumnSorterMixin.__init__(self, 14)
ColumnSorterMixin.__init__(self, 16)
def GetListCtrl(self):
return self
@ -265,12 +300,12 @@ class SettingsPage(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
grid = wx.FlexGridSizer(cols = 2)
grid.AddGrowableCol(0, 1)
grid.AddGrowableCol(1, 1)
namelabel = wx.StaticText(self, -1, 'Name:')
self.name = wx.TextCtrl(self, -1, vpn.name)
grid.Add(namelabel)
grid.Add(self.name)
grid.Add(self.name, 1, wx.EXPAND)
portlabel = wx.StaticText(self, -1, 'Port:')
self.port = wx.TextCtrl(self, -1, vpn.port)
@ -293,7 +328,7 @@ class SettingsPage(wx.Panel):
class ConnectionsPage(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
self.list = SuperListCtrl(self, id)
self.list.InsertColumn(0, 'Name')
self.list.InsertColumn(1, 'Address')
self.list.InsertColumn(2, 'Port')
@ -323,6 +358,7 @@ class ConnectionsPage(wx.Panel):
self.PopupMenu(self.ContextMenu(self.list.itemDataMap[event.GetIndex()]), event.GetPosition())
def refresh(self):
sortstate = self.list.GetSortState()
self.list.itemDataMap = {}
i = 0
@ -337,11 +373,13 @@ class ConnectionsPage(wx.Panel):
self.list.SetStringItem(i, 4, str(connection.weight))
self.list.itemDataMap[i] = (connection.name, connection.address, connection.port, connection.options, connection.weight)
self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContext)
self.list.SetItemData(i, i)
i += 1
while self.list.GetItemCount() > i:
self.list.DeleteItem(self.list.GetItemCount() - 1)
self.list.SortListItems(sortstate[0], sortstate[1])
class NodesPage(wx.Panel):
def __init__(self, parent, id):
@ -362,6 +400,7 @@ class NodesPage(wx.Panel):
self.list.InsertColumn(12, 'PMTU')
self.list.InsertColumn(13, 'Min MTU')
self.list.InsertColumn(14, 'Max MTU')
self.list.InsertColumn(15, 'Since')
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox.Add(self.list, 1, wx.EXPAND)
@ -369,6 +408,7 @@ class NodesPage(wx.Panel):
self.refresh()
def refresh(self):
sortstate = self.list.GetSortState()
self.list.itemDataMap = {}
i = 0
@ -383,25 +423,32 @@ class NodesPage(wx.Panel):
self.list.SetStringItem(i, 4, str(node.digest))
self.list.SetStringItem(i, 5, str(node.maclength))
self.list.SetStringItem(i, 6, str(node.compression))
self.list.SetStringItem(i, 7, str(node.options))
self.list.SetStringItem(i, 8, str(node.status))
self.list.SetStringItem(i, 7, format(node.options, "x"))
self.list.SetStringItem(i, 8, format(node.status, "04x"))
self.list.SetStringItem(i, 9, node.nexthop)
self.list.SetStringItem(i, 10, node.via)
self.list.SetStringItem(i, 11, str(node.distance))
self.list.SetStringItem(i, 12, str(node.pmtu))
self.list.SetStringItem(i, 13, str(node.minmtu))
self.list.SetStringItem(i, 14, str(node.maxmtu))
self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu)
if node.last_state_change:
since = time.strftime("%Y-%m-%d %H:%M", time.localtime(node.last_state_change))
else:
since = "never"
self.list.SetStringItem(i, 15, since)
self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu, since)
self.list.SetItemData(i, i)
i += 1
while self.list.GetItemCount() > i:
self.list.DeleteItem(self.list.GetItemCount() - 1)
self.list.SortListItems(sortstate[0], sortstate[1])
class EdgesPage(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
self.list = SuperListCtrl(self, id)
self.list.InsertColumn(0, 'From')
self.list.InsertColumn(1, 'To')
self.list.InsertColumn(2, 'Address')
@ -415,6 +462,7 @@ class EdgesPage(wx.Panel):
self.refresh()
def refresh(self):
sortstate = self.list.GetSortState()
self.list.itemDataMap = {}
i = 0
@ -426,14 +474,17 @@ class EdgesPage(wx.Panel):
self.list.SetStringItem(i, 1, edge.to)
self.list.SetStringItem(i, 2, edge.address)
self.list.SetStringItem(i, 3, edge.port)
self.list.SetStringItem(i, 4, str(edge.options))
self.list.SetStringItem(i, 4, format(edge.options, "x"))
self.list.SetStringItem(i, 5, str(edge.weight))
self.list.itemDataMap[i] = (edge.fr, edge.to, edge.address, edge.port, edge.options, edge.weight)
self.list.SetItemData(i, i)
i += 1
while self.list.GetItemCount() > i:
self.list.DeleteItem(self.list.GetItemCount() - 1)
self.list.SortListItems(sortstate[0], sortstate[1])
class SubnetsPage(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
@ -447,6 +498,7 @@ class SubnetsPage(wx.Panel):
self.refresh()
def refresh(self):
sortstate = self.list.GetSortState()
self.list.itemDataMap = {}
i = 0
@ -458,11 +510,14 @@ class SubnetsPage(wx.Panel):
self.list.SetStringItem(i, 1, subnet.weight)
self.list.SetStringItem(i, 2, subnet.owner)
self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner)
i = i + 1
self.list.SetItemData(i, i)
i += 1
while self.list.GetItemCount() > i:
self.list.DeleteItem(self.list.GetItemCount() - 1)
self.list.SortListItems(sortstate[0], sortstate[1])
class StatusPage(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
@ -493,7 +548,7 @@ class NetPage(wx.Notebook):
class MainWindow(wx.Frame):
def OnQuit(self, event):
self.Close(True)
app.ExitMainLoop()
def OnTimer(self, event):
vpn.refresh()

9
have.h
View file

@ -1,7 +1,7 @@
/*
have.h -- include headers which are known to exist
Copyright (C) 1998-2005 Ivo Timmermans
2003-2011 Guus Sliepen <guus@tinc-vpn.org>
2003-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
@ -42,6 +42,7 @@
#ifdef HAVE_MINGW
#include <w32api.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#endif
@ -199,4 +200,10 @@
#include <event.h>
#endif
#ifdef HAVE_MINGW
#define SLASH "\\"
#else
#define SLASH "/"
#endif
#endif /* __TINC_SYSTEM_H__ */

View file

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2009-04-28.21; # UTC
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -156,6 +156,10 @@ while test $# -ne 0; do
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
@ -186,6 +190,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
@ -200,7 +208,11 @@ if test $# -eq 0; then
fi
if test -z "$dir_arg"; then
trap '(exit $?); exit' 1 2 13 15
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
@ -228,9 +240,9 @@ fi
for src
do
# Protect names starting with `-'.
# Protect names problematic for `test' and other utilities.
case $src in
-*) src=./$src;;
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
@ -252,12 +264,7 @@ do
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
@ -385,7 +392,7 @@ do
case $dstdir in
/*) prefix='/';;
-*) prefix='./';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
@ -403,7 +410,7 @@ do
for d
do
test -z "$d" && continue
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then

View file

@ -1,9 +1,9 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@ -39,7 +56,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@ -48,6 +66,11 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@ -97,6 +120,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -236,10 +260,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:

View file

@ -35,7 +35,7 @@ AC_DEFUN([tinc_OPENSSL],
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 openssl/ecdh.h openssl/ec.h],
[],
[AC_MSG_ERROR([OpenSSL header files not found.]); break]
)
@ -45,7 +45,7 @@ AC_DEFUN([tinc_OPENSSL],
[AC_MSG_ERROR([OpenSSL libraries not found.])]
)
AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex], ,
AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex ECDH_compute_key ECDSA_verify], ,
[AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
)

42
m4/readline.m4 Normal file
View file

@ -0,0 +1,42 @@
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)
])

53
missing
View file

@ -1,10 +1,10 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2009-04-28.21; # UTC
scriptversion=2012-01-06.13; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009 Free Software Foundation, Inc.
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
@ -84,7 +84,6 @@ Supported PROGRAM values:
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
@ -122,15 +121,6 @@ case $1 in
# Not GNU programs, they don't have --version.
;;
tar*)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
@ -226,7 +216,7 @@ WARNING: \`$1' $msg. You should only need it if
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG="\${$#}"
eval LASTARG=\${$#}
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
@ -256,7 +246,7 @@ WARNING: \`$1' is $msg. You should only need it if
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG="\${$#}"
eval LASTARG=\${$#}
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
@ -318,41 +308,6 @@ WARNING: \`$1' is $msg. You should only need it if
touch $file
;;
tar*)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case $firstarg in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case $firstarg in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.

View file

@ -1,30 +1,43 @@
## Produce this file with automake to get Makefile.in
sbin_PROGRAMS = tincd tincctl
sbin_PROGRAMS = tincd tincctl sptps_test
EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
tincd_SOURCES = \
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c \
buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c tincd.c \
dummy_device.c raw_socket_device.c multicast_device.c
if UML
tincd_SOURCES += uml_device.c
endif
if VDE
tincd_SOURCES += vde_device.c
endif
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
list.c tincctl.c top.c
info.c list.c subnet_parse.c tincctl.c top.c
nodist_tincctl_SOURCES = \
ecdsagen.c rsagen.c
sptps_test_SOURCES = \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
sptps.c sptps_test.c utils.c
if TUNEMU
tincd_SOURCES += bsd/tunemu.c
endif
tincctl_LDADD = $(CURSES_LIBS)
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =
@ -32,8 +45,8 @@ INCLUDES = @INCLUDES@ -I$(top_builddir)
noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h tincctl.h top.h bsd/tunemu.h
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h

View file

@ -1,9 +1,9 @@
# Makefile.in generated by automake 1.11.1 from Makefile.am.
# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -17,6 +17,23 @@
VPATH = @srcdir@
am__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@ -35,9 +52,11 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT)
@TUNEMU_TRUE@am__append_1 = bsd/tunemu.c
@TUNEMU_TRUE@am__append_2 = -lpcap
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sptps_test$(EXEEXT)
@UML_TRUE@am__append_1 = uml_device.c
@VDE_TRUE@am__append_2 = vde_device.c
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c
@TUNEMU_TRUE@am__append_4 = -lpcap
subdir = src
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
@ -45,7 +64,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@ -54,34 +74,47 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)"
PROGRAMS = $(sbin_PROGRAMS)
am_sptps_test_OBJECTS = logger.$(OBJEXT) cipher.$(OBJEXT) \
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
digest.$(OBJEXT) prf.$(OBJEXT) sptps.$(OBJEXT) \
sptps_test.$(OBJEXT) utils.$(OBJEXT)
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
sptps_test_LDADD = $(LDADD)
am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
getopt1.$(OBJEXT) dropin.$(OBJEXT) list.$(OBJEXT) \
tincctl.$(OBJEXT) top.$(OBJEXT)
getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
top.$(OBJEXT)
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
am__DEPENDENCIES_1 =
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1)
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
buffer.c conf.c connection.c control.c edge.c graph.c logger.c \
meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \
node.c process.c protocol.c protocol_auth.c protocol_edge.c \
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
subnet.c tincd.c bsd/tunemu.c
@TUNEMU_TRUE@am__objects_1 = tunemu.$(OBJEXT)
hash.c buffer.c conf.c connection.c control.c edge.c graph.c \
logger.c meta.c net.c net_packet.c net_setup.c net_socket.c \
netutl.c node.c process.c protocol.c protocol_auth.c \
protocol_edge.c protocol_misc.c protocol_key.c \
protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c \
tincd.c dummy_device.c raw_socket_device.c multicast_device.c \
uml_device.c vde_device.c bsd/tunemu.c
@UML_TRUE@am__objects_1 = uml_device.$(OBJEXT)
@VDE_TRUE@am__objects_2 = vde_device.$(OBJEXT)
@TUNEMU_TRUE@am__objects_3 = tunemu.$(OBJEXT)
am_tincd_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
list.$(OBJEXT) splay_tree.$(OBJEXT) dropin.$(OBJEXT) \
fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \
buffer.$(OBJEXT) conf.$(OBJEXT) connection.$(OBJEXT) \
control.$(OBJEXT) edge.$(OBJEXT) graph.$(OBJEXT) \
logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \
hash.$(OBJEXT) buffer.$(OBJEXT) conf.$(OBJEXT) \
connection.$(OBJEXT) control.$(OBJEXT) edge.$(OBJEXT) \
graph.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \
net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \
netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \
protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \
protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \
route.$(OBJEXT) subnet.$(OBJEXT) tincd.$(OBJEXT) \
$(am__objects_1)
route.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
subnet_parse.$(OBJEXT) tincd.$(OBJEXT) dummy_device.$(OBJEXT) \
raw_socket_device.$(OBJEXT) multicast_device.$(OBJEXT) \
$(am__objects_1) $(am__objects_2) $(am__objects_3)
nodist_tincd_OBJECTS = device.$(OBJEXT) cipher.$(OBJEXT) \
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT)
@ -94,9 +127,16 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(tincctl_SOURCES) $(nodist_tincctl_SOURCES) \
$(tincd_SOURCES) $(nodist_tincd_SOURCES)
DIST_SOURCES = $(tincctl_SOURCES) $(am__tincd_SOURCES_DIST)
SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
$(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
$(nodist_tincd_SOURCES)
DIST_SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
$(am__tincd_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(nodist_noinst_HEADERS) $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
@ -133,7 +173,7 @@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_2)
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_4)
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
@ -149,6 +189,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@ -203,30 +244,36 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \
dropin.c fake-getaddrinfo.c fake-getnameinfo.c buffer.c conf.c \
connection.c control.c edge.c graph.c logger.c meta.c net.c \
net_packet.c net_setup.c net_socket.c netutl.c node.c \
dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c buffer.c \
conf.c connection.c control.c edge.c graph.c logger.c meta.c \
net.c net_packet.c net_setup.c net_socket.c netutl.c node.c \
process.c protocol.c protocol_auth.c protocol_edge.c \
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
subnet.c tincd.c $(am__append_1)
sptps.c subnet.c subnet_parse.c tincd.c dummy_device.c \
raw_socket_device.c multicast_device.c $(am__append_1) \
$(am__append_2) $(am__append_3)
nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \
list.c tincctl.c top.c
info.c list.c subnet_parse.c tincctl.c top.c
nodist_tincctl_SOURCES = \
ecdsagen.c rsagen.c
tincctl_LDADD = $(CURSES_LIBS)
sptps_test_SOURCES = \
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
sptps.c sptps_test.c utils.c
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES =
noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h tincctl.h top.h bsd/tunemu.h
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
@ -268,8 +315,11 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \
@ -303,10 +353,13 @@ uninstall-sbinPROGRAMS:
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES)
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
@rm -f sptps_test$(EXEEXT)
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES) $(EXTRA_tincctl_DEPENDENCIES)
@rm -f tincctl$(EXEEXT)
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS)
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES)
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
@rm -f tincd$(EXEEXT)
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
@ -325,6 +378,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/digest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dropin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsagen.Po@am__quote@
@ -334,9 +388,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/graph.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/meta.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multicast_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_packet.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_setup.Po@am__quote@
@ -351,16 +408,22 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_key.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_misc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_subnet.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_socket_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsagen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay_tree.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet_parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincctl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/top.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tunemu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@ -492,10 +555,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2011 Guus Sliepen <guus@tinc-vpn.org>
2001-2012 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify
@ -33,7 +33,12 @@
#include "bsd/tunemu.h"
#endif
#define DEFAULT_DEVICE "/dev/tun0"
#define DEFAULT_TUN_DEVICE "/dev/tun0"
#if defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
#define DEFAULT_TAP_DEVICE "/dev/tap0"
#else
#define DEFAULT_TAP_DEVICE "/dev/tun0"
#endif
typedef enum device_type {
DEVICE_TYPE_TUN,
@ -58,11 +63,15 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
static device_type_t device_type = DEVICE_TYPE_TUN;
#endif
bool setup_device(void) {
static bool setup_device(void) {
char *type;
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = xstrdup(DEFAULT_DEVICE);
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);
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
@ -81,7 +90,7 @@ bool setup_device(void) {
else if(!strcasecmp(type, "tap"))
device_type = DEVICE_TYPE_TAP;
else {
logger(LOG_ERR, "Unknown device type %s!", type);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
return false;
}
} else {
@ -102,10 +111,14 @@ bool setup_device(void) {
}
if(device_fd < 0) {
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
return false;
}
#ifdef FD_CLOEXEC
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
switch(device_type) {
default:
device_type = DEVICE_TYPE_TUN;
@ -114,7 +127,7 @@ bool setup_device(void) {
{
const int zero = 0;
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false;
}
}
@ -133,7 +146,7 @@ bool setup_device(void) {
{
const int one = 1;
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false;
}
}
@ -170,12 +183,12 @@ bool setup_device(void) {
#endif
}
logger(LOG_INFO, "%s is a %s", device, device_info);
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void) {
static void close_device(void) {
switch(device_type) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
@ -190,7 +203,7 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int inlen;
switch(device_type) {
@ -204,7 +217,7 @@ bool read_packet(vpn_packet_t *packet) {
inlen = read(device_fd, packet->data + 14, MTU - 14);
if(inlen <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -219,12 +232,13 @@ bool read_packet(vpn_packet_t *packet) {
packet->data[13] = 0xDD;
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = inlen + 14;
break;
@ -233,7 +247,7 @@ bool read_packet(vpn_packet_t *packet) {
struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
if((inlen = readv(device_fd, vector, 2)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -250,19 +264,20 @@ bool read_packet(vpn_packet_t *packet) {
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while reading packet from %s %s",
ntohl(type), device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = inlen + 10;
break;
}
case DEVICE_TYPE_TAP:
if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -276,20 +291,20 @@ bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
packet->len, device_info);
return true;
}
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
static bool write_packet(vpn_packet_t *packet) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
switch(device_type) {
case DEVICE_TYPE_TUN:
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -310,14 +325,14 @@ bool write_packet(vpn_packet_t *packet) {
type = htonl(AF_INET6);
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while writing packet to %s %s",
af, device_info, device);
return false;
}
if(writev(device_fd, vector, 2) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -326,7 +341,7 @@ bool write_packet(vpn_packet_t *packet) {
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -335,7 +350,7 @@ bool write_packet(vpn_packet_t *packet) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -351,8 +366,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
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);
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

218
src/cipher.c Normal file
View file

@ -0,0 +1,218 @@
/*
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 <openssl/rand.h>
#include <openssl/err.h>
#include "cipher.h"
#include "logger.h"
#include "xalloc.h"
typedef struct cipher_counter {
unsigned char counter[EVP_MAX_IV_LENGTH];
unsigned char block[EVP_MAX_IV_LENGTH];
int n;
} cipher_counter_t;
static bool cipher_open(cipher_t *cipher) {
EVP_CIPHER_CTX_init(&cipher->ctx);
return true;
}
bool cipher_open_by_name(cipher_t *cipher, const char *name) {
cipher->cipher = EVP_get_cipherbyname(name);
if(cipher->cipher)
return cipher_open(cipher);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
return false;
}
bool cipher_open_by_nid(cipher_t *cipher, int nid) {
cipher->cipher = EVP_get_cipherbynid(nid);
if(cipher->cipher)
return cipher_open(cipher);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
return false;
}
bool cipher_open_blowfish_ofb(cipher_t *cipher) {
cipher->cipher = EVP_bf_ofb();
return cipher_open(cipher);
}
void cipher_close(cipher_t *cipher) {
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
free(cipher->counter);
cipher->counter = NULL;
}
size_t cipher_keylength(const cipher_t *cipher) {
return cipher->cipher->key_len + cipher->cipher->block_size;
}
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
bool result;
if(encrypt)
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
else
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
if(result)
return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
bool result;
if(encrypt)
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
else
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
if(result)
return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
bool cipher_set_counter(cipher_t *cipher, const void *counter, size_t len) {
if(len > cipher->cipher->block_size - 4) {
logger(DEBUG_ALWAYS, LOG_ERR, "Counter too long");
abort();
}
memcpy(cipher->counter->counter + cipher->cipher->block_size - len, counter, len);
memset(cipher->counter->counter, 0, 4);
cipher->counter->n = 0;
return true;
}
bool cipher_set_counter_key(cipher_t *cipher, void *key) {
int result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, NULL);
if(!result) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
if(!cipher->counter)
cipher->counter = xmalloc_and_zero(sizeof *cipher->counter);
else
cipher->counter->n = 0;
memcpy(cipher->counter->counter, (unsigned char *)key + cipher->cipher->key_len, cipher->cipher->block_size);
return true;
}
bool cipher_counter_xor(cipher_t *cipher, const void *indata, size_t inlen, void *outdata) {
if(!cipher->counter) {
logger(DEBUG_ALWAYS, LOG_ERR, "Counter not initialized");
return false;
}
const unsigned char *in = indata;
unsigned char *out = outdata;
while(inlen--) {
// Encrypt the new counter value if we need it
if(!cipher->counter->n) {
int len;
if(!EVP_EncryptUpdate(&cipher->ctx, cipher->counter->block, &len, cipher->counter->counter, cipher->cipher->block_size)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
// Increase the counter value
for(int i = 0; i < cipher->cipher->block_size; i++)
if(++cipher->counter->counter[i])
break;
}
*out++ = *in++ ^ cipher->counter->counter[cipher->counter->n++];
if(cipher->counter->n >= cipher->cipher->block_size)
cipher->counter->n = 0;
}
return true;
}
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
if(oneshot) {
int len, pad;
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
if(outlen) *outlen = len + pad;
return true;
}
} else {
int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
if(outlen) *outlen = len;
return true;
}
}
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
if(oneshot) {
int len, pad;
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
if(outlen) *outlen = len + pad;
return true;
}
} else {
int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
if(outlen) *outlen = len;
return true;
}
}
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
int cipher_get_nid(const cipher_t *cipher) {
return cipher->cipher ? cipher->cipher->nid : 0;
}
bool cipher_active(const cipher_t *cipher) {
return cipher->cipher && cipher->cipher->nid != 0;
}

View file

@ -2,7 +2,7 @@
conf.c -- configuration code
Copyright (C) 1998 Robert van der Meulen
1998-2005 Ivo Timmermans
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
2000 Cris van Pelt
@ -141,7 +141,7 @@ bool get_config_bool(const config_t *cfg, bool *result) {
return true;
}
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
logger(DEBUG_ALWAYS, LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
@ -154,7 +154,7 @@ bool get_config_int(const config_t *cfg, int *result) {
if(sscanf(cfg->value, "%d", result) == 1)
return true;
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
logger(DEBUG_ALWAYS, LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
@ -182,7 +182,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
return true;
}
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
logger(DEBUG_ALWAYS, LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
@ -195,7 +195,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
return false;
if(!str2net(&subnet, cfg->value)) {
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
@ -206,7 +206,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
|| ((subnet.type == SUBNET_IPV6)
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) {
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
@ -236,8 +236,9 @@ static char *readline(FILE * fp, char *buf, size_t buflen) {
if(!newline)
return buf;
*newline = '\0'; /* kill newline */
if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
/* kill newline and carriage return if necessary */
*newline = '\0';
if(newline > p && newline[-1] == '\r')
newline[-1] = '\0';
return buf;
@ -265,10 +266,10 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
if(!*value) {
const char err[] = "No value for variable";
if (fname)
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' on line %d while reading config file %s",
err, variable, lineno, fname);
else
logger(LOG_ERR, "%s `%s' in command line option %d",
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' in command line option %d",
err, variable, lineno);
return NULL;
}
@ -298,7 +299,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
return false;
}
@ -339,33 +340,31 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
}
void read_config_options(splay_tree_t *config_tree, const char *prefix) {
list_node_t *node, *next;
size_t prefix_len = prefix ? strlen(prefix) : 0;
for(node = cmdline_conf->tail; node; node = next) {
config_t *orig_cfg, *cfg = (config_t *)node->data;
next = node->prev;
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
const config_t *cfg = node->data;
config_t *new;
if(!prefix) {
if(strchr(cfg->variable, '.'))
continue;
node->data = NULL;
list_unlink_node(cmdline_conf, node);
} else {
if(strncmp(prefix, cfg->variable, prefix_len) ||
cfg->variable[prefix_len] != '.')
continue;
/* Because host configuration is parsed again when
reconnecting, nodes must not be freed when a prefix
is given. */
orig_cfg = cfg;
cfg = new_config();
cfg->variable = xstrdup(orig_cfg->variable + prefix_len + 1);
cfg->value = xstrdup(orig_cfg->value);
cfg->file = NULL;
cfg->line = orig_cfg->line;
}
config_add(config_tree, cfg);
new = new_config();
if(prefix)
new->variable = xstrdup(cfg->variable + prefix_len + 1);
else
new->variable = xstrdup(cfg->variable);
new->value = xstrdup(cfg->value);
new->file = NULL;
new->line = cfg->line;
config_add(config_tree, new);
}
}
@ -375,26 +374,25 @@ bool read_server_config(void) {
read_config_options(config_tree, NULL);
xasprintf(&fname, "%s/tinc.conf", confbase);
xasprintf(&fname, "%s" SLASH "tinc.conf", confbase);
x = read_config_file(config_tree, fname);
if(!x) { /* System error: complain */
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
}
if(!x)
logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
free(fname);
return x;
}
bool read_connection_config(connection_t *c) {
bool read_host_config(splay_tree_t *config_tree, const char *name) {
char *fname;
bool x;
read_config_options(c->config_tree, c->name);
read_config_options(config_tree, name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
x = read_config_file(c->config_tree, fname);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
x = read_config_file(config_tree, fname);
free(fname);
return x;
@ -402,12 +400,12 @@ bool read_connection_config(connection_t *c) {
bool append_config_file(const char *name, const char *key, const char *value) {
char *fname;
xasprintf(&fname, "%s/hosts/%s", confbase, name);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
FILE *fp = fopen(fname, "a");
if(!fp) {
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
} else {
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
fclose(fp);
@ -415,45 +413,5 @@ bool append_config_file(const char *name, const char *key, const char *value) {
free(fname);
return fp;
}
bool disable_old_keys(FILE *f) {
char buf[100];
long pos;
bool disabled = false;
rewind(f);
pos = ftell(f);
if(pos < 0)
return false;
while(fgets(buf, sizeof buf, f)) {
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
buf[11] = 'O';
buf[12] = 'L';
buf[13] = 'D';
if(fseek(f, pos, SEEK_SET))
break;
if(fputs(buf, f) <= 0)
break;
disabled = true;
}
else if(!strncmp(buf, "-----END RSA", 12)) {
buf[ 9] = 'O';
buf[10] = 'L';
buf[11] = 'D';
if(fseek(f, pos, SEEK_SET))
break;
if(fputs(buf, f) <= 0)
break;
disabled = true;
}
pos = ftell(f);
if(pos < 0)
break;
}
return disabled;
return fp != NULL;
}

View file

@ -1,7 +1,7 @@
/*
conf.h -- header for conf.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2009 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
it under the terms of the GNU General Public License as published by
@ -60,10 +60,7 @@ extern config_t *parse_config_line(char *, const char *, int);
extern bool read_config_file(splay_tree_t *, const char *);
extern void read_config_options(splay_tree_t *, const char *);
extern bool read_server_config(void);
extern bool read_connection_config(struct connection_t *);
extern bool read_host_config(splay_tree_t *, const char *);
extern bool append_config_file(const char *, const char *, const char *);
extern FILE *ask_and_open(const char *, const char *, const char *);
extern bool is_safe_path(const char *);
extern bool disable_old_keys(FILE *);
#endif /* __TINC_CONF_H__ */

View file

@ -1,6 +1,6 @@
/*
connection.c -- connection list management
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
2008 Max Rijevski <maksuf@gmail.com>
@ -21,7 +21,7 @@
#include "system.h"
#include "splay_tree.h"
#include "list.h"
#include "cipher.h"
#include "conf.h"
#include "control_common.h"
@ -31,23 +31,19 @@
#include "utils.h"
#include "xalloc.h"
splay_tree_t *connection_tree; /* Meta connections */
connection_t *broadcast;
static int connection_compare(const connection_t *a, const connection_t *b) {
return a < b ? -1 : a == b ? 0 : 1;
}
list_t *connection_list;
connection_t *everyone;
void init_connections(void) {
connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection);
broadcast = new_connection();
broadcast->name = xstrdup("everyone");
broadcast->hostname = xstrdup("BROADCAST");
connection_list = list_alloc((list_action_t) free_connection);
everyone = new_connection();
everyone->name = xstrdup("everyone");
everyone->hostname = xstrdup("BROADCAST");
}
void exit_connections(void) {
splay_delete_tree(connection_tree);
free_connection(broadcast);
list_delete_list(connection_list);
free_connection(everyone);
}
connection_t *new_connection(void) {
@ -58,27 +54,17 @@ void free_connection(connection_t *c) {
if(!c)
return;
if(c->name)
free(c->name);
if(c->hostname)
free(c->hostname);
cipher_close(&c->incipher);
digest_close(&c->indigest);
cipher_close(&c->outcipher);
digest_close(&c->outdigest);
ecdh_free(&c->ecdh);
sptps_stop(&c->sptps);
ecdsa_free(&c->ecdsa);
rsa_free(&c->rsa);
if(c->hischallenge)
free(c->hischallenge);
if(c->config_tree)
exit_configuration(&c->config_tree);
buffer_clear(&c->inbuf);
buffer_clear(&c->outbuf);
@ -91,24 +77,26 @@ void free_connection(connection_t *c) {
if(c->socket > 0)
closesocket(c->socket);
free(c->name);
free(c->hostname);
if(c->config_tree)
exit_configuration(&c->config_tree);
free(c);
}
void connection_add(connection_t *c) {
splay_insert(connection_tree, c);
list_insert_tail(connection_list, c);
}
void connection_del(connection_t *c) {
splay_delete(connection_tree, c);
list_delete(connection_list, c);
}
bool dump_connections(connection_t *cdump) {
splay_node_t *node;
connection_t *c;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
send_request(cdump, "%d %d %s at %s options %x socket %d status %04x",
for list_each(connection_t, c, connection_list) {
send_request(cdump, "%d %d %s %s %x %d %x",
CONTROL, REQ_DUMP_CONNECTIONS,
c->name, c->hostname, c->options, c->socket,
bitfield_to_int(&c->status, sizeof c->status));

View file

@ -1,6 +1,6 @@
/*
connection.h -- header for connection.c
Copyright (C) 2000-2010 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -25,29 +25,31 @@
#include "cipher.h"
#include "digest.h"
#include "rsa.h"
#include "splay_tree.h"
#include "list.h"
#include "sptps.h"
#define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002
#define OPTION_PMTU_DISCOVERY 0x0004
#define OPTION_CLAMP_MSS 0x0008
#define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
typedef struct connection_status_t {
unsigned int pinged:1; /* sent ping */
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 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 timeout_unused:1; /* 1 if gotten timeout */
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 mst:1; /* 1 if this connection is part of a minimum spanning tree */
unsigned int control:1;
unsigned int pcap:1;
unsigned int unused:21;
unsigned int control:1; /* 1 if this is a control connection */
unsigned int pcap:1; /* 1 if this is a control connection requesting packet capture */
unsigned int log:1; /* 1 if this is a control connection requesting log dump */
unsigned int unused:20;
} connection_status_t;
#include "ecdh.h"
#include "ecdsa.h"
#include "edge.h"
#include "net.h"
@ -73,11 +75,11 @@ typedef struct connection_t {
rsa_t rsa; /* his public RSA key */
ecdsa_t ecdsa; /* his public ECDSA key */
ecdsa_t ecdh; /* state for ECDH key exchange */
cipher_t incipher; /* Cipher he will use to send data to us */
cipher_t outcipher; /* Cipher we will use to send data to him */
digest_t indigest;
digest_t outdigest;
sptps_t sptps;
int inmaclength;
int outmaclength;
@ -98,8 +100,8 @@ typedef struct connection_t {
splay_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
} connection_t;
extern splay_tree_t *connection_tree;
extern connection_t *broadcast;
extern list_t *connection_list;
extern connection_t *everyone;
extern void init_connections(void);
extern void exit_connections(void);

View file

@ -1,6 +1,6 @@
/*
control.c -- Control socket handling.
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -29,7 +29,6 @@
#include "netutl.h"
#include "protocol.h"
#include "route.h"
#include "splay_tree.h"
#include "utils.h"
#include "xalloc.h"
@ -44,16 +43,16 @@ static bool control_ok(connection_t *c, int type) {
return control_return(c, type, 0);
}
bool control_h(connection_t *c, char *request) {
bool control_h(connection_t *c, const char *request) {
int type;
if(!c->status.control || c->allow_request != CONTROL) {
logger(LOG_ERR, "Unauthorized control request from %s (%s)", c->name, c->hostname);
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(LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
return false;
}
@ -93,22 +92,18 @@ bool control_h(connection_t *c, char *request) {
return control_ok(c, REQ_RETRY);
case REQ_RELOAD:
logger(LOG_NOTICE, "Got '%s' command", "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];
connection_t *other;
splay_node_t *node, *next;
bool found = false;
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1)
return control_return(c, REQ_DISCONNECT, -1);
for(node = connection_tree->head; node; node = next) {
next = node->next;
other = node->data;
for list_each(connection_t, other, connection_list) {
if(strcmp(other->name, name))
continue;
terminate_connection(other, other->status.active);
@ -122,10 +117,17 @@ bool control_h(connection_t *c, char *request) {
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);
}
@ -137,7 +139,7 @@ bool init_control(void) {
FILE *f = fopen(pidfilename, "w");
if(!f) {
logger(LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
return false;
}

View file

@ -1,6 +1,7 @@
/*
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
@ -39,6 +40,7 @@ enum request_type {
REQ_DISCONNECT,
REQ_DUMP_TRAFFIC,
REQ_PCAP,
REQ_LOG,
};
#define TINC_CTL_VERSION_CURRENT 0

43
src/crypto.c Normal file
View file

@ -0,0 +1,43 @@
/*
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 <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include "crypto.h"
void crypto_init(void) {
RAND_load_file("/dev/urandom", 1024);
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
OpenSSL_add_all_algorithms();
}
void crypto_exit(void) {
EVP_cleanup();
}
void randomize(void *out, size_t outlen) {
RAND_pseudo_bytes(out, outlen);
}

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Windows tap driver in a Cygwin environment
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2009 Guus Sliepen <guus@tinc-vpn.org>
2002-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
@ -45,7 +45,7 @@ static uint64_t device_total_out = 0;
static pid_t reader_pid;
static int sp[2];
bool setup_device(void) {
static bool setup_device(void) {
HKEY key, key2;
int i, err;
@ -64,7 +64,7 @@ bool setup_device(void) {
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false;
}
@ -116,7 +116,7 @@ bool setup_device(void) {
RegCloseKey(key);
if(!found) {
logger(LOG_ERR, "No Windows tap device found!");
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
return false;
}
@ -133,7 +133,7 @@ bool setup_device(void) {
Furthermore I don't really know how to do it the "Windows" way. */
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
return false;
}
@ -142,7 +142,7 @@ bool setup_device(void) {
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
return false;
}
@ -151,7 +151,7 @@ bool setup_device(void) {
/* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
return false;
}
@ -164,7 +164,7 @@ bool setup_device(void) {
reader_pid = fork();
if(reader_pid == -1) {
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
return false;
}
@ -180,13 +180,13 @@ bool setup_device(void) {
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
buf[0] = 0;
write(sp[1], buf, 1);
exit(1);
}
logger(LOG_DEBUG, "Tap reader forked and running.");
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader forked and running.");
/* Notify success */
@ -203,18 +203,18 @@ bool setup_device(void) {
read(device_fd, &gelukt, 1);
if(gelukt != 1) {
logger(LOG_DEBUG, "Tap reader failed!");
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader failed!");
return false;
}
device_info = "Windows tap device";
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
void close_device(void) {
static void close_device(void) {
close(sp[0]);
close(sp[1]);
CloseHandle(device_handle);
@ -225,11 +225,11 @@ void close_device(void) {
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int inlen;
if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -238,20 +238,20 @@ bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
long outlen;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
@ -260,8 +260,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
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);
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -1,7 +1,7 @@
/*
net.h -- generic header for device.c
device.h -- generic header for device.c
Copyright (C) 2001-2005 Ivo Timmermans
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
2001-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
@ -32,10 +32,20 @@ extern uint64_t device_in_bytes;
extern uint64_t device_out_packets;
extern uint64_t device_out_bytes;
extern bool setup_device(void);
extern void close_device(void);
extern bool read_packet(struct vpn_packet_t *);
extern bool write_packet(struct vpn_packet_t *);
extern void dump_device_stats(void);
typedef struct devops_t {
bool (*setup)(void);
void (*close)(void);
bool (*read)(struct vpn_packet_t *);
bool (*write)(struct vpn_packet_t *);
void (*dump_stats)(void);
} devops_t;
extern const devops_t os_devops;
extern const devops_t dummy_devops;
extern const devops_t raw_socket_devops;
extern const devops_t multicast_devops;
extern const devops_t uml_devops;
extern const devops_t vde_devops;
extern devops_t devops;
#endif /* __TINC_DEVICE_H__ */

127
src/digest.c Normal file
View file

@ -0,0 +1,127 @@
/*
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 "utils.h"
#include "xalloc.h"
#include <openssl/err.h>
#include <openssl/hmac.h>
#include "digest.h"
#include "logger.h"
static void set_maclength(digest_t *digest, int maclength) {
int digestlen = EVP_MD_size(digest->digest);
if(maclength > digestlen || maclength < 0)
digest->maclength = digestlen;
else
digest->maclength = maclength;
}
bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
digest->digest = EVP_get_digestbyname(name);
digest->key = NULL;
if(!digest->digest) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
return false;
}
set_maclength(digest, maclength);
return true;
}
bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
digest->digest = EVP_get_digestbynid(nid);
digest->key = NULL;
if(!digest->digest) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
return false;
}
set_maclength(digest, maclength);
return true;
}
bool digest_open_sha1(digest_t *digest, int maclength) {
digest->digest = EVP_sha1();
digest->key = NULL;
set_maclength(digest, maclength);
return true;
}
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
digest->key = xrealloc(digest->key, len);
memcpy(digest->key, key, len);
digest->keylength = len;
return true;
}
void digest_close(digest_t *digest) {
free(digest->key);
digest->key = NULL;
}
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
size_t len = EVP_MD_size(digest->digest);
unsigned char tmpdata[len];
if(digest->key) {
HMAC(digest->digest, digest->key, digest->keylength, indata, inlen, tmpdata, NULL);
} else {
EVP_MD_CTX ctx;
if(!EVP_DigestInit(&ctx, digest->digest)
|| !EVP_DigestUpdate(&ctx, indata, inlen)
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
}
memcpy(outdata, tmpdata, digest->maclength);
return true;
}
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
size_t len = digest->maclength;
unsigned char outdata[len];
return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, digest->maclength);
}
int digest_get_nid(const digest_t *digest) {
return digest->digest ? digest->digest->type : 0;
}
size_t digest_keylength(const digest_t *digest) {
return digest->digest->md_size;
}
size_t digest_length(const digest_t *digest) {
return digest->maclength;
}
bool digest_active(const digest_t *digest) {
return digest->digest && digest->digest->type != 0;
}

62
src/dummy_device.c Normal file
View file

@ -0,0 +1,62 @@
/*
device.c -- Dummy device
Copyright (C) 2011-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 "device.h"
#include "logger.h"
#include "net.h"
static char *device_info = "dummy device";
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
static bool setup_device(void) {
device = "dummy";
iface = "dummy";
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
static void close_device(void) {
}
static bool read_packet(vpn_packet_t *packet) {
return false;
}
static bool write_packet(vpn_packet_t *packet) {
device_total_out += packet->len;
return true;
}
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t dummy_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

96
src/ecdh.c Normal file
View file

@ -0,0 +1,96 @@
/*
ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011-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 "utils.h"
#include "xalloc.h"
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include "ecdh.h"
#include "logger.h"
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!*ecdh) {
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
if(!EC_KEY_generate_key(*ecdh)) {
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
const EC_POINT *point = EC_KEY_get0_public_key(*ecdh);
if(!point) {
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
if(!result) {
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
}
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh));
if(!point) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL);
if(!result) {
EC_POINT_free(point);
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
result = ECDH_compute_key(shared, ECDH_SIZE, point, *ecdh, NULL);
EC_POINT_free(point);
EC_KEY_free(*ecdh);
*ecdh = NULL;
if(!result) {
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
}
void ecdh_free(ecdh_t *ecdh) {
if(*ecdh) {
EC_KEY_free(*ecdh);
*ecdh = NULL;
}
}

130
src/ecdsa.c Normal file
View file

@ -0,0 +1,130 @@
/*
ecdsa.c -- ECDSA key handling
Copyright (C) 2011-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 <openssl/pem.h>
#include <openssl/err.h>
#include "logger.h"
#include "ecdsa.h"
#include "utils.h"
// Get and set ECDSA keys
//
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!*ecdsa) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
int len = strlen(p);
unsigned char pubkey[len / 4 * 3 + 3];
const unsigned char *ppubkey = pubkey;
len = b64decode(p, (char *)pubkey, len);
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
}
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
unsigned char *pubkey = NULL;
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5);
b64encode((char *)pubkey, base64, len);
free(pubkey);
return base64;
}
// Read PEM ECDSA keys
bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
*ecdsa = PEM_read_EC_PUBKEY(fp, ecdsa, NULL, NULL);
if(*ecdsa)
return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
*ecdsa = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL);
if(*ecdsa)
return true;
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
size_t ecdsa_size(ecdsa_t *ecdsa) {
return ECDSA_size(*ecdsa);
}
// TODO: standardise output format?
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa);
unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash);
memset(sig, 0, siglen);
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
}
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa);
unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash);
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
}
bool ecdsa_active(ecdsa_t *ecdsa) {
return *ecdsa;
}
void ecdsa_free(ecdsa_t *ecdsa) {
if(*ecdsa) {
EC_KEY_free(*ecdsa);
*ecdsa = NULL;
}
}

View file

@ -1,6 +1,6 @@
/*
edge.c -- edge tree management
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -29,7 +29,7 @@
#include "utils.h"
#include "xalloc.h"
splay_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
splay_tree_t *edge_weight_tree;
static int edge_compare(const edge_t *a, const edge_t *b) {
return strcmp(a->to->name, b->to->name);
@ -107,17 +107,10 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
}
bool dump_edges(connection_t *c) {
splay_node_t *node, *node2;
node_t *n;
edge_t *e;
char *address;
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);
send_request(c, "%d %d %s to %s at %s options %x weight %d",
for splay_each(node_t, n, node_tree) {
for splay_each(edge_t, e, n->edge_tree) {
char *address = sockaddr2hostname(&e->address);
send_request(c, "%d %d %s %s %s %x %d",
CONTROL, REQ_DUMP_EDGES,
e->from->name, e->to->name, address,
e->options, e->weight);

View file

@ -1,6 +1,6 @@
/*
edge.h -- header for edge.c
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify

View file

@ -32,8 +32,7 @@ struct addrinfo {
#endif /* !HAVE_STRUCT_ADDRINFO */
#if !HAVE_DECL_GETADDRINFO
int getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
#endif /* !HAVE_GETADDRINFO */
#if !HAVE_DECL_GAI_STRERROR

View file

@ -2,8 +2,7 @@
#define _FAKE_GETNAMEINFO_H
#if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags);
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

View file

@ -1,6 +1,6 @@
/*
cipher.c -- Symmetric block cipher handling
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -97,12 +97,12 @@ static bool cipher_open(cipher_t *cipher, int algo, int mode) {
gcry_error_t err;
if(!ciphertonid(algo, mode, &cipher->nid)) {
logger(LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
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(LOG_DEBUG, "Unable to intialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unable to intialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
return false;
}
@ -118,7 +118,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
int algo, mode;
if(!nametocipher(name, &algo, &mode)) {
logger(LOG_DEBUG, "Unknown cipher name '%s'!", name);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher name '%s'!", name);
return false;
}
@ -129,7 +129,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
int algo, mode;
if(!nidtocipher(nid, &algo, &mode)) {
logger(LOG_DEBUG, "Unknown cipher ID %d!", nid);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher ID %d!", nid);
return false;
}
@ -199,7 +199,7 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
size_t reqlen = ((inlen + cipher->blklen) / cipher->blklen) * cipher->blklen;
if(*outlen < reqlen) {
logger(LOG_ERR, "Error while encrypting: not enough room for padding");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: not enough room for padding");
return false;
}
@ -217,13 +217,13 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
if((err = gcry_cipher_encrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
logger(LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
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(LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
return false;
}
@ -241,7 +241,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
if((err = gcry_cipher_decrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
logger(LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
return false;
}
@ -252,7 +252,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
uint8_t padbyte = ((uint8_t *)outdata)[inlen - 1];
if(padbyte == 0 || padbyte > cipher->blklen || padbyte > inlen) {
logger(LOG_ERR, "Error while decrypting: invalid padding");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
return false;
}
@ -260,7 +260,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
for(int i = inlen - 1; i >= origlen; i--)
if(((uint8_t *)outdata)[i] != padbyte) {
logger(LOG_ERR, "Error while decrypting: invalid padding");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
return false;
}

View file

@ -1,6 +1,6 @@
/*
cipher.h -- header file cipher.c
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-2009 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

View file

@ -1,6 +1,6 @@
/*
crypto.h -- header for crypto.c
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-2009 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

View file

@ -1,6 +1,6 @@
/*
digest.c -- Digest handling
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -75,7 +75,7 @@ static bool digesttonid(int algo, int *nid) {
static bool digest_open(digest_t *digest, int algo, int maclength) {
if(!digesttonid(algo, &digest->nid)) {
logger(LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
return false;
}
@ -96,7 +96,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
int algo;
if(!nametodigest(name, &algo)) {
logger(LOG_DEBUG, "Unknown digest name '%s'!", name);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
return false;
}
@ -107,7 +107,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
int algo;
if(!nidtodigest(nid, &algo)) {
logger(LOG_DEBUG, "Unknown digest ID %d!", nid);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest ID %d!", nid);
return false;
}

View file

@ -1,6 +1,6 @@
/*
digest.h -- header file digest.c
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-2009 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

View file

@ -1,6 +1,6 @@
/*
rsa.c -- RSA key handling
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -187,7 +187,7 @@ bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
if(err) {
logger(LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
return false;
}
@ -202,7 +202,7 @@ bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
?: gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
if(err) {
logger(LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
return false;
}
@ -216,7 +216,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
size_t derlen;
if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
logger(LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
return NULL;
}
@ -224,7 +224,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|| derlen) {
logger(LOG_ERR, "Error while decoding RSA public key");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA public key");
return NULL;
}
@ -236,7 +236,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
size_t derlen;
if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
logger(LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
return NULL;
}
@ -251,7 +251,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|| !ber_read_mpi(&derp, &derlen, NULL)
|| !ber_read_mpi(&derp, &derlen, NULL) // u
|| derlen) {
logger(LOG_ERR, "Error while decoding RSA private key");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA private key");
return NULL;
}
@ -267,7 +267,7 @@ size_t rsa_size(rsa_t *rsa) {
*/
// TODO: get rid of this macro, properly clean up gcry_ structures after use
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(DEBUG_ALWAYS, LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
gcry_mpi_t inmpi;

View file

@ -1,6 +1,6 @@
/*
rsagen.c -- RSA key generation and export
Copyright (C) 2008 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2008-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
@ -164,12 +164,12 @@ bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
if(!ber_write_mpi(&derp1, &derlen1, &rsa->n)
|| !ber_write_mpi(&derp1, &derlen1, &rsa->e)
|| !ber_write_sequence(&derp2, &derlen2, derbuf1, derlen1)) {
logger(LOG_ERR, "Error while encoding RSA public key");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA public key");
return false;
}
if(!pem_encode(fp, "RSA PUBLIC KEY", derbuf2, derlen2)) {
logger(LOG_ERR, "Unable to write RSA public key: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA public key: %s", strerror(errno));
return false;
}
@ -193,12 +193,12 @@ bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
|| ber_write_mpi(&derp1, &derlen1, &exp1)
|| ber_write_mpi(&derp1, &derlen1, &exp2)
|| ber_write_mpi(&derp1, &derlen1, &coeff))
logger(LOG_ERR, "Error while encoding RSA private key");
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA private key");
return false;
}
if(!pem_encode(fp, "RSA PRIVATE KEY", derbuf2, derlen2)) {
logger(LOG_ERR, "Unable to write RSA private key: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA private key: %s", strerror(errno));
return false;
}

View file

@ -1,6 +1,6 @@
/*
graph.c -- graph algorithms
Copyright (C) 2001-2011 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -44,12 +44,12 @@
#include "system.h"
#include "splay_tree.h"
#include "config.h"
#include "connection.h"
#include "device.h"
#include "edge.h"
#include "graph.h"
#include "list.h"
#include "logger.h"
#include "netutl.h"
#include "node.h"
@ -65,34 +65,22 @@
Please note that sorting on weight is already done by add_edge().
*/
void mst_kruskal(void) {
splay_node_t *node, *next;
edge_t *e;
node_t *n;
connection_t *c;
static void mst_kruskal(void) {
/* Clear MST status on connections */
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
for list_each(connection_t, c, connection_list)
c->status.mst = false;
}
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Running Kruskal's algorithm:");
/* Clear visited status on nodes */
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for splay_each(node_t, n, node_tree)
n->status.visited = false;
}
/* Add safe edges */
for(node = edge_weight_tree->head; node; node = next) {
next = node->next;
e = node->data;
for splay_each(edge_t, e, edge_weight_tree) {
if(!e->reverse || (e->from->status.visited && e->to->status.visited))
continue;
@ -105,31 +93,21 @@ void mst_kruskal(void) {
if(e->reverse->connection)
e->reverse->connection->status.mst = true;
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
e->to->name, e->weight);
}
}
/* Implementation of Dijkstra's algorithm.
Running time: O(N^2)
/* Implementation of a simple breadth-first search algorithm.
Running time: O(E)
*/
static void sssp_dijkstra(void) {
splay_node_t *node, *to;
edge_t *e;
node_t *n, *m;
list_t *todo_list;
list_node_t *lnode, *nnode;
bool indirect;
todo_list = list_alloc(NULL);
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:");
static void sssp_bfs(void) {
list_t *todo_list = list_alloc(NULL);
/* Clear visited status on nodes */
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for splay_each(node_t, n, node_tree) {
n->status.visited = false;
n->status.indirect = true;
n->distance = -1;
@ -137,119 +115,23 @@ static void sssp_dijkstra(void) {
/* Begin with myself */
myself->status.visited = true;
myself->status.indirect = false;
myself->nexthop = myself;
myself->prevedge = NULL;
myself->via = myself;
myself->distance = 0;
list_insert_head(todo_list, myself);
/* Loop while todo_list is filled */
while(todo_list->head) {
n = NULL;
nnode = NULL;
for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Examining edges from %s", n->name);
/* Select node from todo_list with smallest distance */
for(lnode = todo_list->head; lnode; lnode = lnode->next) {
m = lnode->data;
if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) {
n = m;
nnode = lnode;
}
}
/* Mark this node as visited and remove it from the todo_list */
n->status.visited = true;
list_unlink_node(todo_list, nnode);
/* Update distance of neighbours and add them to the todo_list */
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
e = to->data;
if(e->to->status.visited || !e->reverse)
continue;
/* Situation:
/
/
----->(n)---e-->(e->to)
\
\
Where e is an edge, (n) and (e->to) are nodes.
n->address is set to the e->address of the edge left of n to n.
We are currently examining the edge e right of n from n:
- If edge e provides for better reachability of e->to, update e->to.
*/
if(e->to->distance < 0)
list_insert_tail(todo_list, e->to);
indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address));
if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight)
continue;
e->to->distance = n->distance + e->weight;
e->to->status.indirect = indirect;
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
e->to->via = indirect ? n->via : e->to;
e->to->options = e->options;
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
update_node_udp(e->to, &e->address);
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name,
e->to->name, e->weight, e->to->distance);
}
}
list_free(todo_list);
}
/* Implementation of a simple breadth-first search algorithm.
Running time: O(E)
*/
void sssp_bfs(void) {
splay_node_t *node, *to;
edge_t *e;
node_t *n;
list_t *todo_list;
list_node_t *from, *todonext;
bool indirect;
todo_list = list_alloc(NULL);
/* Clear visited status on nodes */
for(node = node_tree->head; node; node = node->next) {
n = node->data;
n->status.visited = false;
n->status.indirect = true;
}
/* Begin with myself */
myself->status.visited = true;
myself->status.indirect = false;
myself->nexthop = myself;
myself->via = myself;
list_insert_head(todo_list, myself);
/* Loop while todo_list is filled */
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
n = from->data;
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
e = to->data;
if(n->distance < 0)
abort();
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
if(!e->reverse)
continue;
@ -270,61 +152,63 @@ void sssp_bfs(void) {
of nodes behind it.
*/
indirect = n->status.indirect || e->options & OPTION_INDIRECT;
bool indirect = n->status.indirect || e->options & OPTION_INDIRECT;
if(e->to->status.visited
&& (!e->to->status.indirect || indirect))
&& (!e->to->status.indirect || indirect)
&& (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
continue;
e->to->status.visited = true;
e->to->status.indirect = indirect;
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
e->to->prevedge = e;
e->to->via = indirect ? n->via : e->to;
e->to->options = e->options;
e->to->distance = n->distance + 1;
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN))
update_node_udp(e->to, &e->address);
list_insert_tail(todo_list, e->to);
}
todonext = from->next;
list_delete_node(todo_list, from);
next = node->next; /* Because the list_insert_tail() above could have added something extra for us! */
list_delete_node(todo_list, node);
}
list_free(todo_list);
}
static void check_reachability(void) {
splay_node_t *node, *next;
node_t *n;
char *name;
char *address, *port;
char *envp[7];
int i;
/* Check reachability status. */
for(node = node_tree->head; node; node = next) {
next = node->next;
n = node->data;
for splay_each(node_t, n, node_tree) {
if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable;
n->last_state_change = time(NULL);
if(n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
n->name, n->hostname);
} else {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became unreachable",
n->name, n->hostname);
}
if(experimental && OPTION_VERSION(n->options) >= 2)
n->status.sptps = true;
/* TODO: only clear status.validkey if node is unreachable? */
n->status.validkey = false;
if(n->status.sptps) {
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
}
n->last_req_key = 0;
n->status.udp_confirmed = false;
n->maxmtu = MTU;
n->minmtu = 0;
n->mtuprobes = 0;
@ -332,6 +216,11 @@ static void check_reachability(void) {
if(timeout_initialized(&n->mtuevent))
event_del(&n->mtuevent);
char *name;
char *address;
char *port;
char *envp[7];
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
@ -343,31 +232,37 @@ static void check_reachability(void) {
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
xasprintf(&name,
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
n->name);
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
execute_script(name, envp);
free(name);
free(address);
free(port);
for(i = 0; i < 6; i++)
for(int i = 0; i < 6; i++)
free(envp[i]);
subnet_update(n, NULL, n->status.reachable);
if(!n->status.reachable)
if(!n->status.reachable) {
update_node_udp(n, NULL);
else if(n->connection)
memset(&n->status, 0, sizeof n->status);
n->options = 0;
} else if(n->connection) {
if(n->status.sptps) {
if(n->connection->outgoing)
send_req_key(n);
} else {
send_ans_key(n);
}
}
}
}
}
void graph(void) {
subnet_cache_flush();
sssp_dijkstra();
sssp_bfs();
check_reachability();
mst_kruskal();
}

View file

@ -1,6 +1,6 @@
/*
graph.h -- header for graph.c
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify

105
src/hash.c Normal file
View file

@ -0,0 +1,105 @@
/*
hash.c -- hash table management
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.
*/
#include "system.h"
#include "hash.h"
#include "xalloc.h"
/* Generic hash function */
static uint32_t hash_function(const void *p, size_t len) {
const uint8_t *q = p;
uint32_t hash = 0;
while(true) {
for(int i = len > 4 ? 4 : len; --i;)
hash += q[i] << (8 * i);
hash *= 0x9e370001UL; // Golden ratio prime.
if(len <= 4)
break;
len -= 4;
}
return hash;
}
/* Map 32 bits int onto 0..n-1, without throwing away too many bits if n is 2^8 or 2^16 */
static uint32_t modulo(uint32_t hash, size_t n) {
if(n == 0x100)
return (hash >> 24) ^ ((hash >> 16) & 0xff) ^ ((hash >> 8) & 0xff) ^ (hash & 0xff);
else if(n == 0x10000)
return (hash >> 16) ^ (hash & 0xffff);
else
return hash % n;
}
/* (De)allocation */
hash_t *hash_alloc(size_t n, size_t size) {
hash_t *hash = xmalloc_and_zero(sizeof *hash);
hash->n = n;
hash->size = size;
hash->keys = xmalloc(hash->n * hash->size);
hash->values = xmalloc_and_zero(hash->n * sizeof *hash->values);
return hash;
}
void hash_free(hash_t *hash) {
free(hash->keys);
free(hash->values);
free(hash);
}
/* Searching and inserting */
void hash_insert(hash_t *hash, const void *key, const void *value) {
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
memcpy(hash->keys + i * hash->size, key, hash->size);
hash->values[i] = value;
}
void *hash_search(const hash_t *hash, const void *key) {
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
return (void *)hash->values[i];
}
return NULL;
}
void *hash_search_or_insert(hash_t *hash, const void *key, const void *value) {
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size))
return (void *)hash->values[i];
memcpy(hash->keys + i * hash->size, key, hash->size);
hash->values[i] = value;
return NULL;
}
/* Utility functions */
void hash_clear(hash_t *hash) {
memset(hash->values, 0, hash->n * sizeof *hash->values);
}
void hash_resize(hash_t *hash, size_t n) {
hash->keys = xrealloc(hash->keys, n * hash->size);
hash->values = xrealloc(hash->values, n * sizeof *hash->values);
if(n > hash->n)
memset(hash->values + hash->n, 0, (n - hash->n) * sizeof *hash->values);
}

41
src/hash.h Normal file
View file

@ -0,0 +1,41 @@
/*
hash.h -- header file for hash.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.
*/
#ifndef __TINC_HASH_H__
#define __TINC_HASH_H__
typedef struct hash_t {
size_t n;
size_t size;
char *keys;
const void **values;
} hash_t;
extern hash_t *hash_alloc(size_t n, size_t size) __attribute__ ((__malloc__));
extern void hash_free(hash_t *);
extern void hash_insert(hash_t *, const void *key, const void *value);
extern void *hash_search(const hash_t *, const void *key);
extern void *hash_search_or_insert(hash_t *, const void *key, const void *value);
extern void hash_clear(hash_t *);
extern void hash_resize(hash_t *, size_t n);
#endif /* __TINC_HASH_H__ */

266
src/info.c Normal file
View file

@ -0,0 +1,266 @@
/*
info.c -- Show information about a node, subnet or address
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.
*/
#include "system.h"
#include "control_common.h"
#include "list.h"
#include "subnet.h"
#include "tincctl.h"
#include "info.h"
#include "xalloc.h"
void logger(int level, int priority, const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
char *strip_weight(char *netstr) {
int len = strlen(netstr);
if(len >= 3 && !strcmp(netstr + len - 3, "#10"))
netstr[len - 3] = 0;
return netstr;
}
static int info_node(int fd, const char *item) {
// Check the list of nodes
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_NODES, item);
bool found = false;
char line[4096];
char node[4096];
char from[4096];
char to[4096];
char subnet[4096];
char host[4096];
char port[4096];
char via[4096];
char nexthop[4096];
int code, req, cipher, digest, maclength, compression, distance;
short int pmtu, minmtu, maxmtu;
unsigned int options;
node_status_t status;
long int last_state_change;
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
if(n == 2)
break;
if(n != 18) {
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
if(!strcmp(node, item)) {
found = true;
break;
}
}
if(!found) {
fprintf(stderr, "Unknown node %s.\n", item);
return 1;
}
while(recvline(fd, line, sizeof line)) {
if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
break;
}
printf("Node: %s\n", item);
printf("Address: %s port %s\n", host, port);
char timestr[32] = "never";
if(last_state_change)
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&last_state_change));
if(status.reachable)
printf("Online since: %s\n", timestr);
else
printf("Last seen: %s\n", timestr);
printf("Status: ");
if(status.validkey)
printf(" validkey");
if(status.visited)
printf(" visited");
if(status.reachable)
printf(" reachable");
if(status.indirect)
printf(" indirect");
if(status.sptps)
printf(" sptps");
if(status.udp_confirmed)
printf(" udp_confirmed");
printf("\n");
printf("Options: ");
if(options & OPTION_INDIRECT)
printf(" indirect");
if(options & OPTION_TCPONLY)
printf(" tcponly");
if(options & OPTION_PMTU_DISCOVERY)
printf(" pmtu_discovery");
if(options & OPTION_CLAMP_MSS)
printf(" clamp_mss");
printf("\n");
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
printf("Reachability: ");
if(!strcmp(host, "MYSELF"))
printf("can reach itself\n");
else if(!status.reachable)
printf("unreachable\n");
else if(strcmp(via, item))
printf("indirectly via %s\n", via);
else if(!status.validkey)
printf("unknown\n");
else if(minmtu > 0)
printf("directly with UDP\nPMTU: %d\n", pmtu);
else if(!strcmp(nexthop, item))
printf("directly with TCP\n");
else
printf("none, forwarded via %s\n", nexthop);
// List edges
printf("Edges: ");
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s %s", &code, &req, from, to);
if(n == 2)
break;
if(n != 4) {
fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
return 1;
}
if(!strcmp(from, item))
printf(" %s", to);
}
printf("\n");
// List subnets
printf("Subnets: ");
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s %s", &code, &req, subnet, from);
if(n == 2)
break;
if(n != 4) {
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
return 1;
}
if(!strcmp(from, item))
printf(" %s", strip_weight(subnet));
}
printf("\n");
return 0;
}
static int info_subnet(int fd, const char *item) {
subnet_t subnet, find;
if(!str2net(&find, item)) {
fprintf(stderr, "Could not parse subnet or address '%s'.\n", item);
return 1;
}
bool address = !strchr(item, '/');
bool weight = strchr(item, '#');
bool found = false;
char line[4096];
char netstr[4096];
char owner[4096];
int code, req;
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s %s", &code, &req, netstr, owner);
if(n == 2)
break;
if(n != 4 || !str2net(&subnet, netstr)) {
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
return 1;
}
if(find.type != subnet.type)
continue;
if(weight) {
if(find.weight != subnet.weight)
continue;
}
if(find.type == SUBNET_IPV4) {
if(address) {
if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength))
continue;
} else {
if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength)
continue;
if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
continue;
}
} else if(find.type == SUBNET_IPV6) {
if(address) {
if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength))
continue;
} else {
if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength)
continue;
if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
continue;
}
} if(find.type == SUBNET_MAC) {
if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof subnet.net.mac))
continue;
}
found = true;
printf("Subnet: %s\n", strip_weight(netstr));
printf("Owner: %s\n", owner);
}
if(!found) {
if(address)
fprintf(stderr, "Unknown address %s.\n", item);
else
fprintf(stderr, "Unknown subnet %s.\n", item);
return 1;
}
return 0;
}
int info(int fd, const char *item) {
if(check_id(item))
return info_node(fd, item);
if(strchr(item, '.') || strchr(item, ':'))
return info_subnet(fd, item);
fprintf(stderr, "Argument is not a node name, subnet or address.\n");
return 1;
}

27
src/info.h Normal file
View file

@ -0,0 +1,27 @@
/*
info.h -- header for info.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.
*/
#ifndef __TINC_INFO_H__
#define __TINC_INFO_H__
extern int info(int fd, const char *item);
extern char *strip_weight(char *);
#endif

View file

@ -1,7 +1,7 @@
/*
ipv4.h -- missing IPv4 related definitions
Copyright (C) 2005 Ivo Timmermans
2006 Guus Sliepen <guus@tinc-vpn.org>
2006-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
@ -41,6 +41,14 @@
#define ICMP_NET_UNKNOWN 6
#endif
#ifndef ICMP_TIME_EXCEEDED
#define ICMP_TIME_EXCEEDED 11
#endif
#ifndef ICMP_EXC_TTL
#define ICMP_EXC_TTL 0
#endif
#ifndef ICMP_NET_UNREACH
#define ICMP_NET_UNREACH 0
#endif

View file

@ -1,7 +1,7 @@
/*
ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans
2006 Guus Sliepen <guus@tinc-vpn.org>
2006-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
@ -95,8 +95,10 @@ struct icmp6_hdr {
#define ICMP6_DST_UNREACH_NOROUTE 0
#define ICMP6_DST_UNREACH 1
#define ICMP6_PACKET_TOO_BIG 2
#define ICMP6_TIME_EXCEEDED 3
#define ICMP6_DST_UNREACH_ADMIN 1
#define ICMP6_DST_UNREACH_ADDR 3
#define ICMP6_TIME_EXCEED_TRANSIT 0
#define ND_NEIGHBOR_SOLICIT 135
#define ND_NEIGHBOR_ADVERT 136
#define icmp6_data32 icmp6_dataun.icmp6_un_data32

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Linux ethertap and tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2009 Guus Sliepen <guus@tinc-vpn.org>
2001-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
@ -41,6 +41,7 @@ int device_fd = -1;
static device_type_t device_type;
char *device = NULL;
char *iface = NULL;
static char *type = NULL;
static char ifrname[IFNAMSIZ];
static char *device_info;
@ -49,27 +50,35 @@ uint64_t device_in_bytes = 0;
uint64_t device_out_packets = 0;
uint64_t device_out_bytes = 0;
bool setup_device(void) {
static bool setup_device(void) {
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = xstrdup(DEFAULT_DEVICE);
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
#ifdef HAVE_LINUX_IF_TUN_H
if (netname != NULL)
if(netname)
iface = xstrdup(netname);
#else
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
#endif
device_fd = open(device, O_RDWR | O_NONBLOCK);
if(device_fd < 0) {
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
return false;
}
#ifdef FD_CLOEXEC
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
struct ifreq ifr = {{{0}}};
if(routing_mode == RMODE_ROUTER) {
get_config_string(lookup_config(config_tree, "DeviceType"), &type);
if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
return false;
}
if((type && !strcasecmp(type, "tun")) || (!type && routing_mode == RMODE_ROUTER)) {
ifr.ifr_flags = IFF_TUN;
device_type = DEVICE_TYPE_TUN;
device_info = "Linux tun/tap device (tun mode)";
@ -92,28 +101,24 @@ bool setup_device(void) {
if(!ioctl(device_fd, TUNSETIFF, &ifr)) {
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
if(iface) free(iface);
iface = xstrdup(ifrname);
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
if(iface) free(iface);
free(iface);
iface = xstrdup(ifrname);
}
logger(LOG_INFO, "%s is a %s", device, device_info);
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void) {
static void close_device(void) {
close(device_fd);
free(type);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
int inlen;
switch(device_type) {
@ -121,18 +126,19 @@ bool read_packet(vpn_packet_t *packet) {
inlen = read(device_fd, packet->data + 10, MTU - 10);
if(inlen <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
memset(packet->data, 0, 12);
packet->len = inlen + 10;
break;
case DEVICE_TYPE_TAP:
inlen = read(device_fd, packet->data, MTU);
if(inlen <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
@ -146,28 +152,28 @@ bool read_packet(vpn_packet_t *packet) {
device_in_packets++;
device_in_bytes += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
static bool write_packet(vpn_packet_t *packet) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
switch(device_type) {
case DEVICE_TYPE_TUN:
packet->data[10] = packet->data[11] = 0;
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -182,8 +188,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

View file

@ -1,7 +1,7 @@
/*
list.c -- functions to deal with double linked lists
Copyright (C) 2000-2005 Ivo Timmermans
2000-2006 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
it under the terms of the GNU General Public License as published by
@ -26,9 +26,7 @@
/* (De)constructors */
list_t *list_alloc(list_action_t delete) {
list_t *list;
list = xmalloc_and_zero(sizeof(list_t));
list_t *list = xmalloc_and_zero(sizeof(list_t));
list->delete = delete;
return list;
@ -52,9 +50,7 @@ void list_free_node(list_t *list, list_node_t *node) {
/* Insertion and deletion */
list_node_t *list_insert_head(list_t *list, void *data) {
list_node_t *node;
node = list_alloc_node();
list_node_t *node = list_alloc_node();
node->data = data;
node->prev = NULL;
@ -72,9 +68,7 @@ list_node_t *list_insert_head(list_t *list, void *data) {
}
list_node_t *list_insert_tail(list_t *list, void *data) {
list_node_t *node;
node = list_alloc_node();
list_node_t *node = list_alloc_node();
node->data = data;
node->next = NULL;
@ -92,9 +86,7 @@ list_node_t *list_insert_tail(list_t *list, void *data) {
}
list_node_t *list_insert_after(list_t *list, list_node_t *after, void *data) {
list_node_t *node;
node = list_alloc_node();
list_node_t *node = list_alloc_node();
node->data = data;
node->next = after->next;
@ -158,6 +150,12 @@ void list_delete_tail(list_t *list) {
list_delete_node(list, list->tail);
}
void list_delete(list_t *list, const void *data) {
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
if(node->data == data)
list_delete_node(list, node);
}
/* Head/tail lookup */
void *list_get_head(list_t *list) {
@ -177,12 +175,8 @@ void *list_get_tail(list_t *list) {
/* Fast list deletion */
void list_delete_list(list_t *list) {
list_node_t *node, *next;
for(node = list->head; node; node = next) {
next = node->next;
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
list_free_node(list, node);
}
list_free(list);
}
@ -190,20 +184,12 @@ void list_delete_list(list_t *list) {
/* Traversing */
void list_foreach_node(list_t *list, list_action_node_t action) {
list_node_t *node, *next;
for(node = list->head; node; node = next) {
next = node->next;
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
action(node);
}
}
void list_foreach(list_t *list, list_action_t action) {
list_node_t *node, *next;
for(node = list->head; node; node = next) {
next = node->next;
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
if(node->data)
action(node->data);
}
}

View file

@ -1,7 +1,7 @@
/*
list.h -- header file for list.c
Copyright (C) 2000-2005 Ivo Timmermans
2000-2006 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
it under the terms of the GNU General Public License as published by
@ -57,6 +57,8 @@ extern list_node_t *list_insert_tail(list_t *, void *);
extern list_node_t *list_insert_after(list_t *, list_node_t *, void *);
extern list_node_t *list_insert_before(list_t *, list_node_t *, void *);
extern void list_delete(list_t *, const void *);
extern void list_unlink_node(list_t *, list_node_t *);
extern void list_delete_node(list_t *, list_node_t *);
@ -77,4 +79,6 @@ extern void list_delete_list(list_t *);
extern void list_foreach(list_t *, list_action_t);
extern void list_foreach_node(list_t *, list_action_node_t);
#define list_each(type, item, list) (type *item = (type *)1; item; item = NULL) for(list_node_t *node = (list)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
#endif /* __TINC_LIST_H__ */

View file

@ -1,6 +1,6 @@
/*
logger.c -- logging code
Copyright (C) 2004-2006 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2004-2012 Guus Sliepen <guus@tinc-vpn.org>
2004-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -21,7 +21,11 @@
#include "system.h"
#include "conf.h"
#include "meta.h"
#include "logger.h"
#include "connection.h"
#include "control_common.h"
#include "sptps.h"
debug_t debug_level = DEBUG_NOTHING;
static logmode_t logmode = LOGMODE_STDERR;
@ -32,6 +36,89 @@ static FILE *logfile = NULL;
static HANDLE loghandle = NULL;
#endif
static const char *logident = NULL;
bool logcontrol = false;
static void real_logger(int level, int priority, const char *message) {
char timestr[32] = "";
time_t now;
static bool suppress = false;
// Bail out early if there is nothing to do.
if(suppress)
return;
if(!logcontrol && (level > debug_level || logmode == LOGMODE_NULL))
return;
if(level <= debug_level) {
switch(logmode) {
case LOGMODE_STDERR:
fprintf(stderr, "%s\n", message);
fflush(stderr);
break;
case LOGMODE_FILE:
now = time(NULL);
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
fflush(logfile);
break;
case LOGMODE_SYSLOG:
#ifdef HAVE_MINGW
{
const char *messages[] = {message};
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
}
#else
#ifdef HAVE_SYSLOG_H
syslog(priority, "%s", message);
#endif
#endif
break;
case LOGMODE_NULL:
break;
}
}
if(logcontrol) {
suppress = true;
logcontrol = false;
for list_each(connection_t, c, connection_list) {
if(!c->status.log)
continue;
logcontrol = true;
if(level > (c->outcompression >= 0 ? c->outcompression : debug_level))
continue;
int len = strlen(message);
if(send_request(c, "%d %d %d", CONTROL, REQ_LOG, len))
send_meta(c, message, len);
}
suppress = false;
}
}
void logger(int level, int priority, const char *format, ...) {
va_list ap;
char message[1024] = "";
va_start(ap, format);
int len = vsnprintf(message, sizeof message, format, ap);
va_end(ap);
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
message[len - 1] = 0;
real_logger(level, priority, message);
}
static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) {
char message[1024] = "";
int len = vsnprintf(message, sizeof message, format, ap);
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
message[len - 1] = 0;
real_logger(DEBUG_ALWAYS, LOG_ERR, message);
}
void openlogger(const char *ident, logmode_t mode) {
logident = ident;
@ -66,6 +153,11 @@ void openlogger(const char *ident, logmode_t mode) {
case LOGMODE_NULL:
break;
}
if(logmode != LOGMODE_NULL)
sptps_log = sptps_logger;
else
sptps_log = sptps_log_quiet;
}
void reopenlogger() {
@ -75,62 +167,13 @@ void reopenlogger() {
fflush(logfile);
FILE *newfile = fopen(logfilename, "a");
if(!newfile) {
logger(LOG_ERR, "Unable to reopen log file %s: %s\n", logfilename, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
return;
}
fclose(logfile);
logfile = newfile;
}
void logger(int priority, const char *format, ...) {
va_list ap;
char timestr[32] = "";
time_t now;
va_start(ap, format);
switch(logmode) {
case LOGMODE_STDERR:
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
fflush(stderr);
break;
case LOGMODE_FILE:
now = time(NULL);
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid);
vfprintf(logfile, format, ap);
fprintf(logfile, "\n");
fflush(logfile);
break;
case LOGMODE_SYSLOG:
#ifdef HAVE_MINGW
{
char message[4096];
const char *messages[] = {message};
vsnprintf(message, sizeof message, format, ap);
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
}
#else
#ifdef HAVE_SYSLOG_H
#ifdef HAVE_VSYSLOG
vsyslog(priority, format, ap);
#else
{
char message[4096];
vsnprintf(message, sizeof message, format, ap);
syslog(priority, "%s", message);
}
#endif
break;
#endif
#endif
case LOGMODE_NULL:
break;
}
va_end(ap);
}
void closelogger(void) {
switch(logmode) {

View file

@ -1,3 +1,23 @@
/*
logger.h -- header file for logger.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-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.
*/
#ifndef __TINC_LOGGER_H__
#define __TINC_LOGGER_H__
@ -46,11 +66,10 @@ enum {
#endif
extern debug_t debug_level;
extern bool logcontrol;
extern void openlogger(const char *, logmode_t);
extern void reopenlogger(void);
extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
extern void logger(int, int, const char *, ...) __attribute__ ((__format__(printf, 3, 4)));
extern void closelogger(void);
#define ifdebug(l) if(debug_level >= DEBUG_##l)
#endif /* __TINC_LOGGER_H__ */

View file

@ -1,6 +1,6 @@
/*
meta.c -- handle the meta communication
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
2006 Scott Lamb <slamb@slamb.org>
@ -21,7 +21,6 @@
#include "system.h"
#include "splay_tree.h"
#include "cipher.h"
#include "connection.h"
#include "logger.h"
@ -31,21 +30,38 @@
#include "utils.h"
#include "xalloc.h"
bool send_meta(connection_t *c, const char *buffer, int length) {
bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t length) {
connection_t *c = handle;
if(!c) {
logger(LOG_ERR, "send_meta() called with NULL pointer!");
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta_sptps() called with NULL pointer!");
abort();
}
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
buffer_add(&c->outbuf, buffer, length);
event_add(&c->outevent, NULL);
return true;
}
bool send_meta(connection_t *c, const char *buffer, int length) {
if(!c) {
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
abort();
}
logger(DEBUG_META, LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
c->name, c->hostname);
if(c->protocol_minor >= 2)
return sptps_send_record(&c->sptps, 0, buffer, length);
/* Add our data to buffer */
if(c->status.encryptout) {
size_t outlen = length;
if(!cipher_encrypt(&c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
logger(LOG_ERR, "Error while encrypting metadata to %s (%s)",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)",
c->name, c->hostname);
return false;
}
@ -60,15 +76,47 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
}
void broadcast_meta(connection_t *from, const char *buffer, int length) {
splay_node_t *node;
connection_t *c;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
for list_each(connection_t, c, connection_list)
if(c != from && c->status.active)
send_meta(c, buffer, length);
}
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
connection_t *c = handle;
if(!c) {
logger(DEBUG_ALWAYS, LOG_ERR, "receive_meta_sptps() called with NULL pointer!");
abort();
}
if(type == SPTPS_HANDSHAKE) {
if(c->allow_request == ACK)
return send_ack(c);
else
return true;
}
if(!data)
return true;
/* Are we receiving a TCPpacket? */
if(c->tcplen) {
if(length != c->tcplen)
return false;
receive_tcppacket(c, data, length);
c->tcplen = 0;
return true;
}
/* Change newline to null byte, just like non-SPTPS requests */
if(data[length - 1] == '\n')
((char *)data)[length - 1] = 0;
/* Otherwise we are waiting for a request */
return receive_request(c, data);
}
bool receive_meta(connection_t *c) {
@ -88,7 +136,7 @@ bool receive_meta(connection_t *c) {
buffer_compact(&c->inbuf, MAXBUFSIZE);
if(sizeof inbuf <= c->inbuf.len) {
logger(LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
logger(DEBUG_ALWAYS, LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
return false;
}
@ -96,17 +144,20 @@ bool receive_meta(connection_t *c) {
if(inlen <= 0) {
if(!inlen || !errno) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)",
c->name, c->hostname);
} else if(sockwouldblock(sockerrno))
return true;
else
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Metadata socket read error for %s (%s): %s",
c->name, c->hostname, sockstrerror(sockerrno));
return false;
}
do {
if(c->protocol_minor >= 2)
return sptps_receive_data(&c->sptps, bufp, inlen);
if(!c->status.decryptin) {
endp = memchr(bufp, '\n', inlen);
if(endp)
@ -120,10 +171,9 @@ bool receive_meta(connection_t *c) {
bufp = endp;
} else {
size_t outlen = inlen;
ifdebug(META) logger(LOG_DEBUG, "Received encrypted %d bytes", inlen);
if(!cipher_decrypt(&c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) {
logger(LOG_ERR, "Error while decrypting metadata from %s (%s)",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
c->name, c->hostname);
return false;
}
@ -137,6 +187,14 @@ bool receive_meta(connection_t *c) {
if(c->tcplen) {
char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
if(tcpbuffer) {
if(proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
if(tcpbuffer[0] == 0 && tcpbuffer[1] == 0x5a) {
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
} else {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected");
return false;
}
} else
receive_tcppacket(c, tcpbuffer, c->tcplen);
c->tcplen = 0;
continue;

View file

@ -1,6 +1,6 @@
/*
meta.h -- header for meta.c
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -24,6 +24,8 @@
#include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int);
extern bool send_meta_sptps(void *, uint8_t, const char *, size_t);
extern bool receive_meta_sptps(void *, uint8_t, const char *, uint16_t);
extern void broadcast_meta(struct connection_t *, const char *, int);
extern bool receive_meta(struct connection_t *);

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Windows tap driver in a MinGW environment
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
2002-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
@ -50,7 +50,7 @@ static DWORD WINAPI tapreader(void *bla) {
OVERLAPPED overlapped;
vpn_packet_t packet;
logger(LOG_DEBUG, "Tap reader running");
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader running");
/* Read from tap device and send to parent */
@ -69,7 +69,7 @@ static DWORD WINAPI tapreader(void *bla) {
if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
continue;
} else {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return -1;
}
@ -83,7 +83,7 @@ static DWORD WINAPI tapreader(void *bla) {
}
}
bool setup_device(void) {
static bool setup_device(void) {
HKEY key, key2;
int i;
@ -105,7 +105,7 @@ bool setup_device(void) {
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false;
}
@ -156,7 +156,7 @@ bool setup_device(void) {
RegCloseKey(key);
if(!found) {
logger(LOG_ERR, "No Windows tap device found!");
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
return false;
}
@ -174,14 +174,14 @@ bool setup_device(void) {
}
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
return false;
}
/* 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)) {
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
return false;
}
@ -194,7 +194,7 @@ bool setup_device(void) {
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
if(!thread) {
logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
return false;
}
@ -205,31 +205,31 @@ bool setup_device(void) {
device_info = "Windows tap device";
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
void close_device(void) {
static void close_device(void) {
CloseHandle(device_handle);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
static bool read_packet(vpn_packet_t *packet) {
return false;
}
bool write_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
long outlen;
OVERLAPPED overlapped = {0};
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
@ -238,8 +238,16 @@ bool write_packet(vpn_packet_t *packet) {
return true;
}
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);
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t os_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};

235
src/multicast_device.c Normal file
View file

@ -0,0 +1,235 @@
/*
device.c -- multicast socket
Copyright (C) 2002-2005 Ivo Timmermans,
2002-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 "conf.h"
#include "device.h"
#include "net.h"
#include "logger.h"
#include "netutl.h"
#include "utils.h"
#include "route.h"
#include "xalloc.h"
static char *device_info;
static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0;
static struct addrinfo *ai = NULL;
static mac_t ignore_src = {{0}};
static bool setup_device(void) {
char *host = NULL;
char *port;
char *space;
int ttl = 1;
device_info = "multicast socket";
get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Device variable required for %s", device_info);
goto error;
}
host = xstrdup(device);
space = strchr(host, ' ');
if(!space) {
logger(DEBUG_ALWAYS, LOG_ERR, "Port number required for %s", device_info);
goto error;
}
*space++ = 0;
port = space;
space = strchr(port, ' ');
if(space) {
*space++ = 0;
ttl = atoi(space);
}
ai = str2addrinfo(host, port, SOCK_DGRAM);
if(!ai)
goto error;
device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
if(device_fd < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
goto error;
}
#ifdef FD_CLOEXEC
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
static const int one = 1;
setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one);
if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
goto error;
}
switch(ai->ai_family) {
#ifdef IP_ADD_MEMBERSHIP
case AF_INET: {
struct ip_mreq mreq;
struct sockaddr_in in;
memcpy(&in, ai->ai_addr, sizeof in);
mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
goto error;
}
#ifdef IP_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one);
#endif
#ifdef IP_MULTICAST_TTL
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof ttl);
#endif
} break;
#endif
#ifdef IPV6_JOIN_GROUP
case AF_INET6: {
struct ipv6_mreq mreq;
struct sockaddr_in6 in6;
memcpy(&in6, ai->ai_addr, sizeof in6);
memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr);
mreq.ipv6mr_interface = in6.sin6_scope_id;
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
goto error;
}
#ifdef IPV6_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one);
#endif
#ifdef IPV6_MULTICAST_HOPS
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof ttl);
#endif
} break;
#endif
default:
logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family);
goto error;
}
freeaddrinfo(ai);
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
error:
if(device_fd >= 0)
closesocket(device_fd);
if(ai)
freeaddrinfo(ai);
free(host);
return false;
}
static void close_device(void) {
close(device_fd);
free(device);
free(iface);
if(ai)
freeaddrinfo(ai);
}
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = recv(device_fd, packet->data, MTU, 0)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) {
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
packet->len = 0;
return true;
}
packet->len = lenin;
device_total_in += packet->len;
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
static bool write_packet(vpn_packet_t *packet) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(sendto(device_fd, packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
device_total_out += packet->len;
memcpy(&ignore_src, packet->data + 6, sizeof ignore_src);
return true;
}
static void dump_device_stats(void) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
}
const devops_t multicast_devops = {
.setup = setup_device,
.close = close_device,
.read = read_packet,
.write = write_packet,
.dump_stats = dump_device_stats,
};
#if 0
static bool not_supported(void) {
logger(DEBUG_ALWAYS, LOG_ERR, "Raw socket device not supported on this platform");
return false;
}
const devops_t multicast_devops = {
.setup = not_supported,
.close = NULL,
.read = NULL,
.write = NULL,
.dump_stats = NULL,
};
#endif

223
src/net.c
View file

@ -1,7 +1,7 @@
/*
net.c -- most of the network code
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2011 Loïc Grenié <loic.grenie@gmail.com>
@ -23,7 +23,6 @@
#include "system.h"
#include "utils.h"
#include "splay_tree.h"
#include "conf.h"
#include "connection.h"
#include "device.h"
@ -40,40 +39,28 @@
int contradicting_add_edge = 0;
int contradicting_del_edge = 0;
static int sleeptime = 10;
time_t last_config_check = 0;
/* Purge edges and subnets of unreachable nodes. Use carefully. */
void purge(void) {
splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
node_t *n;
edge_t *e;
subnet_t *s;
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes");
/* Remove all edges and subnets owned by unreachable nodes. */
for(nnode = node_tree->head; nnode; nnode = nnext) {
nnext = nnode->next;
n = nnode->data;
for splay_each(node_t, n, node_tree) {
if(!n->status.reachable) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
n->hostname);
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname);
for(snode = n->subnet_tree->head; snode; snode = snext) {
snext = snode->next;
s = snode->data;
send_del_subnet(broadcast, s);
for splay_each(subnet_t, s, n->subnet_tree) {
send_del_subnet(everyone, s);
if(!strictsubnets)
subnet_del(n, s);
}
for(enode = n->edge_tree->head; enode; enode = enext) {
enext = enode->next;
e = enode->data;
for splay_each(edge_t, e, n->edge_tree) {
if(!tunnelserver)
send_del_edge(broadcast, e);
send_del_edge(everyone, e);
edge_del(e);
}
}
@ -81,20 +68,13 @@ void purge(void) {
/* Check if anyone else claims to have an edge to an unreachable node. If not, delete node. */
for(nnode = node_tree->head; nnode; nnode = nnext) {
nnext = nnode->next;
n = nnode->data;
for splay_each(node_t, n, node_tree) {
if(!n->status.reachable) {
for(enode = edge_weight_tree->head; enode; enode = enext) {
enext = enode->next;
e = enode->data;
for splay_each(edge_t, e, edge_weight_tree)
if(e->to == n)
break;
}
return;
if(!enode && (!strictsubnets || !n->subnet_tree->head))
if(!strictsubnets || !n->subnet_tree->head)
/* in strictsubnets mode do not delete nodes with subnets */
node_del(n);
}
@ -103,25 +83,25 @@ void purge(void) {
/*
Terminate a connection:
- Close the socket
- Remove associated edge and tell other connections about it if report = true
- Mark it as inactive
- Remove the edge representing this connection
- Kill it with fire
- Check if we need to retry making an outgoing connection
- Deactivate the host
*/
void terminate_connection(connection_t *c, bool report) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
c->name, c->hostname);
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname);
c->status.active = false;
if(c->node)
if(c->node && c->node->connection == c)
c->node->connection = NULL;
if(c->edge) {
if(report && !tunnelserver)
send_del_edge(broadcast, c->edge);
send_del_edge(everyone, c->edge);
edge_del(c->edge);
c->edge = NULL;
/* Run MST and SSSP algorithms */
@ -134,18 +114,19 @@ void terminate_connection(connection_t *c, bool report) {
e = lookup_edge(c->node, myself);
if(e) {
if(!tunnelserver)
send_del_edge(broadcast, e);
send_del_edge(everyone, e);
edge_del(e);
}
}
}
outgoing_t *outgoing = c->outgoing;
connection_del(c);
/* Check if this was our outgoing connection */
if(c->outgoing)
retry_outgoing(c->outgoing);
connection_del(c);
if(outgoing)
do_outgoing_connection(outgoing);
}
/*
@ -157,42 +138,34 @@ void terminate_connection(connection_t *c, bool report) {
and close the connection.
*/
static void timeout_handler(int fd, short events, void *event) {
splay_node_t *node, *next;
connection_t *c;
time_t now = time(NULL);
for(node = connection_tree->head; node; node = next) {
next = node->next;
c = node->data;
for list_each(connection_t, c, connection_list) {
if(c->status.control)
continue;
if(c->last_ping_time + pingtimeout <= now) {
if(c->status.active) {
if(c->status.pinged) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
c->name, c->hostname, now - c->last_ping_time);
terminate_connection(c, true);
continue;
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now - c->last_ping_time);
} else if(c->last_ping_time + pinginterval <= now) {
send_ping(c);
}
continue;
} else {
if(c->status.connecting) {
ifdebug(CONNECTIONS)
logger(LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
c->status.connecting = false;
closesocket(c->socket);
do_outgoing_connection(c);
} else {
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
terminate_connection(c, false);
continue;
}
} else {
if(c->status.connecting)
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
else
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
}
terminate_connection(c, c->status.active);
}
}
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
usleep(sleeptime * 1000000LL);
sleeptime *= 2;
if(sleeptime < 0)
@ -222,11 +195,8 @@ void handle_meta_connection_data(int fd, short events, void *data) {
if(!result)
finish_connecting(c);
else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
"Error while connecting to %s (%s): %s",
c->name, c->hostname, sockstrerror(result));
closesocket(c->socket);
do_outgoing_connection(c);
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result));
terminate_connection(c, false);
return;
}
}
@ -238,27 +208,23 @@ void handle_meta_connection_data(int fd, short events, void *data) {
}
static void sigterm_handler(int signal, short events, void *data) {
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
event_loopexit(NULL);
}
static void sighup_handler(int signal, short events, void *data) {
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
reopenlogger();
reload_configuration();
}
static void sigalrm_handler(int signal, short events, void *data) {
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
retry();
}
int reload_configuration(void) {
connection_t *c;
splay_node_t *node, *next;
char *fname;
struct stat s;
static time_t last_config_check = 0;
/* Reread our own configuration file */
@ -266,85 +232,112 @@ int reload_configuration(void) {
init_configuration(&config_tree);
if(!read_server_config()) {
logger(LOG_ERR, "Unable to reread configuration file, exitting.");
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting.");
event_loopexit(NULL);
return EINVAL;
}
/* Close connections to hosts that have a changed or deleted host config file */
read_config_options(config_tree, NULL);
for(node = connection_tree->head; node; node = next) {
c = node->data;
next = node->next;
if(c->outgoing) {
free(c->outgoing->name);
if(c->outgoing->ai)
freeaddrinfo(c->outgoing->ai);
free(c->outgoing);
c->outgoing = NULL;
}
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
if(stat(fname, &s) || s.st_mtime > last_config_check)
terminate_connection(c, c->status.active);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
read_config_file(config_tree, fname);
free(fname);
}
last_config_check = time(NULL);
/* Parse some options that are allowed to be changed while tinc is running */
setup_myself_reloadable();
/* If StrictSubnet is set, expire deleted Subnets and read new ones in */
if(strictsubnets) {
subnet_t *subnet;
for(node = subnet_tree->head; node; node = node->next) {
subnet = node->data;
for splay_each(subnet_t, subnet, subnet_tree)
subnet->expires = 1;
}
load_all_subnets();
for(node = subnet_tree->head; node; node = next) {
next = node->next;
subnet = node->data;
for splay_each(subnet_t, subnet, subnet_tree) {
if(subnet->expires == 1) {
send_del_subnet(broadcast, subnet);
send_del_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, false);
subnet_del(subnet->owner, subnet);
} else if(subnet->expires == -1) {
subnet->expires = 0;
} else {
send_add_subnet(broadcast, subnet);
send_add_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, true);
}
}
} else { /* Only read our own subnets back in */
for splay_each(subnet_t, subnet, myself->subnet_tree)
if(!subnet->expires)
subnet->expires = 1;
config_t *cfg = lookup_config(config_tree, "Subnet");
while(cfg) {
subnet_t *subnet, *s2;
if(!get_config_subnet(cfg, &subnet))
continue;
if((s2 = lookup_subnet(myself, subnet))) {
if(s2->expires == 1)
s2->expires = 0;
free_subnet(subnet);
} else {
subnet_add(myself, subnet);
send_add_subnet(everyone, subnet);
subnet_update(myself, subnet, true);
}
cfg = lookup_config_next(config_tree, cfg);
}
for splay_each(subnet_t, subnet, myself->subnet_tree) {
if(subnet->expires == 1) {
send_del_subnet(everyone, subnet);
subnet_update(myself, subnet, false);
subnet_del(myself, subnet);
}
}
}
/* Try to make outgoing connections */
try_outgoing_connections();
/* Close connections to hosts that have a changed or deleted host config file */
for list_each(connection_t, c, connection_list) {
if(c->status.control)
continue;
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
struct stat s;
if(stat(fname, &s) || s.st_mtime > last_config_check) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Host config file of %s has been changed", c->name);
terminate_connection(c, c->status.active);
}
free(fname);
}
last_config_check = time(NULL);
return 0;
}
void retry(void) {
connection_t *c;
splay_node_t *node;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
for list_each(connection_t, c, connection_list) {
if(c->outgoing && !c->node) {
if(timeout_initialized(&c->outgoing->ev))
event_del(&c->outgoing->ev);
if(c->status.connecting)
close(c->socket);
c->outgoing->timeout = 0;
do_outgoing_connection(c);
terminate_connection(c, c->status.active);
}
}
}
@ -375,7 +368,7 @@ int main_loop(void) {
#endif
if(event_loop(0) < 0) {
logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
return 1;
}

View file

@ -1,7 +1,7 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2009 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
it under the terms of the GNU General Public License as published by
@ -31,8 +31,11 @@
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#endif
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + padding + HMAC + compressor overhead */
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
/* MAXBUFSIZE is the maximum size of a request: enough for a MAXSIZEd packet or a 8192 bits RSA key */
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)
#define MAXSOCKETS 8 /* Probably overkill... */
@ -83,6 +86,18 @@ typedef struct vpn_packet_t {
uint8_t data[MAXSIZE];
} vpn_packet_t;
/* Packet types when using SPTPS */
#define PKT_COMPRESSED 1
#define PKT_MAC 2
#define PKT_PROBE 4
typedef enum packet_type_t {
PACKET_NORMAL,
PACKET_COMPRESSED,
PACKET_PROBE
} packet_type_t;
typedef struct listen_socket_t {
struct event ev_tcp;
struct event ev_udp;
@ -97,6 +112,7 @@ typedef struct listen_socket_t {
typedef struct outgoing_t {
char *name;
int timeout;
splay_tree_t *config_tree;
struct config_t *cfg;
struct addrinfo *ai;
struct addrinfo *aip;
@ -109,6 +125,7 @@ extern int maxoutbufsize;
extern int seconds_till_retry;
extern int addressfamily;
extern unsigned replaywin;
extern bool localdiscovery;
extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets;
@ -119,6 +136,24 @@ extern bool do_prune;
extern char *myport;
extern int contradicting_add_edge;
extern int contradicting_del_edge;
extern time_t last_config_check;
extern char *proxyhost;
extern char *proxyport;
extern char *proxyuser;
extern char *proxypass;
typedef enum proxytype_t {
PROXY_NONE = 0,
PROXY_SOCKS4,
PROXY_SOCKS4A,
PROXY_SOCKS5,
PROXY_HTTP,
PROXY_EXEC,
} proxytype_t;
extern proxytype_t proxytype;
extern char *scriptinterpreter;
extern char *scriptextension;
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
#include "connection.h"
@ -127,20 +162,23 @@ extern int contradicting_del_edge;
extern void retry_outgoing(outgoing_t *);
extern void handle_incoming_vpn_data(int, short, void *);
extern void finish_connecting(struct connection_t *);
extern bool do_outgoing_connection(struct connection_t *);
extern bool do_outgoing_connection(struct outgoing_t *);
extern void handle_new_meta_connection(int, short, void *);
extern int setup_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_socket(const sockaddr_t *);
extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
extern bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len);
extern void send_packet(struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, const char *, int);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
extern char *get_name(void);
extern bool setup_myself_reloadable(void);
extern bool setup_network(void);
extern void setup_outgoing_connection(struct outgoing_t *);
extern void try_outgoing_connections(void);
extern void close_network_connections(void);
extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool);
extern void flush_queue(struct node_t *);
extern bool node_read_ecdsa_public_key(struct node_t *);
extern bool read_ecdsa_public_key(struct connection_t *);
extern bool read_rsa_public_key(struct connection_t *);

View file

@ -1,7 +1,7 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2010 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com>
@ -36,7 +36,6 @@
#include LZO1X_H
#endif
#include "splay_tree.h"
#include "cipher.h"
#include "conf.h"
#include "connection.h"
@ -62,24 +61,30 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
static void send_udppacket(node_t *, vpn_packet_t *);
unsigned replaywin = 16;
bool localdiscovery = false;
#define MAX_SEQNO 1073741824
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
// mtuprobes == 31: sleep pinginterval seconds
// mtuprobes == 32: send 1 burst, sleep pingtimeout second
// mtuprobes == 33: no response from other side, restart PMTU discovery process
/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
mtuprobes == 31: sleep pinginterval seconds
mtuprobes == 32: send 1 burst, sleep pingtimeout second
mtuprobes == 33: no response from other side, restart PMTU discovery process
Probes are sent in batches of three, with random sizes between the lower and
upper boundaries for the MTU thus far discovered.
In case local discovery is enabled, a fourth packet is added to each batch,
which will be broadcast to the local network.
*/
static void send_mtu_probe_handler(int fd, short events, void *data) {
node_t *n = data;
vpn_packet_t packet;
int len, i;
int timeout = 1;
n->mtuprobes++;
if(!n->status.reachable || !n->status.validkey) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
n->mtuprobes = 0;
return;
}
@ -91,14 +96,15 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
goto end;
}
ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
n->status.udp_confirmed = false;
n->mtuprobes = 1;
n->minmtu = 0;
n->maxmtu = MTU;
}
if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) {
ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
n->mtuprobes = 31;
}
@ -108,7 +114,7 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
else
n->maxmtu = n->minmtu;
n->mtu = n->minmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
logger(DEBUG_TRAFFIC, LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
n->mtuprobes = 31;
}
@ -119,7 +125,9 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
timeout = pingtimeout;
}
for(i = 0; i < 3; i++) {
for(int i = 0; i < 3 + localdiscovery; i++) {
int len;
if(n->maxmtu <= n->minmtu)
len = n->maxmtu;
else
@ -128,12 +136,16 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
if(len < 64)
len = 64;
vpn_packet_t packet;
memset(packet.data, 0, 14);
randomize(packet.data + 14, len - 14);
packet.len = len;
if(i >= 3 && n->mtuprobes <= 10)
packet.priority = -1;
else
packet.priority = 0;
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
send_udppacket(n, &packet);
}
@ -149,12 +161,14 @@ void send_mtu_probe(node_t *n) {
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
if(!packet->data[0]) {
packet->data[0] = 1;
send_udppacket(n, packet);
} else {
n->status.udp_confirmed = true;
if(n->mtuprobes > 30) {
if(n->minmtu)
n->mtuprobes = 30;
@ -231,7 +245,7 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
/* VPN packet I/O */
static void receive_packet(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
packet->len, n->name, n->hostname);
n->in_packets++;
@ -241,6 +255,9 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) {
}
static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
if(n->status.sptps)
return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
return false;
@ -254,8 +271,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t *outpkt = pkt[0];
size_t outlen;
if(n->status.sptps) {
sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
return;
}
if(!cipher_active(&n->incipher)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
n->name, n->hostname);
return;
}
@ -263,7 +285,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
/* Check packet length */
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname);
return;
}
@ -273,7 +295,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(digest_active(&n->indigest)) {
inpkt->len -= n->indigest.maclength;
if(!digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
return;
}
}
@ -284,7 +306,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
outlen = MAXSIZE;
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
return;
}
@ -301,16 +323,16 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(inpkt->seqno != n->received_seqno + 1) {
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) {
logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
return;
}
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
} else if (inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
return;
}
@ -338,7 +360,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
outpkt = pkt[nextpkt++];
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname);
return;
}
@ -369,6 +391,53 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
receive_packet(c->node, &outpkt);
}
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
if(!n->status.validkey) {
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
if(!n->status.waitingforkey)
send_req_key(n);
else if(n->last_req_key + 10 < time(NULL)) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
send_req_key(n);
}
return;
}
uint8_t type = 0;
int offset = 0;
if(!(origpkt->data[12] | origpkt->data[13])) {
sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
return;
}
if(routing_mode == RMODE_ROUTER)
offset = 14;
else
type = PKT_MAC;
if(origpkt->len < offset)
return;
vpn_packet_t outpkt;
if(n->outcompression) {
int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
if(len < 0) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
} else if(len < origpkt->len - offset) {
outpkt.len = len + offset;
origpkt = &outpkt;
type |= PKT_COMPRESSED;
}
}
sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
return;
}
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
@ -379,21 +448,23 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
size_t outlen;
#if defined(SOL_IP) && defined(IP_TOS)
static int priority = 0;
int origpriority = origpkt->priority;
#endif
int sock;
int origpriority = origpkt->priority;
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
return;
}
if(n->status.sptps)
return send_sptps_packet(n, origpkt);
/* Make sure we have a valid key */
if(!n->status.validkey) {
time_t now = time(NULL);
ifdebug(TRAFFIC) logger(LOG_INFO,
logger(DEBUG_TRAFFIC, LOG_INFO,
"No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname);
@ -408,7 +479,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
}
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
ifdebug(TRAFFIC) logger(LOG_INFO,
logger(DEBUG_TRAFFIC, LOG_INFO,
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
@ -426,7 +497,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
outpkt = pkt[nextpkt++];
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)",
n->name, n->hostname);
return;
}
@ -446,7 +517,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
outlen = MAXSIZE;
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
@ -461,41 +532,221 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
inpkt->len += digest_length(&n->outdigest);
}
/* Send the packet */
sockaddr_t *sa;
int sock;
/* Overloaded use of priority field: -1 means local broadcast */
if(origpriority == -1 && n->prevedge) {
sockaddr_t broadcast;
broadcast.in.sin_family = AF_INET;
broadcast.in.sin_addr.s_addr = -1;
broadcast.in.sin_port = n->prevedge->address.in.sin_port;
sa = &broadcast;
sock = 0;
} else {
if(origpriority == -1)
origpriority = 0;
if(n->status.udp_confirmed) {
/* Address of this node is confirmed, so use it. */
sa = &n->address;
sock = n->sock;
} else {
/* Otherwise, go through the list of known addresses of
this node. The first address we try is always the
one in n->address; that could be set to the node's
reflexive UDP address discovered during key
exchange. The other known addresses are those found
in edges to this node. */
static unsigned int i;
int j = 0;
edge_t *candidate = NULL;
if(i) {
for splay_each(edge_t, e, edge_weight_tree) {
if(e->to != n)
continue;
j++;
if(!candidate || j == i)
candidate = e;
}
}
if(!candidate) {
sa = &n->address;
sock = n->sock;
} else {
sa = &candidate->address;
sock = rand() % listen_sockets;
}
if(i++)
if(i > j)
i = 0;
}
}
/* Determine which socket we have to use */
if(sa->sa.sa_family != listen_socket[sock].sa.sa.sa_family)
for(sock = 0; sock < listen_sockets; sock++)
if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family)
if(sa->sa.sa_family == listen_socket[sock].sa.sa.sa_family)
break;
if(sock >= listen_sockets)
sock = 0; /* If none is available, just use the first and hope for the best. */
sock = 0;
/* Send the packet */
if(!n->status.udp_confirmed)
n->sock = sock;
#if defined(SOL_IP) && defined(IP_TOS)
if(priorityinheritance && origpriority != priority
&& listen_socket[sock].sa.sa.sa_family == AF_INET) {
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority)) /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
#endif
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
socklen_t sl = SALEN(n->address.sa);
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, sl) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
if(n->mtu >= origlen)
n->mtu = origlen - 1;
} else
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
}
end:
origpkt->len = origlen;
}
bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
node_t *to = handle;
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, or this packet is larger than the MTU. */
if(type >= SPTPS_HANDSHAKE || ((myself->options | to->options) & OPTION_TCPONLY) || (type != PKT_PROBE && len > to->minmtu)) {
char buf[len * 4 / 3 + 5];
b64encode(data, buf, len);
/* If no valid key is known yet, send the packets using ANS_KEY requests,
to ensure we get to learn the reflexive UDP address. */
if(!to->status.validkey)
return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, myself->name, to->name, buf, myself->incompression);
else
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_SPTPS, buf);
}
/* Otherwise, send the packet via UDP */
struct sockaddr *sa;
socklen_t sl;
int sock;
sa = &(to->address.sa);
sl = SALEN(to->address.sa);
sock = to->sock;
if(sendto(listen_socket[sock].udp, data, len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(to->maxmtu >= len)
to->maxmtu = len - 1;
if(to->mtu >= len)
to->mtu = len - 1;
} else {
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", to->name, to->hostname, sockstrerror(sockerrno));
return false;
}
}
return true;
}
bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len) {
node_t *from = handle;
if(type == SPTPS_HANDSHAKE) {
if(!from->status.validkey) {
from->status.validkey = true;
from->status.waitingforkey = false;
logger(DEBUG_META, LOG_INFO, "SPTPS key exchange with %s (%s) succesful", from->name, from->hostname);
}
return true;
}
if(len > MTU) {
logger(DEBUG_ALWAYS, LOG_ERR, "Packet from %s (%s) larger than maximum supported size (%d > %d)", from->name, from->hostname, len, MTU);
return false;
}
vpn_packet_t inpkt;
if(type == PKT_PROBE) {
inpkt.len = len;
memcpy(inpkt.data, data, len);
mtu_probe_h(from, &inpkt, len);
return true;
}
if(type & ~(PKT_COMPRESSED | PKT_MAC)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unexpected SPTPS record type %d len %d from %s (%s)", type, len, from->name, from->hostname);
return false;
}
/* Check if we have the headers we need */
if(routing_mode != RMODE_ROUTER && !(type & PKT_MAC)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Received packet from %s (%s) without MAC header (maybe Mode is not set correctly)", from->name, from->hostname);
return false;
} else if(routing_mode == RMODE_ROUTER && (type & PKT_MAC)) {
logger(DEBUG_TRAFFIC, LOG_WARNING, "Received packet from %s (%s) with MAC header (maybe Mode is not set correctly)", from->name, from->hostname);
}
int offset = (type & PKT_MAC) ? 0 : 14;
if(type & PKT_COMPRESSED) {
len = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
if(len < 0) {
return false;
} else {
inpkt.len = len + offset;
}
if(inpkt.len > MAXSIZE)
abort();
} else {
memcpy(inpkt.data + offset, data, len);
inpkt.len = len + offset;
}
/* Generate the Ethernet packet type if necessary */
if(offset) {
switch(inpkt.data[14] >> 4) {
case 4:
inpkt.data[12] = 0x08;
inpkt.data[13] = 0x00;
break;
case 6:
inpkt.data[12] = 0x86;
inpkt.data[13] = 0xDD;
break;
default:
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown IP version %d while reading packet from %s (%s)",
inpkt.data[14] >> 4, from->name, from->hostname);
return false;
}
}
receive_packet(from, &inpkt);
return true;
}
/*
send a packet to the given vpn ip.
*/
@ -507,15 +758,15 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
memcpy(packet->data, mymac.x, ETH_ALEN);
n->out_packets++;
n->out_bytes += packet->len;
write_packet(packet);
devops.write(packet);
return;
}
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
logger(DEBUG_TRAFFIC, LOG_ERR, "Sending packet of %d bytes to %s (%s)",
packet->len, n->name, n->hostname);
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
logger(DEBUG_TRAFFIC, LOG_INFO, "Node %s (%s) is not reachable",
n->name, n->hostname);
return;
}
@ -523,10 +774,15 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
n->out_packets++;
n->out_bytes += packet->len;
if(n->status.sptps) {
send_sptps_packet(n, packet);
return;
}
via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
if(via != n)
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet to %s via %s (%s)",
n->name, via->name, n->via->hostname);
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
@ -539,46 +795,53 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
/* Broadcast a packet using the minimum spanning tree */
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
splay_node_t *node;
connection_t *c;
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
if(from != myself) {
// Always give ourself a copy of the packet.
if(from != myself)
send_packet(myself, packet);
// In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops.
if(tunnelserver)
if(tunnelserver || broadcast_mode == BMODE_NONE)
return;
}
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
logger(DEBUG_TRAFFIC, LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
switch(broadcast_mode) {
// In MST mode, broadcast packets travel via the Minimum Spanning Tree.
// This guarantees all nodes receive the broadcast packet, and
// usually distributes the sending of broadcast packets over all nodes.
case BMODE_MST:
for list_each(connection_t, c, connection_list)
if(c->status.active && c->status.mst && c != from->nexthop->connection)
send_packet(c->node, packet);
break;
// In direct mode, we send copies to each node we know of.
// However, this only reaches nodes that can be reached in a single hop.
// We don't have enough information to forward broadcast packets in this case.
case BMODE_DIRECT:
if(from != myself)
break;
for splay_each(node_t, n, node_tree)
if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
send_packet(n, packet);
break;
default:
break;
}
}
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
splay_node_t *node;
edge_t *e;
node_t *n = NULL;
bool hard = false;
static time_t last_hard_try = 0;
time_t now = time(NULL);
if(last_hard_try == now)
return NULL;
else
last_hard_try = now;
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
if(e->to == myself)
for splay_each(edge_t, e, edge_weight_tree) {
if(!e->to->status.reachable || e->to == myself)
continue;
if(sockaddrcmp_noport(from, &e->address)) {
@ -597,13 +860,14 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
if(hard)
last_hard_try = now;
last_hard_try = now;
return n;
}
void handle_incoming_vpn_data(int sock, short events, void *data) {
vpn_packet_t pkt;
char *hostname;
sockaddr_t from;
sockaddr_t from = {{0}};
socklen_t fromlen = sizeof from;
node_t *n;
int len;
@ -612,7 +876,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
return;
}
@ -626,9 +890,9 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
n = try_harder(&from, &pkt);
if(n)
update_node_udp(n, &from);
else ifdebug(PROTOCOL) {
else if(debug_level >= DEBUG_PROTOCOL) {
hostname = sockaddr2hostname(&from);
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
return;
}
@ -636,6 +900,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
return;
}
n->sock = (intptr_t)data;
receive_udppacket(n, &pkt);
}
@ -644,7 +910,7 @@ void handle_device_data(int sock, short events, void *data) {
packet.priority = 0;
if(read_packet(&packet)) {
if(devops.read(&packet)) {
myself->in_packets++;
myself->in_bytes += packet.len;
route(myself, &packet);

View file

@ -1,7 +1,7 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com>
@ -22,7 +22,6 @@
#include "system.h"
#include "splay_tree.h"
#include "cipher.h"
#include "conf.h"
#include "connection.h"
@ -44,6 +43,16 @@
char *myport;
static struct event device_ev;
devops_t devops;
char *proxyhost;
char *proxyport;
char *proxyuser;
char *proxypass;
proxytype_t proxytype;
char *scriptinterpreter;
char *scriptextension;
bool node_read_ecdsa_public_key(node_t *n) {
if(ecdsa_active(&n->ecdsa))
@ -51,14 +60,14 @@ bool node_read_ecdsa_public_key(node_t *n) {
splay_tree_t *config_tree;
FILE *fp;
char *fname;
char *pubname = NULL, *hcfname = NULL;
char *p;
bool result = false;
xasprintf(&fname, "%s/hosts/%s", confbase, n->name);
xasprintf(&hcfname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
init_configuration(&config_tree);
if(!read_config_file(config_tree, fname))
if(!read_config_file(config_tree, hcfname))
goto exit;
/* First, check for simple ECDSAPublicKey statement */
@ -71,15 +80,13 @@ bool node_read_ecdsa_public_key(node_t *n) {
/* Else, check for ECDSAPublicKeyFile statement and read it */
free(fname);
if(!get_config_string(lookup_config(config_tree, "ECDSAPublicKeyFile"), &pubname))
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
if(!get_config_string(lookup_config(config_tree, "ECDSAPublicKeyFile"), &fname))
xasprintf(&fname, "%s/hosts/%s", confbase, n->name);
fp = fopen(fname, "r");
fp = fopen(pubname, "r");
if(!fp) {
logger(LOG_ERR, "Error reading ECDSA public key file `%s': %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s", pubname, strerror(errno));
goto exit;
}
@ -88,7 +95,8 @@ bool node_read_ecdsa_public_key(node_t *n) {
exit:
exit_configuration(&config_tree);
free(fname);
free(hcfname);
free(pubname);
return result;
}
@ -109,12 +117,12 @@ bool read_ecdsa_public_key(connection_t *c) {
/* Else, check for ECDSAPublicKeyFile statement and read it */
if(!get_config_string(lookup_config(c->config_tree, "ECDSAPublicKeyFile"), &fname))
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, "Error reading ECDSA public key file `%s': %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s",
fname, strerror(errno));
free(fname);
return false;
@ -124,7 +132,7 @@ bool read_ecdsa_public_key(connection_t *c) {
fclose(fp);
if(!result)
logger(LOG_ERR, "Reading ECDSA public key file `%s' failed: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing ECDSA public key file `%s' failed.", fname);
free(fname);
return result;
}
@ -146,13 +154,12 @@ bool read_rsa_public_key(connection_t *c) {
/* Else, check for PublicKeyFile statement and read it */
if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
free(fname);
return false;
}
@ -161,7 +168,7 @@ bool read_rsa_public_key(connection_t *c) {
fclose(fp);
if(!result)
logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
free(fname);
return result;
}
@ -174,13 +181,12 @@ static bool read_ecdsa_private_key(void) {
/* Check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "ECDSAPrivateKeyFile"), &fname))
xasprintf(&fname, "%s/ecdsa_key.priv", confbase);
xasprintf(&fname, "%s" SLASH "ecdsa_key.priv", confbase);
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s",
fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
free(fname);
return false;
}
@ -189,20 +195,20 @@ static bool read_ecdsa_private_key(void) {
struct stat s;
if(fstat(fileno(fp), &s)) {
logger(LOG_ERR, "Could not stat ECDSA private key file `%s': %s'", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat ECDSA private key file `%s': %s'", fname, strerror(errno));
free(fname);
return false;
}
if(s.st_mode & ~0100700)
logger(LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
#endif
result = ecdsa_read_pem_private_key(&myself->connection->ecdsa, fp);
fclose(fp);
if(!result)
logger(LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
free(fname);
return result;
}
@ -217,25 +223,25 @@ static bool read_rsa_private_key(void) {
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
logger(LOG_ERR, "PrivateKey used but no PublicKey found!");
logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
free(d);
return false;
}
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
free(n);
free(d);
return true;
return result;
}
/* Else, check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
xasprintf(&fname, "%s/rsa_key.priv", confbase);
xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, "Error reading RSA private key file `%s': %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
fname, strerror(errno));
free(fname);
return false;
@ -245,20 +251,20 @@ static bool read_rsa_private_key(void) {
struct stat s;
if(fstat(fileno(fp), &s)) {
logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
free(fname);
return false;
}
if(s.st_mode & ~0100700)
logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
#endif
result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
fclose(fp);
if(!result)
logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
free(fname);
return result;
}
@ -271,7 +277,7 @@ static void keyexpire_handler(int fd, short events, void *data) {
void regenerate_key(void) {
if(timeout_initialized(&keyexpire_event)) {
ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
event_del(&keyexpire_event);
send_key_changed();
} else {
@ -288,17 +294,11 @@ void load_all_subnets(void) {
DIR *dir;
struct dirent *ent;
char *dname;
char *fname;
splay_tree_t *config_tree;
config_t *cfg;
subnet_t *s, *s2;
node_t *n;
bool result;
xasprintf(&dname, "%s/hosts", confbase);
xasprintf(&dname, "%s" SLASH "hosts", confbase);
dir = opendir(dname);
if(!dir) {
logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
free(dname);
return;
}
@ -307,18 +307,20 @@ void load_all_subnets(void) {
if(!check_id(ent->d_name))
continue;
n = lookup_node(ent->d_name);
node_t *n = lookup_node(ent->d_name);
#ifdef _DIRENT_HAVE_D_TYPE
//if(ent->d_type != DT_REG)
// continue;
#endif
xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
char *fname;
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
splay_tree_t *config_tree;
init_configuration(&config_tree);
result = read_config_file(config_tree, fname);
read_config_options(config_tree, ent->d_name);
read_config_file(config_tree, fname);
free(fname);
if(!result)
continue;
if(!n) {
n = new_node();
@ -326,7 +328,9 @@ void load_all_subnets(void) {
node_add(n);
}
for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
subnet_t *s, *s2;
if(!get_config_subnet(cfg, &s))
continue;
@ -343,84 +347,127 @@ void load_all_subnets(void) {
closedir(dir);
}
/*
Configure node_t myself and set up the local sockets (listen only)
*/
static bool setup_myself(void) {
config_t *cfg;
subnet_t *subnet;
char *name, *hostname, *mode, *afname, *cipher, *digest;
char *fname = NULL;
char *address = NULL;
char *envp[5];
struct addrinfo *ai, *aip, hint = {0};
bool choice;
int i, err;
int replaywin_int;
char *get_name(void) {
char *name = NULL;
myself = new_node();
myself->connection = new_connection();
get_config_string(lookup_config(config_tree, "Name"), &name);
myself->hostname = xstrdup("MYSELF");
myself->connection->hostname = xstrdup("MYSELF");
if(!name)
return NULL;
myself->connection->options = 0;
myself->connection->protocol_major = PROT_MAJOR;
myself->connection->protocol_minor = PROT_MINOR;
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */
logger(LOG_ERR, "Name for tinc daemon required!");
if(*name == '$') {
char *envname = getenv(name + 1);
if(!envname) {
if(strcmp(name + 1, "HOST")) {
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
return false;
}
envname = alloca(32);
if(gethostname(envname, 32)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", strerror(errno));
return false;
}
envname[31] = 0;
}
free(name);
name = xstrdup(envname);
for(char *c = name; *c; c++)
if(!isalnum(*c))
*c = '_';
}
if(!check_id(name)) {
logger(LOG_ERR, "Invalid name for myself!");
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
free(name);
return false;
}
myself->name = name;
myself->connection->name = xstrdup(name);
xasprintf(&fname, "%s/hosts/%s", confbase, name);
read_config_options(config_tree, name);
read_config_file(config_tree, fname);
free(fname);
return name;
}
get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
bool setup_myself_reloadable(void) {
char *proxy = NULL;
char *rmode = NULL;
char *fmode = NULL;
char *bmode = NULL;
char *afname = NULL;
char *space;
bool choice;
if(experimental && !read_ecdsa_private_key())
free(scriptinterpreter);
scriptinterpreter = NULL;
get_config_string(lookup_config(config_tree, "ScriptsInterpreter"), &scriptinterpreter);
free(scriptextension);
if(!get_config_string(lookup_config(config_tree, "ScriptsExtension"), &scriptextension))
#ifdef HAVE_MINGW
scriptextension = xstrdup(".bat");
#else
scriptextension = xstrdup("");
#endif
get_config_string(lookup_config(config_tree, "Proxy"), &proxy);
if(proxy) {
if((space = strchr(proxy, ' ')))
*space++ = 0;
if(!strcasecmp(proxy, "none")) {
proxytype = PROXY_NONE;
} else if(!strcasecmp(proxy, "socks4")) {
proxytype = PROXY_SOCKS4;
} else if(!strcasecmp(proxy, "socks4a")) {
proxytype = PROXY_SOCKS4A;
} else if(!strcasecmp(proxy, "socks5")) {
proxytype = PROXY_SOCKS5;
} else if(!strcasecmp(proxy, "http")) {
proxytype = PROXY_HTTP;
} else if(!strcasecmp(proxy, "exec")) {
proxytype = PROXY_EXEC;
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type %s!", proxy);
return false;
if(!read_rsa_private_key())
return false;
if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
myport = xstrdup("655");
if(!atoi(myport)) {
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
sockaddr_t sa;
if(!ai || !ai->ai_addr)
return false;
free(myport);
memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
sockaddr2str(&sa, NULL, &myport);
}
/* Read in all the subnets specified in the host configuration file */
switch(proxytype) {
case PROXY_NONE:
default:
break;
cfg = lookup_config(config_tree, "Subnet");
while(cfg) {
if(!get_config_subnet(cfg, &subnet))
case PROXY_EXEC:
if(!space || !*space) {
logger(DEBUG_ALWAYS, LOG_ERR, "Argument expected for proxy type exec!");
return false;
}
proxyhost = xstrdup(space);
break;
subnet_add(myself, subnet);
cfg = lookup_config_next(config_tree, cfg);
case PROXY_SOCKS4:
case PROXY_SOCKS4A:
case PROXY_SOCKS5:
case PROXY_HTTP:
proxyhost = space;
if(space && (space = strchr(space, ' ')))
*space++ = 0, proxyport = space;
if(space && (space = strchr(space, ' ')))
*space++ = 0, proxyuser = space;
if(space && (space = strchr(space, ' ')))
*space++ = 0, proxypass = space;
if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
logger(DEBUG_ALWAYS, LOG_ERR, "Host and port argument expected for proxy!");
return false;
}
proxyhost = xstrdup(proxyhost);
proxyport = xstrdup(proxyport);
if(proxyuser && *proxyuser)
proxyuser = xstrdup(proxyuser);
if(proxypass && *proxypass)
proxypass = xstrdup(proxypass);
break;
}
/* Check some options */
free(proxy);
}
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
myself->options |= OPTION_INDIRECT;
@ -432,36 +479,34 @@ static bool setup_myself(void) {
myself->options |= OPTION_INDIRECT;
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
strictsubnets |= tunnelserver;
get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
if(!strcasecmp(mode, "router"))
if(get_config_string(lookup_config(config_tree, "Mode"), &rmode)) {
if(!strcasecmp(rmode, "router"))
routing_mode = RMODE_ROUTER;
else if(!strcasecmp(mode, "switch"))
else if(!strcasecmp(rmode, "switch"))
routing_mode = RMODE_SWITCH;
else if(!strcasecmp(mode, "hub"))
else if(!strcasecmp(rmode, "hub"))
routing_mode = RMODE_HUB;
else {
logger(LOG_ERR, "Invalid routing mode!");
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid routing mode!");
return false;
}
free(mode);
free(rmode);
}
if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
if(!strcasecmp(mode, "off"))
if(get_config_string(lookup_config(config_tree, "Forwarding"), &fmode)) {
if(!strcasecmp(fmode, "off"))
forwarding_mode = FMODE_OFF;
else if(!strcasecmp(mode, "internal"))
else if(!strcasecmp(fmode, "internal"))
forwarding_mode = FMODE_INTERNAL;
else if(!strcasecmp(mode, "kernel"))
else if(!strcasecmp(fmode, "kernel"))
forwarding_mode = FMODE_KERNEL;
else {
logger(LOG_ERR, "Invalid forwarding mode!");
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid forwarding mode!");
return false;
}
free(mode);
free(fmode);
}
choice = true;
@ -475,10 +520,24 @@ static bool setup_myself(void) {
myself->options |= OPTION_CLAMP_MSS;
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
if(get_config_string(lookup_config(config_tree, "Broadcast"), &bmode)) {
if(!strcasecmp(bmode, "no"))
broadcast_mode = BMODE_NONE;
else if(!strcasecmp(bmode, "yes") || !strcasecmp(bmode, "mst"))
broadcast_mode = BMODE_MST;
else if(!strcasecmp(bmode, "direct"))
broadcast_mode = BMODE_DIRECT;
else {
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid broadcast mode!");
return false;
}
free(bmode);
}
#if !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance)
logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
@ -486,34 +545,12 @@ static bool setup_myself(void) {
if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
if(maxtimeout <= 0) {
logger(LOG_ERR, "Bogus maximum timeout!");
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus maximum timeout!");
return false;
}
} else
maxtimeout = 900;
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
if(udp_rcvbuf <= 0) {
logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
return false;
}
}
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
if(udp_sndbuf <= 0) {
logger(LOG_ERR, "UDPSndBuf cannot be negative!");
return false;
}
}
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
if(replaywin_int < 0) {
logger(LOG_ERR, "ReplayWindow cannot be negative!");
return false;
}
replaywin = (unsigned)replaywin_int;
}
if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
if(!strcasecmp(afname, "IPv4"))
addressfamily = AF_INET;
@ -522,7 +559,7 @@ static bool setup_myself(void) {
else if(!strcasecmp(afname, "any"))
addressfamily = AF_UNSPEC;
else {
logger(LOG_ERR, "Invalid address family!");
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid address family!");
return false;
}
free(afname);
@ -530,44 +567,149 @@ static bool setup_myself(void) {
get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600;
return true;
}
/*
Configure node_t myself and set up the local sockets (listen only)
*/
static bool setup_myself(void) {
char *name, *hostname, *cipher, *digest, *type;
char *fname = NULL;
char *address = NULL;
if(!(name = get_name())) {
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
return false;
}
myself = new_node();
myself->connection = new_connection();
myself->name = name;
myself->connection->name = xstrdup(name);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
read_config_options(config_tree, name);
read_config_file(config_tree, fname);
free(fname);
if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
myport = xstrdup("655");
xasprintf(&myself->hostname, "MYSELF port %s", myport);
myself->connection->hostname = xstrdup(myself->hostname);
myself->connection->options = 0;
myself->connection->protocol_major = PROT_MAJOR;
myself->connection->protocol_minor = PROT_MINOR;
myself->options |= PROT_MINOR << 24;
get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
if(experimental && !read_ecdsa_private_key())
return false;
if(!read_rsa_private_key())
return false;
if(!atoi(myport)) {
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
sockaddr_t sa;
if(!ai || !ai->ai_addr)
return false;
free(myport);
memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
sockaddr2str(&sa, NULL, &myport);
}
/* Read in all the subnets specified in the host configuration file */
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
subnet_t *subnet;
if(!get_config_subnet(cfg, &subnet))
return false;
subnet_add(myself, subnet);
}
/* Check some options */
if(!setup_myself_reloadable())
return false;
get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
strictsubnets |= tunnelserver;
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
if(udp_rcvbuf <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "UDPRcvBuf cannot be negative!");
return false;
}
}
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
if(udp_sndbuf <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "UDPSndBuf cannot be negative!");
return false;
}
}
int replaywin_int;
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
if(replaywin_int < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "ReplayWindow cannot be negative!");
return false;
}
replaywin = (unsigned)replaywin_int;
sptps_replaywin = replaywin;
}
/* Generate packet encryption key */
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
cipher = xstrdup("blowfish");
if(!cipher_open_by_name(&myself->incipher, cipher)) {
logger(LOG_ERR, "Unrecognized cipher type!");
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
return false;
}
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600;
free(cipher);
regenerate_key();
/* Check if we want to use message authentication codes... */
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
digest = xstrdup("sha1");
int maclength = 4;
get_config_int(lookup_config(config_tree, "MACLength"), &maclength);
if(maclength < 0) {
logger(LOG_ERR, "Bogus MAC length!");
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus MAC length!");
return false;
}
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
digest = xstrdup("sha1");
if(!digest_open_by_name(&myself->indigest, digest, maclength)) {
logger(LOG_ERR, "Unrecognized digest type!");
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
return false;
}
free(digest);
/* Compression */
if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
if(myself->incompression < 0 || myself->incompression > 11) {
logger(LOG_ERR, "Bogus compression level!");
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus compression level!");
return false;
}
} else
@ -580,6 +722,8 @@ static bool setup_myself(void) {
myself->nexthop = myself;
myself->via = myself;
myself->status.reachable = true;
myself->last_state_change = time(NULL);
myself->status.sptps = experimental;
node_add(myself);
graph();
@ -589,20 +733,40 @@ static bool setup_myself(void) {
/* Open device */
if(!setup_device())
devops = os_devops;
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "dummy"))
devops = dummy_devops;
else if(!strcasecmp(type, "raw_socket"))
devops = raw_socket_devops;
else if(!strcasecmp(type, "multicast"))
devops = multicast_devops;
#ifdef ENABLE_UML
else if(!strcasecmp(type, "uml"))
devops = uml_devops;
#endif
#ifdef ENABLE_VDE
else if(!strcasecmp(type, "vde"))
devops = vde_devops;
#endif
}
if(!devops.setup())
return false;
if(device_fd >= 0) {
event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
if (event_add(&device_ev, NULL) < 0) {
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
close_device();
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
devops.close();
return false;
}
}
/* Run tinc-up script to further initialize the tap interface */
char *envp[5];
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
@ -611,7 +775,7 @@ static bool setup_myself(void) {
execute_script("tinc-up", envp);
for(i = 0; i < 4; i++)
for(int i = 0; i < 4; i++)
free(envp[i]);
/* Run subnet-up scripts for our own subnets */
@ -620,24 +784,100 @@ static bool setup_myself(void) {
/* Open sockets */
get_config_string(lookup_config(config_tree, "BindToAddress"), &address);
if(!do_detach && getenv("LISTEN_FDS")) {
sockaddr_t sa;
socklen_t salen;
listen_sockets = atoi(getenv("LISTEN_FDS"));
#ifdef HAVE_UNSETENV
unsetenv("LISTEN_FDS");
#endif
if(listen_sockets > MAXSOCKETS) {
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
return false;
}
for(int i = 0; i < listen_sockets; i++) {
salen = sizeof sa;
if(getsockname(i + 3, &sa.sa, &salen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
return false;
}
listen_socket[i].tcp = i + 3;
#ifdef FD_CLOEXEC
fcntl(i + 3, F_SETFD, FD_CLOEXEC);
#endif
listen_socket[i].udp = setup_vpn_in_socket(&sa);
if(listen_socket[i].udp < 0)
return false;
event_set(&listen_socket[i].ev_tcp, listen_socket[i].tcp, EV_READ|EV_PERSIST, handle_new_meta_connection, NULL);
if(event_add(&listen_socket[i].ev_tcp, NULL) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
abort();
}
event_set(&listen_socket[i].ev_udp, listen_socket[i].udp, EV_READ|EV_PERSIST, handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
abort();
}
if(debug_level >= DEBUG_CONNECTIONS) {
hostname = sockaddr2hostname(&sa);
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
free(hostname);
}
memcpy(&listen_socket[i].sa, &sa, salen);
}
} else {
listen_sockets = 0;
config_t *cfg = lookup_config(config_tree, "BindToAddress");
do {
get_config_string(cfg, &address);
if(cfg)
cfg = lookup_config_next(config_tree, cfg);
char *port = myport;
if(address) {
char *space = strchr(address, ' ');
if(space) {
*space++ = 0;
port = space;
}
if(!strcmp(address, "*"))
*address = 0;
}
struct addrinfo *ai, hint = {0};
hint.ai_family = addressfamily;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
hint.ai_flags = AI_PASSIVE;
err = getaddrinfo(address, myport, &hint, &ai);
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
free(address);
if(err || !ai) {
logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
gai_strerror(err));
return false;
}
listen_sockets = 0;
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
if(listen_sockets >= MAXSOCKETS) {
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
return false;
}
for(aip = ai; aip; aip = aip->ai_next) {
listen_socket[listen_sockets].tcp =
setup_listen_socket((sockaddr_t *) aip->ai_addr);
@ -657,43 +897,42 @@ static bool setup_myself(void) {
EV_READ|EV_PERSIST,
handle_new_meta_connection, NULL);
if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
abort();
}
event_set(&listen_socket[listen_sockets].ev_udp,
listen_socket[listen_sockets].udp,
EV_READ|EV_PERSIST,
handle_incoming_vpn_data, NULL);
handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
abort();
}
ifdebug(CONNECTIONS) {
if(debug_level >= DEBUG_CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
logger(LOG_NOTICE, "Listening on %s", hostname);
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
free(hostname);
}
memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
listen_sockets++;
if(listen_sockets >= MAXSOCKETS) {
logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
break;
}
}
freeaddrinfo(ai);
} while(cfg);
}
if(listen_sockets)
logger(LOG_NOTICE, "Ready");
logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
else {
logger(LOG_ERR, "Unable to create any listening socket!");
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to create any listening socket!");
return false;
}
last_config_check = time(NULL);
return true;
}
@ -732,14 +971,12 @@ bool setup_network(void) {
close all open network connections
*/
void close_network_connections(void) {
splay_node_t *node, *next;
connection_t *c;
char *envp[5];
int i;
for(node = connection_tree->head; node; node = next) {
for(list_node_t *node = connection_list->head, *next; node; node = next) {
next = node->next;
c = node->data;
connection_t *c = node->data;
/* Keep control connections open until the end, so they know when we really terminated */
if(c->status.control)
c->socket = -1;
c->outgoing = NULL;
terminate_connection(c, false);
}
@ -752,13 +989,14 @@ void close_network_connections(void) {
free_connection(myself->connection);
}
for(i = 0; i < listen_sockets; i++) {
for(int i = 0; i < listen_sockets; i++) {
event_del(&listen_socket[i].ev_tcp);
event_del(&listen_socket[i].ev_udp);
close(listen_socket[i].tcp);
close(listen_socket[i].udp);
}
char *envp[5];
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
@ -775,10 +1013,10 @@ void close_network_connections(void) {
if(myport) free(myport);
for(i = 0; i < 4; i++)
for(int i = 0; i < 4; i++)
free(envp[i]);
close_device();
devops.close();
return;
}

View file

@ -1,7 +1,7 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
@ -22,9 +22,9 @@
#include "system.h"
#include "splay_tree.h"
#include "conf.h"
#include "connection.h"
#include "list.h"
#include "logger.h"
#include "meta.h"
#include "net.h"
@ -33,8 +33,6 @@
#include "utils.h"
#include "xalloc.h"
#include <assert.h>
/* Needed on Mac OS/X */
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
@ -59,13 +57,13 @@ static void configure_tcp(connection_t *c) {
int flags = fcntl(c->socket, F_GETFL);
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
}
#elif defined(WIN32)
unsigned long arg = 1;
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
logger(LOG_ERR, "ioctlsocket for %s: %d", c->hostname, sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno));
}
#endif
@ -98,74 +96,17 @@ static bool bind_to_interface(int sd) {
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
if(status) {
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
strerror(errno));
return false;
}
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "BindToInterface");
#endif
return true;
}
static bool bind_to_address(connection_t *c) {
char *node;
struct addrinfo *ai_list;
struct addrinfo *ai_ptr;
struct addrinfo ai_hints;
int status;
assert(c != NULL);
assert(c->socket >= 0);
node = NULL;
if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
&node))
return true;
assert(node != NULL);
memset(&ai_hints, 0, sizeof(ai_hints));
ai_hints.ai_family = c->address.sa.sa_family;
/* We're called from `do_outgoing_connection' only. */
ai_hints.ai_socktype = SOCK_STREAM;
ai_hints.ai_protocol = IPPROTO_TCP;
ai_list = NULL;
status = getaddrinfo(node, /* service = */ NULL,
&ai_hints, &ai_list);
if(status) {
logger(LOG_WARNING, "Error looking up %s port %s: %s",
node, "any", gai_strerror(status));
free(node);
return false;
}
assert(ai_list != NULL);
status = -1;
for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
status = bind(c->socket,
ai_list->ai_addr, ai_list->ai_addrlen);
if(!status)
break;
}
if(status) {
logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno));
} else ifdebug(CONNECTIONS) {
logger(LOG_DEBUG, "Successfully bound outgoing "
"TCP socket to %s", node);
}
free(node);
freeaddrinfo(ai_list);
return status ? false : true;
}
int setup_listen_socket(const sockaddr_t *sa) {
int nfd;
char *addrstr;
@ -175,10 +116,14 @@ int setup_listen_socket(const sockaddr_t *sa) {
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(nfd < 0) {
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
logger(DEBUG_STATUS, LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
return -1;
}
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
/* Optimize TCP settings */
option = 1;
@ -199,26 +144,26 @@ int setup_listen_socket(const sockaddr_t *sa) {
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) {
closesocket(nfd);
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
strerror(sockerrno));
return -1;
}
#else
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "BindToInterface");
#endif
}
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd);
addrstr = sockaddr2hostname(sa);
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
free(addrstr);
return -1;
}
if(listen(nfd, 3)) {
closesocket(nfd);
logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
return -1;
}
@ -233,17 +178,21 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
if(nfd < 0) {
logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
return -1;
}
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
{
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno));
return -1;
}
@ -253,7 +202,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
unsigned long arg = 1;
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
closesocket(nfd);
logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
return -1;
}
}
@ -261,12 +210,13 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof option);
if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf)))
logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf)))
logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
@ -313,7 +263,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd);
addrstr = sockaddr2hostname(sa);
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
free(addrstr);
return -1;
}
@ -334,14 +284,15 @@ void retry_outgoing(outgoing_t *outgoing) {
timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0});
ifdebug(CONNECTIONS) logger(LOG_NOTICE,
logger(DEBUG_CONNECTIONS, LOG_NOTICE,
"Trying to re-establish outgoing connection in %d seconds",
outgoing->timeout);
}
void finish_connecting(connection_t *c) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
if(proxytype != PROXY_EXEC)
configure_tcp(c);
c->last_ping_time = time(NULL);
@ -350,113 +301,68 @@ void finish_connecting(connection_t *c) {
send_id(c);
}
bool do_outgoing_connection(connection_t *c) {
char *address, *port, *space;
int result;
static void do_outgoing_pipe(connection_t *c, char *command) {
#ifndef HAVE_MINGW
int fd[2];
if(!c->outgoing) {
logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name);
abort();
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s", strerror(errno));
return;
}
begin:
if(!c->outgoing->ai) {
if(!c->outgoing->cfg) {
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
c->name);
retry_outgoing(c->outgoing);
c->outgoing = NULL;
connection_del(c);
return false;
if(fork()) {
c->socket = fd[0];
close(fd[1]);
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Using proxy %s", command);
return;
}
get_config_string(c->outgoing->cfg, &address);
close(0);
close(1);
close(fd[0]);
dup2(fd[1], 0);
dup2(fd[1], 1);
close(fd[1]);
space = strchr(address, ' ');
if(space) {
port = xstrdup(space + 1);
*space = 0;
} else {
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
port = xstrdup("655");
}
// Other filedescriptors should be closed automatically by CLOEXEC
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
free(address);
free(port);
char *host = NULL;
char *port = NULL;
c->outgoing->aip = c->outgoing->ai;
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
}
sockaddr2str(&c->address, &host, &port);
setenv("REMOTEADDRESS", host, true);
setenv("REMOTEPORT", port, true);
setenv("NODE", c->name, true);
setenv("NAME", myself->name, true);
if(netname)
setenv("NETNAME", netname, true);
if(!c->outgoing->aip) {
if(c->outgoing->ai)
freeaddrinfo(c->outgoing->ai);
c->outgoing->ai = NULL;
goto begin;
}
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
c->outgoing->aip = c->outgoing->aip->ai_next;
if(c->hostname)
free(c->hostname);
c->hostname = sockaddr2hostname(&c->address);
ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
c->hostname);
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(c->socket == -1) {
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
goto begin;
}
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
if(c->address.sa.sa_family == AF_INET6)
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
int result = system(command);
if(result < 0)
logger(DEBUG_ALWAYS, LOG_ERR, "Could not execute %s: %s", command, strerror(errno));
else if(result)
logger(DEBUG_ALWAYS, LOG_ERR, "%s exited with non-zero status %d", command, result);
exit(result);
#else
logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type exec not supported on this platform!");
return;
#endif
bind_to_interface(c->socket);
bind_to_address(c);
/* Optimize TCP settings */
configure_tcp(c);
/* Connect */
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
if(result == -1) {
if(sockinprogress(sockerrno)) {
c->status.connecting = true;
return true;
}
closesocket(c->socket);
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno));
goto begin;
}
finish_connecting(c);
return true;
}
static void handle_meta_write(int sock, short events, void *data) {
ifdebug(META) logger(LOG_DEBUG, "handle_meta_write() called");
connection_t *c = data;
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
if(outlen <= 0) {
logger(LOG_ERR, "Onoes, outlen = %d (%s)", (int)outlen, strerror(errno));
if(!errno || errno == EPIPE) {
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)", c->name, c->hostname);
} else if(sockwouldblock(sockerrno)) {
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Sending %d bytes to %s (%s) would block", c->outbuf.len - c->outbuf.offset, c->name, c->hostname);
return;
} else {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, strerror(errno));
}
terminate_connection(c, c->status.active);
return;
}
@ -466,51 +372,151 @@ static void handle_meta_write(int sock, short events, void *data) {
event_del(&c->outevent);
}
void setup_outgoing_connection(outgoing_t *outgoing) {
connection_t *c;
node_t *n;
if(event_initialized(&outgoing->ev))
event_del(&outgoing->ev);
bool do_outgoing_connection(outgoing_t *outgoing) {
char *address, *port, *space;
struct addrinfo *proxyai = NULL;
int result;
n = lookup_node(outgoing->name);
if(n)
if(n->connection) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);
n->connection->outgoing = outgoing;
return;
begin:
if(!outgoing->ai) {
if(!outgoing->cfg) {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
retry_outgoing(outgoing);
return false;
}
c = new_connection();
get_config_string(outgoing->cfg, &address);
space = strchr(address, ' ');
if(space) {
port = xstrdup(space + 1);
*space = 0;
} else {
if(!get_config_string(lookup_config(outgoing->config_tree, "Port"), &port))
port = xstrdup("655");
}
outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
free(address);
free(port);
outgoing->aip = outgoing->ai;
outgoing->cfg = lookup_config_next(outgoing->config_tree, outgoing->cfg);
}
if(!outgoing->aip) {
if(outgoing->ai)
freeaddrinfo(outgoing->ai);
outgoing->ai = NULL;
goto begin;
}
connection_t *c = new_connection();
c->outgoing = outgoing;
memcpy(&c->address, outgoing->aip->ai_addr, outgoing->aip->ai_addrlen);
outgoing->aip = outgoing->aip->ai_next;
c->hostname = sockaddr2hostname(&c->address);
logger(DEBUG_CONNECTIONS, LOG_INFO, "Trying to connect to %s (%s)", outgoing->name, c->hostname);
if(!proxytype) {
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
configure_tcp(c);
} else if(proxytype == PROXY_EXEC) {
do_outgoing_pipe(c, proxyhost);
} else {
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
if(!proxyai) {
free_connection(c);
goto begin;
}
logger(DEBUG_CONNECTIONS, LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
}
if(c->socket == -1) {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
free_connection(c);
goto begin;
}
#ifdef FD_CLOEXEC
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
#endif
if(proxytype != PROXY_EXEC) {
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
if(c->address.sa.sa_family == AF_INET6)
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
bind_to_interface(c->socket);
}
/* Connect */
if(!proxytype) {
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
} else if(proxytype == PROXY_EXEC) {
result = 0;
} else {
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
freeaddrinfo(proxyai);
}
if(result == -1 && !sockinprogress(sockerrno)) {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not connect to %s (%s): %s", outgoing->name, c->hostname, sockstrerror(sockerrno));
free_connection(c);
goto begin;
}
/* Now that there is a working socket, fill in the rest and register this connection. */
c->status.connecting = true;
c->name = xstrdup(outgoing->name);
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
init_configuration(&c->config_tree);
read_connection_config(c);
outgoing->cfg = lookup_config(c->config_tree, "Address");
if(!outgoing->cfg) {
logger(LOG_ERR, "No address specified for %s", c->name);
free_connection(c);
return;
}
c->outgoing = outgoing;
c->last_ping_time = time(NULL);
connection_add(c);
if (do_outgoing_connection(c)) {
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
event_add(&c->inevent, NULL);
return true;
}
void setup_outgoing_connection(outgoing_t *outgoing) {
if(event_initialized(&outgoing->ev))
event_del(&outgoing->ev);
node_t *n = lookup_node(outgoing->name);
if(n && n->connection) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
n->connection->outgoing = outgoing;
return;
}
init_configuration(&outgoing->config_tree);
read_host_config(outgoing->config_tree, outgoing->name);
outgoing->cfg = lookup_config(outgoing->config_tree, "Address");
if(!outgoing->cfg) {
logger(DEBUG_ALWAYS, LOG_ERR, "No address specified for %s", outgoing->name);
return;
}
do_outgoing_connection(outgoing);
}
/*
@ -526,7 +532,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
fd = accept(sock, &sa.sa, &len);
if(fd < 0) {
logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
return;
}
@ -544,7 +550,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
c->socket = fd;
c->last_ping_time = time(NULL);
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname);
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
@ -559,9 +565,15 @@ void handle_new_meta_connection(int sock, short events, void *data) {
}
static void free_outgoing(outgoing_t *outgoing) {
if(event_initialized(&outgoing->ev))
event_del(&outgoing->ev);
if(outgoing->ai)
freeaddrinfo(outgoing->ai);
if(outgoing->config_tree)
exit_configuration(&outgoing->config_tree);
if(outgoing->name)
free(outgoing->name);
@ -569,26 +581,60 @@ static void free_outgoing(outgoing_t *outgoing) {
}
void try_outgoing_connections(void) {
static config_t *cfg = NULL;
char *name;
outgoing_t *outgoing;
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
if(!outgoing_list) {
outgoing_list = list_alloc((list_action_t)free_outgoing);
} else {
for list_each(outgoing_t, outgoing, outgoing_list)
outgoing->timeout = -1;
}
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
for(config_t *cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
char *name;
get_config_string(cfg, &name);
if(!check_id(name)) {
logger(LOG_ERR,
logger(DEBUG_ALWAYS, LOG_ERR,
"Invalid name for outgoing connection in %s line %d",
cfg->file, cfg->line);
free(name);
continue;
}
outgoing = xmalloc_and_zero(sizeof *outgoing);
bool found = false;
for list_each(outgoing_t, outgoing, outgoing_list) {
if(!strcmp(outgoing->name, name)) {
found = true;
outgoing->timeout = 0;
break;
}
}
if(!found) {
outgoing_t *outgoing = xmalloc_and_zero(sizeof *outgoing);
outgoing->name = name;
list_insert_tail(outgoing_list, outgoing);
setup_outgoing_connection(outgoing);
}
}
/* Terminate any connections whose outgoing_t is to be deleted. */
for list_each(connection_t, c, connection_list) {
if(c->outgoing && c->outgoing->timeout == -1) {
c->outgoing = NULL;
logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
terminate_connection(c, c->status.active);
}
}
/* Delete outgoing_ts for which there is no ConnectTo. */
for list_each(outgoing_t, outgoing, outgoing_list)
if(outgoing->timeout == -1)
list_delete_node(outgoing_list, node);
}

View file

@ -1,7 +1,7 @@
/*
netutl.c -- some supporting network utility code
Copyright (C) 1998-2005 Ivo Timmermans
2000-2011 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
it under the terms of the GNU General Public License as published by
@ -42,7 +42,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
err = getaddrinfo(address, service, &hint, &ai);
if(err) {
logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
logger(DEBUG_ALWAYS, LOG_WARNING, "Error looking up %s port %s: %s", address,
service, gai_strerror(err));
return NULL;
}
@ -62,8 +62,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port) {
err = getaddrinfo(address, port, &hint, &ai);
if(err || !ai) {
ifdebug(SCARY_THINGS)
logger(LOG_DEBUG, "Unknown type address %s port %s", address, port);
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Unknown type address %s port %s", address, port);
result.sa.sa_family = AF_UNKNOWN;
result.unknown.address = xstrdup(address);
result.unknown.port = xstrdup(port);
@ -83,7 +82,9 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
int err;
if(sa->sa.sa_family == AF_UNKNOWN) {
if(addrstr)
*addrstr = xstrdup(sa->unknown.address);
if(portstr)
*portstr = xstrdup(sa->unknown.port);
return;
}
@ -91,7 +92,7 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
if(err) {
logger(LOG_ERR, "Error while translating addresses: %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while translating addresses: %s",
gai_strerror(err));
abort();
}
@ -121,7 +122,7 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
if(err) {
logger(LOG_ERR, "Error while looking up hostname: %s",
logger(DEBUG_ALWAYS, LOG_ERR, "Error while looking up hostname: %s",
gai_strerror(err));
}
@ -152,7 +153,7 @@ int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
default:
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
logger(DEBUG_ALWAYS, LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family);
abort();
}
@ -195,7 +196,7 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
default:
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
logger(DEBUG_ALWAYS, LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family);
abort();
}
@ -224,71 +225,3 @@ void sockaddrunmap(sockaddr_t *sa) {
sa->in.sin_family = AF_INET;
}
}
/* Subnet mask handling */
int maskcmp(const void *va, const void *vb, int masklen) {
int i, m, result;
const char *a = va;
const char *b = vb;
for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
result = a[i] - b[i];
if(result)
return result;
}
if(m)
return (a[i] & (0x100 - (1 << (8 - m)))) -
(b[i] & (0x100 - (1 << (8 - m))));
return 0;
}
void mask(void *va, int masklen, int len) {
int i;
char *a = va;
i = masklen / 8;
masklen %= 8;
if(masklen)
a[i++] &= (0x100 - (1 << (8 - masklen)));
for(; i < len; i++)
a[i] = 0;
}
void maskcpy(void *va, const void *vb, int masklen, int len) {
int i, m;
char *a = va;
const char *b = vb;
for(m = masklen, i = 0; m >= 8; m -= 8, i++)
a[i] = b[i];
if(m) {
a[i] = b[i] & (0x100 - (1 << (8 - m)));
i++;
}
for(; i < len; i++)
a[i] = 0;
}
bool maskcheck(const void *va, int masklen, int len) {
int i;
const char *a = va;
i = masklen / 8;
masklen %= 8;
if(masklen && a[i++] & (0xff >> masklen))
return false;
for(; i < len; i++)
if(a[i] != 0)
return false;
return true;
}

View file

@ -1,7 +1,7 @@
/*
netutl.h -- header file for netutl.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2009 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
it under the terms of the GNU General Public License as published by
@ -34,9 +34,5 @@ extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
extern void sockaddrunmap(sockaddr_t *);
extern void sockaddrfree(sockaddr_t *);
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *);
extern int maskcmp(const void *, const void *, int);
extern void maskcpy(void *, const void *, int, int);
extern void mask(void *, int, int);
extern bool maskcheck(const void *, int, int);
#endif /* __TINC_NETUTL_H__ */

View file

@ -1,6 +1,6 @@
/*
node.c -- node tree management
Copyright (C) 2001-2011 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -21,16 +21,17 @@
#include "system.h"
#include "control_common.h"
#include "splay_tree.h"
#include "hash.h"
#include "logger.h"
#include "net.h"
#include "netutl.h"
#include "node.h"
#include "splay_tree.h"
#include "utils.h"
#include "xalloc.h"
splay_tree_t *node_tree; /* Known nodes, sorted by name */
splay_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */
splay_tree_t *node_tree;
static hash_t *node_udp_cache;
node_t *myself;
@ -38,24 +39,13 @@ static int node_compare(const node_t *a, const node_t *b) {
return strcmp(a->name, b->name);
}
static int node_udp_compare(const node_t *a, const node_t *b) {
int result;
result = sockaddrcmp(&a->address, &b->address);
if(result)
return result;
return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
}
void init_nodes(void) {
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
}
void exit_nodes(void) {
splay_delete_tree(node_udp_tree);
hash_free(node_udp_cache);
splay_delete_tree(node_tree);
}
@ -85,8 +75,8 @@ void free_node(node_t *n) {
cipher_close(&n->outcipher);
digest_close(&n->outdigest);
ecdh_free(&n->ecdh);
ecdsa_free(&n->ecdsa);
sptps_stop(&n->sptps);
if(timeout_initialized(&n->mtuevent))
event_del(&n->mtuevent);
@ -108,23 +98,12 @@ void node_add(node_t *n) {
}
void node_del(node_t *n) {
splay_node_t *node, *next;
edge_t *e;
subnet_t *s;
for(node = n->subnet_tree->head; node; node = next) {
next = node->next;
s = node->data;
for splay_each(subnet_t, s, n->subnet_tree)
subnet_del(n, s);
}
for(node = n->edge_tree->head; node; node = next) {
next = node->next;
e = node->data;
for splay_each(edge_t, e, n->edge_tree)
edge_del(e);
}
splay_delete(node_udp_tree, n);
splay_delete(node_tree, n);
}
@ -137,62 +116,41 @@ node_t *lookup_node(char *name) {
}
node_t *lookup_node_udp(const sockaddr_t *sa) {
node_t n = {NULL};
n.address = *sa;
n.name = NULL;
return splay_search(node_udp_tree, &n);
return hash_search(node_udp_cache, sa);
}
void update_node_udp(node_t *n, const sockaddr_t *sa) {
if(n == myself) {
logger(LOG_WARNING, "Trying to update UDP address of myself!");
logger(DEBUG_ALWAYS, LOG_WARNING, "Trying to update UDP address of myself!");
return;
}
splay_delete(node_udp_tree, n);
if(n->hostname)
free(n->hostname);
hash_insert(node_udp_cache, &n->address, NULL);
if(sa) {
n->address = *sa;
hash_insert(node_udp_cache, sa, n);
free(n->hostname);
n->hostname = sockaddr2hostname(&n->address);
splay_insert(node_udp_tree, n);
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
} else {
memset(&n->address, 0, sizeof n->address);
n->hostname = NULL;
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
}
}
bool dump_nodes(connection_t *c) {
splay_node_t *node;
node_t *n;
for(node = node_tree->head; node; node = node->next) {
n = node->data;
send_request(c, "%d %d %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)", CONTROL, REQ_DUMP_NODES,
n->name, n->hostname, cipher_get_nid(&n->outcipher),
for splay_each(node_t, n, node_tree)
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(&n->outcipher),
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu);
}
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
}
bool dump_traffic(connection_t *c) {
splay_node_t *node;
node_t *n;
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for splay_each(node_t, n, node_tree)
send_request(c, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_TRAFFIC,
n->name, n->in_packets, n->in_bytes, n->out_packets, n->out_bytes);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
}

View file

@ -1,6 +1,6 @@
/*
node.h -- header for node.c
Copyright (C) 2001-2010 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -25,32 +25,34 @@
#include "cipher.h"
#include "connection.h"
#include "digest.h"
#include "ecdh.h"
#include "subnet.h"
typedef struct node_status_t {
unsigned int unused_active:1; /* 1 if active (not used for nodes) */
unsigned int validkey:1; /* 1 if we currently have a valid key for him */
unsigned int unused_waitingforkey:1; /* 1 if we already sent out a request */
unsigned int waitingforkey:1; /* 1 if we already sent out a request */
unsigned int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
unsigned int reachable:1; /* 1 if this node is reachable in the graph */
unsigned int indirect:1; /* 1 if this node is not directly reachable by us */
unsigned int ecdh:1; /* 1 if this node supports ECDH key exchange */
unsigned int unused:25;
unsigned int sptps:1; /* 1 if this node supports SPTPS */
unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */
unsigned int unused:24;
} node_status_t;
typedef struct node_t {
char *name; /* name of this node */
uint32_t options; /* options turned on for this node */
int sock; /* Socket to use for outgoing UDP packets */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */
node_status_t status;
time_t last_state_change;
time_t last_req_key;
ecdsa_t ecdsa; /* His public ECDSA key */
ecdh_t ecdh; /* State for ECDH key exchange */
sptps_t sptps;
cipher_t incipher; /* Cipher for UDP packets */
digest_t indigest; /* Digest for UDP packets */
@ -63,6 +65,7 @@ typedef struct node_t {
int distance;
struct node_t *nexthop; /* nearest node from us to him */
struct edge_t *prevedge; /* nearest node from him to us */
struct node_t *via; /* next hop for UDP packets */
splay_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
@ -90,7 +93,6 @@ typedef struct node_t {
extern struct node_t *myself;
extern splay_tree_t *node_tree;
extern splay_tree_t *node_udp_tree;
extern void init_nodes(void);
extern void exit_nodes(void);

View file

@ -1,6 +1,6 @@
/*
cipher.c -- Symmetric block cipher handling
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -26,6 +26,12 @@
#include "logger.h"
#include "xalloc.h"
typedef struct cipher_counter {
unsigned char counter[EVP_MAX_IV_LENGTH];
unsigned char block[EVP_MAX_IV_LENGTH];
int n;
} cipher_counter_t;
static bool cipher_open(cipher_t *cipher) {
EVP_CIPHER_CTX_init(&cipher->ctx);
@ -38,7 +44,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
if(cipher->cipher)
return cipher_open(cipher);
logger(LOG_ERR, "Unknown cipher name '%s'!", name);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
return false;
}
@ -48,7 +54,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
if(cipher->cipher)
return cipher_open(cipher);
logger(LOG_ERR, "Unknown cipher nid %d!", nid);
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
return false;
}
@ -59,10 +65,12 @@ bool cipher_open_blowfish_ofb(cipher_t *cipher) {
void cipher_close(cipher_t *cipher) {
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
free(cipher->counter);
cipher->counter = NULL;
}
size_t cipher_keylength(const cipher_t *cipher) {
return cipher->cipher->key_len + cipher->cipher->iv_len;
return cipher->cipher->key_len + cipher->cipher->block_size;
}
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
@ -76,7 +84,7 @@ bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
if(result)
return true;
logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -91,28 +99,92 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
if(result)
return true;
logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
bool cipher_set_counter(cipher_t *cipher, const void *counter, size_t len) {
if(len > cipher->cipher->block_size - 4) {
logger(DEBUG_ALWAYS, LOG_ERR, "Counter too long");
abort();
}
memcpy(cipher->counter->counter + cipher->cipher->block_size - len, counter, len);
memset(cipher->counter->counter, 0, 4);
cipher->counter->n = 0;
return true;
}
bool cipher_set_counter_key(cipher_t *cipher, void *key) {
int result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, NULL);
if(!result) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
if(!cipher->counter)
cipher->counter = xmalloc_and_zero(sizeof *cipher->counter);
else
cipher->counter->n = 0;
memcpy(cipher->counter->counter, (unsigned char *)key + cipher->cipher->key_len, cipher->cipher->block_size);
return true;
}
bool cipher_counter_xor(cipher_t *cipher, const void *indata, size_t inlen, void *outdata) {
if(!cipher->counter) {
logger(DEBUG_ALWAYS, LOG_ERR, "Counter not initialized");
return false;
}
const unsigned char *in = indata;
unsigned char *out = outdata;
while(inlen--) {
// Encrypt the new counter value if we need it
if(!cipher->counter->n) {
int len;
if(!EVP_EncryptUpdate(&cipher->ctx, cipher->counter->block, &len, cipher->counter->counter, cipher->cipher->block_size)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
// Increase the counter value
for(int i = 0; i < cipher->cipher->block_size; i++)
if(++cipher->counter->counter[i])
break;
}
*out++ = *in++ ^ cipher->counter->counter[cipher->counter->n++];
if(cipher->counter->n >= cipher->cipher->block_size)
cipher->counter->n = 0;
}
return true;
}
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
if(oneshot) {
int len, pad;
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
*outlen = len + pad;
if(outlen) *outlen = len + pad;
return true;
}
} else {
int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
*outlen = len;
if(outlen) *outlen = len;
return true;
}
}
logger(LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -122,18 +194,18 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
*outlen = len + pad;
if(outlen) *outlen = len + pad;
return true;
}
} else {
int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
*outlen = len;
if(outlen) *outlen = len;
return true;
}
}
logger(LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}

View file

@ -1,6 +1,6 @@
/*
cipher.h -- header file cipher.c
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -29,6 +29,7 @@
typedef struct cipher {
EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher;
struct cipher_counter *counter;
} cipher_t;
extern bool cipher_open_by_name(cipher_t *, const char *);
@ -38,8 +39,11 @@ extern void cipher_close(cipher_t *);
extern size_t cipher_keylength(const cipher_t *);
extern bool cipher_set_key(cipher_t *, void *, bool);
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool);
extern bool cipher_set_counter(cipher_t *, const void *, size_t);
extern bool cipher_set_counter_key(cipher_t *, void *);
extern bool cipher_encrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
extern bool cipher_decrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
extern bool cipher_counter_xor(cipher_t *, const void *indata, size_t inlen, void *outdata);
extern int cipher_get_nid(const cipher_t *);
extern bool cipher_active(const cipher_t *);

View file

@ -1,6 +1,6 @@
/*
digest.c -- Digest handling
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
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
@ -41,7 +41,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
digest->key = NULL;
if(!digest->digest) {
logger(LOG_DEBUG, "Unknown digest name '%s'!", name);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
return false;
}
@ -54,7 +54,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
digest->key = NULL;
if(!digest->digest) {
logger(LOG_DEBUG, "Unknown digest nid %d!", nid);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
return false;
}
@ -78,7 +78,6 @@ bool digest_set_key(digest_t *digest, const void *key, size_t len) {
}
void digest_close(digest_t *digest) {
if(digest->key)
free(digest->key);
digest->key = NULL;
}
@ -95,7 +94,7 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out
if(!EVP_DigestInit(&ctx, digest->digest)
|| !EVP_DigestUpdate(&ctx, indata, inlen)
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
logger(LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
}
@ -115,6 +114,10 @@ int digest_get_nid(const digest_t *digest) {
return digest->digest ? digest->digest->type : 0;
}
size_t digest_keylength(const digest_t *digest) {
return digest->digest->md_size;
}
size_t digest_length(const digest_t *digest) {
return digest->maclength;
}

View file

@ -1,6 +1,6 @@
/*
digest.h -- header file digest.c
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-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
@ -39,6 +39,7 @@ extern bool digest_create(struct digest *, const void *indata, size_t inlen, voi
extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
extern bool digest_set_key(struct digest *, const void *key, size_t len);
extern int digest_get_nid(const struct digest *);
extern size_t digest_keylength(const struct digest *);
extern size_t digest_length(const struct digest *);
extern bool digest_active(const struct digest *);

View file

@ -1,6 +1,6 @@
/*
ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-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
@ -30,21 +30,32 @@
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!*ecdh) {
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
if(!EC_KEY_generate_key(*ecdh)) {
logger(LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
const EC_POINT *point = EC_KEY_get0_public_key(*ecdh);
if(!point) {
logger(LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
if(!result) {
logger(LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
EC_KEY_free(*ecdh);
*ecdh = NULL;
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
@ -53,14 +64,15 @@ bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh));
if(!point) {
logger(LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL);
if(!result) {
logger(LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
EC_POINT_free(point);
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
result = ECDH_compute_key(shared, ECDH_SIZE, point, *ecdh, NULL);
@ -69,7 +81,7 @@ bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
*ecdh = NULL;
if(!result) {
logger(LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}

View file

@ -1,6 +1,6 @@
/*
ecdsa.c -- ECDSA key handling
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-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
@ -30,15 +30,19 @@
//
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
if(!*ecdsa) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
int len = strlen(p);
unsigned char pubkey[len / 4 * 3 + 3];
const unsigned char *ppubkey = pubkey;
len = b64decode(p, pubkey, len);
len = b64decode(p, (char *)pubkey, len);
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) {
logger(LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort();
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
return true;
@ -49,7 +53,7 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5);
b64encode(pubkey, base64, len);
b64encode((char *)pubkey, base64, len);
free(pubkey);
@ -64,7 +68,7 @@ bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
if(*ecdsa)
return true;
logger(LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -74,7 +78,7 @@ bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
if(*ecdsa)
return true;
logger(LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -87,31 +91,27 @@ size_t ecdsa_size(ecdsa_t *ecdsa) {
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa);
char hash[SHA512_DIGEST_LENGTH];
unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash);
memset(sig, 0, siglen);
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) {
logger(LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}
if(siglen != ECDSA_size(*ecdsa)) {
logger(LOG_ERR, "Signature length %d != %d", siglen, ECDSA_size(*ecdsa));
}
return true;
}
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa);
char hash[SHA512_DIGEST_LENGTH];
unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash);
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) {
logger(LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
return false;
}

View file

@ -67,7 +67,7 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5);
b64encode(pubkey, base64, len);
b64encode((char *)pubkey, base64, len);
free(pubkey);

View file

@ -1,6 +1,6 @@
/*
prf.c -- Pseudo-Random Function for key material generation
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-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
@ -19,14 +19,16 @@
#include "system.h"
#include <openssl/obj_mac.h>
#include "digest.h"
#include "prf.h"
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
We use SHA512 and Whirlpool instead of MD5 and SHA1.
We use SHA512 instead of MD5 and SHA1.
*/
static bool prf_xor(int nid, char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
digest_t digest;
if(!digest_open_by_nid(&digest, nid, -1))
@ -65,12 +67,9 @@ static bool prf_xor(int nid, char *secret, size_t secretlen, char *seed, size_t
return true;
}
bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
/* Split secret in half, generate outlen bits with two different hash algorithms,
and XOR the results. */
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
/* This construction allows us to easily switch back to a scheme where the PRF is calculated using two different digest algorithms. */
memset(out, 0, outlen);
return prf_xor(NID_sha512, secret, (secretlen + 1) / 2, seed, seedlen, out, outlen)
&& prf_xor(NID_whirlpool, secret + secretlen / 2, (secretlen + 1) / 2, seed, seedlen, out, outlen);
return prf_xor(NID_sha512, secret, secretlen, seed, seedlen, out, outlen);
}

Some files were not shown because too many files have changed in this diff Show more