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. See the AUTHORS file for a complete list.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under

1976
ChangeLog

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
Installation Instructions Installation Instructions
************************* *************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
2006, 2007, 2008, 2009 Free Software Foundation, Inc. Inc.
Copying and distribution of this file, with or without modification, Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright 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. 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 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 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 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@ # @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Inc. # Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@ @SET_MAKE@
VPATH = @srcdir@ 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@ pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@
@ -42,7 +59,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.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) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ 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 \ install-pdf-recursive install-ps-recursive install-recursive \
installcheck-recursive installdirs-recursive pdf-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \
ps-recursive uninstall-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 \ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@ -72,9 +95,11 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION) distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir) top_distdir = $(distdir)
am__remove_distdir = \ am__remove_distdir = \
{ test ! -d "$(distdir)" \ if test -d "$(distdir)"; then \
|| { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr "$(distdir)"; }; } && rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
am__relativize = \ am__relativize = \
dir0=`pwd`; \ dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
@ -103,6 +128,8 @@ am__relativize = \
DIST_ARCHIVES = $(distdir).tar.gz DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@ ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
@ -152,6 +179,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
STRIP = @STRIP@ STRIP = @STRIP@
@ -214,7 +242,7 @@ all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive $(MAKE) $(AM_MAKEFLAGS) all-recursive
.SUFFIXES: .SUFFIXES:
am--refresh: am--refresh: Makefile
@: @:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \ @for dep in $?; do \
@ -250,10 +278,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
config.h: stamp-h1 config.h: stamp-h1
@if test ! -f $@; then \ @if test ! -f $@; then rm -f stamp-h1; else :; fi
rm -f stamp-h1; \ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
else :; fi
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1 @rm -f stamp-h1
@ -435,13 +461,10 @@ distdir: $(DISTFILES)
done done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \ if test "$$subdir" = .; then :; else \
test -d "$(distdir)/$$subdir" \ $(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \ || exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \ $(am__relativize); \
new_distdir=$$reldir; \ new_distdir=$$reldir; \
@ -473,7 +496,11 @@ dist-gzip: distdir
$(am__remove_distdir) $(am__remove_distdir)
dist-bzip2: 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) $(am__remove_distdir)
dist-lzma: distdir dist-lzma: distdir
@ -481,7 +508,7 @@ dist-lzma: distdir
$(am__remove_distdir) $(am__remove_distdir)
dist-xz: 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) $(am__remove_distdir)
dist-tarZ: distdir dist-tarZ: distdir
@ -512,6 +539,8 @@ distcheck: dist
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lzma*) \ *.tar.lzma*) \
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \ *.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \ *.tar.Z*) \
@ -521,7 +550,7 @@ distcheck: dist
*.zip*) \ *.zip*) \
unzip $(distdir).zip ;;\ unzip $(distdir).zip ;;\
esac esac
chmod -R a-w $(distdir); chmod a+w $(distdir) chmod -R a-w $(distdir); chmod u+w $(distdir)
mkdir $(distdir)/_build mkdir $(distdir)/_build
mkdir $(distdir)/_inst mkdir $(distdir)/_inst
chmod a-w $(distdir) chmod a-w $(distdir)
@ -531,6 +560,7 @@ distcheck: dist
&& am__cwd=`pwd` \ && am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build \ && $(am__cd) $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) dvi \
@ -559,8 +589,16 @@ distcheck: dist
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ 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' sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck: distuninstallcheck:
@$(am__cd) '$(distuninstallcheck_dir)' \ @test -n '$(distuninstallcheck_dir)' || { \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ 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:" ; \ || { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \ if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \ echo " (check DESTDIR support)"; \
@ -591,10 +629,15 @@ install-am: all-am
installcheck: installcheck-recursive installcheck: installcheck-recursive
install-strip: install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \ install; \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` 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: mostlyclean-generic:
clean-generic: clean-generic:
@ -681,17 +724,18 @@ uninstall-am:
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
all all-am am--refresh check check-am clean clean-generic \ all all-am am--refresh check check-am clean clean-generic \
ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \ dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
distclean distclean-generic distclean-hdr distclean-tags \ distcheck distclean distclean-generic distclean-hdr \
distcleancheck distdir distuninstallcheck dvi dvi-am html \ distclean-tags distcleancheck distdir distuninstallcheck dvi \
html-am info info-am install install-am install-data \ dvi-am html html-am info info-am install install-am \
install-data-am install-dvi install-dvi-am install-exec \ install-data install-data-am install-dvi install-dvi-am \
install-exec-am install-html install-html-am install-info \ install-exec install-exec-am install-html install-html-am \
install-info-am install-man install-pdf install-pdf-am \ install-info install-info-am install-man install-pdf \
install-ps install-ps-am install-strip installcheck \ install-pdf-am install-ps install-ps-am install-strip \
installcheck-am installdirs installdirs-am maintainer-clean \ installcheck installcheck-am installdirs installdirs-am \
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ maintainer-clean maintainer-clean-generic mostlyclean \
pdf-am ps ps-am tags tags-recursive uninstall uninstall-am mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \
uninstall uninstall-am
ChangeLog: 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. * .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 Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
version of tinc. 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 Version 1.0.15 June 24 2011
* Improved logging to file. * 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. instructions may be found in the INSTALL file.
tinc is Copyright (C) 1998-2011 by: tinc is Copyright (C) 1998-2012 by:
Ivo Timmermans, Ivo Timmermans,
Guus Sliepen <guus@tinc-vpn.org>, Guus Sliepen <guus@tinc-vpn.org>,
@ -29,82 +29,66 @@ protocol is not fixed yet.
Security statement Security statement
------------------ ------------------
This version uses an experimental and unfinished cryptographic protocol. Use This version uses an experimental and unfinished cryptographic protocol. Use it
it at your own risk. at your own risk.
Compatibility 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. versions of tinc.
When the ExperimentalProtocol option is used, tinc is still compatible with When the ExperimentalProtocol option is used, tinc is still compatible with
1.0.X and 1.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 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 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 Features
-------- --------
This version of tinc supports multiple virtual networks at once. To Tinc is a peer-to-peer VPN daemon that supports VPNs with an arbitrary number
use this feature, you may supply a netname via the -n or --net of nodes. Instead of configuring tunnels, you give tinc the location and
options. The standard locations for the config files will then be public key of a few nodes in the VPN. After making the initial connections to
/etc/tinc/<net>/. 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 By default, nodes authenticate each other using 2048 bit RSA (or 521 bit
activity after the keys have expired. This period is adjustable in the ECDSA*) keys. Traffic is encrypted using Blowfish in CBC mode (or AES-256 in
configuration file, and the default time is 3600 seconds (one hour). 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 *) When using the ExperimentalProtocol option.
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.
Since pre5, tinc can operate in several routing modes. The default mode, Tinc fully supports IPv6.
"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.
The algorithms used for encryption and generating message authentication codes Tinc can operate in several routing modes. In the default mode, "router", every
can now be changed in the configuration files. All cipher and digest algorithms node is associated with one or more IPv4 and/or IPv6 Subnets. The other two
supported by OpenSSL can be used. Useful ciphers are "blowfish" (default), modes, "switch" and "hub", let the tinc daemons work together to form a virtual
"bf-ofb", "des", "des3", etcetera. Useful digests are "sha1" (default), "md5", Ethernet network switch or hub.
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.
Normally, when started tinc will detach and run in the background. In a native Normally, when started tinc will detach and run in the background. In a native
Windows environment this means tinc will intall itself as a service, which will Windows environment this means tinc will intall itself as a service, which will
restart after reboots. To prevent tinc from detaching or running as a service, restart after reboots. To prevent tinc from detaching or running as a service,
use the -D option. use the -D option.
The status of the VPN can be queried using the "tincctl" tool, which connects
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 * Alexander Reil and Gemeinde Berg
* Allesandro Gatti * Allesandro Gatti
* Andreas van Cranenburgh * Andreas van Cranenburgh
* Anthony G. Basile
* Armijn Hemel * Armijn Hemel
* Brandon Black * Brandon Black
* Cris van Pelt * Cris van Pelt
* Delf Eldkraft * Delf Eldkraft
* dnk * dnk
* Enrique Zanardi * Enrique Zanardi
* Erik Tews
* Flynn Marquardt * Flynn Marquardt
* Grzegorz Dymarek * Grzegorz Dymarek
* Hans Bayle * Hans Bayle
@ -26,13 +28,17 @@ We would like to thank the following people for their contributions to tinc:
* Mark Glines * Mark Glines
* Markus Goetz * Markus Goetz
* Martin Kihlgren * Martin Kihlgren
* Martin Schürrer
* Matias Carrasco * Matias Carrasco
* Max Rijevski * Max Rijevski
* Menno Smits * Menno Smits
* Mesar Hameed
* Michael Tokarev * Michael Tokarev
* Miles Nordin * Miles Nordin
* Nick Hibma
* Nick Patavalis * Nick Patavalis
* Paul Littlefield * Paul Littlefield
* Philipp Babel
* Robert van der Meulen * Robert van der Meulen
* Rumko * Rumko
* Scott Lamb * Scott Lamb
@ -40,6 +46,7 @@ We would like to thank the following people for their contributions to tinc:
* Teemu Kiviniemi * Teemu Kiviniemi
* Timothy Redaelli * Timothy Redaelli
* Tonnerre Lombard * Tonnerre Lombard
* Vil Brekin
* Wessel Dankers * Wessel Dankers
* Wouter van Heyst * 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, # 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -13,8 +14,8 @@
m4_ifndef([AC_AUTOCONF_VERSION], m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
[m4_warning([this file was generated for autoconf 2.68. [m4_warning([this file was generated for autoconf 2.69.
You have another version of autoconf. It may work, but is not guaranteed to. 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. 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'.])]) 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) 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 1
# AM_AUTOMAKE_VERSION(VERSION) # AM_AUTOMAKE_VERSION(VERSION)
# ---------------------------- # ----------------------------
# Automake X.Y traces this macro to ensure aclocal.m4 has been # 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' [am__api_version='1.11'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to 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. 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 [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. # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], 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_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*- # 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 1
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'. # `$srcdir', `$srcdir/..', or `$srcdir/../..'.
@ -268,14 +274,14 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]]) Usually this means the macro was only invoked conditionally.]])
fi])]) fi])])
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
# Free Software Foundation, Inc. # 2010, 2011 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # 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 # 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, # 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 # 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 # making a dummy file named `D' -- because `-MD' means `put the output
# in D'. # in D'.
rm -rf conftest.dir
mkdir conftest.dir mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're # Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory. # using a relative directory.
@ -379,7 +386,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
break break
fi fi
;; ;;
msvisualcpp | msvcmsys) msvc7 | msvc7msys | msvisualcpp | msvcmsys)
# This compiler won't grok `-c -o', but also, the minuso test has # 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 # not run yet. These depmodes are late enough in the game, and
# so weak that their functioning should not be impacted. # 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 if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp" am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\' AMDEPBACKSLASH='\'
am__nodep='_no'
fi fi
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
AC_SUBST([AMDEPBACKSLASH])dnl AC_SUBST([AMDEPBACKSLASH])dnl
_AM_SUBST_NOTMAKE([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 -*- # Generate code to set up dependency tracking. -*- Autoconf -*-
@ -669,12 +679,15 @@ for _am_header in $config_headers :; do
done done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_INSTALL_SH # AM_PROG_INSTALL_SH
# ------------------ # ------------------
# Define $install_sh. # Define $install_sh.
@ -714,8 +727,8 @@ AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering # From Jim Meyering
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
# Free Software Foundation, Inc. # 2011 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # 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])], [disable], [m4_define([am_maintainer_other], [enable])],
[m4_define([am_maintainer_other], [enable]) [m4_define([am_maintainer_other], [enable])
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) 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 dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode], AC_ARG_ENABLE([maintainer-mode],
[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful [ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
@ -846,12 +859,15 @@ else
fi 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_MKDIR_P # AM_PROG_MKDIR_P
# --------------- # ---------------
# Check for `mkdir -p'. # Check for `mkdir -p'.
@ -874,13 +890,14 @@ esac
# Helper functions for option handling. -*- Autoconf -*- # 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 4 # serial 5
# _AM_MANGLE_OPTION(NAME) # _AM_MANGLE_OPTION(NAME)
# ----------------------- # -----------------------
@ -888,13 +905,13 @@ AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME) # _AM_SET_OPTION(NAME)
# ------------------------------ # --------------------
# Set option NAME. Presently that only means defining a flag for this option. # Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION], AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) [m4_define(_AM_MANGLE_OPTION([$1]), 1)])
# _AM_SET_OPTIONS(OPTIONS) # _AM_SET_OPTIONS(OPTIONS)
# ---------------------------------- # ------------------------
# OPTIONS is a space-separated list of Automake options. # OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_SET_OPTIONS],
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
@ -970,12 +987,14 @@ Check your system clock])
fi fi
AC_MSG_RESULT(yes)]) 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 1
# AM_PROG_INSTALL_STRIP # AM_PROG_INSTALL_STRIP
# --------------------- # ---------------------
# One issue with vendor `install' (even GNU) is that you can't # One issue with vendor `install' (even GNU) is that you can't
@ -998,13 +1017,13 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])]) 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
# serial 2 # serial 3
# _AM_SUBST_NOTMAKE(VARIABLE) # _AM_SUBST_NOTMAKE(VARIABLE)
# --------------------------- # ---------------------------
@ -1013,13 +1032,13 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
AC_DEFUN([_AM_SUBST_NOTMAKE]) AC_DEFUN([_AM_SUBST_NOTMAKE])
# AM_SUBST_NOTMAKE(VARIABLE) # AM_SUBST_NOTMAKE(VARIABLE)
# --------------------------- # --------------------------
# Public sister of _AM_SUBST_NOTMAKE. # Public sister of _AM_SUBST_NOTMAKE.
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*- # 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 # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # 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. # a tarball read from stdin.
# $(am__untar) < result.tar # $(am__untar) < result.tar
AC_DEFUN([_AM_PROG_TAR], AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility. [# Always define AMTAR for backward compatibility. Yes, it's still used
AM_MISSING_PROG([AMTAR], [tar]) # in the wild :-( We should find a proper way to deprecate it ...
AC_SUBST([AMTAR], ['$${TAR-tar}'])
m4_if([$1], [v7], 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_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])]) [m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive]) 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/libevent.m4])
m4_include([m4/lzo.m4]) m4_include([m4/lzo.m4])
m4_include([m4/openssl.m4]) m4_include([m4/openssl.m4])
m4_include([m4/readline.m4])
m4_include([m4/zlib.m4]) m4_include([m4/zlib.m4])

49
config.guess vendored
View file

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

View file

@ -6,6 +6,12 @@
/* Support for tunemu */ /* Support for tunemu */
#undef ENABLE_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. */ /* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H #undef HAVE_ARPA_INET_H
@ -52,6 +58,12 @@
/* DragonFly */ /* DragonFly */
#undef HAVE_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. */ /* Define to 1 if you have the <event.h> header file. */
#undef HAVE_EVENT_H #undef HAVE_EVENT_H
@ -88,6 +100,9 @@
/* Define to 1 if you have the `socket' library (-lsocket). */ /* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET #undef HAVE_LIBSOCKET
/* Define to 1 if you have the <libvdeplug_dyn.h> header file. */
#undef HAVE_LIBVDEPLUG_DYN_H
/* Linux */ /* Linux */
#undef HAVE_LINUX #undef HAVE_LINUX
@ -148,6 +163,9 @@
/* Define to 1 if you have the <netinet/tcp.h> header file. */ /* Define to 1 if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H #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. */ /* Define to 1 if you have the <net/ethernet.h> header file. */
#undef HAVE_NET_ETHERNET_H #undef HAVE_NET_ETHERNET_H
@ -175,6 +193,12 @@
/* OpenBSD */ /* OpenBSD */
#undef HAVE_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. */ /* Define to 1 if you have the <openssl/engine.h> header file. */
#undef HAVE_OPENSSL_ENGINE_H #undef HAVE_OPENSSL_ENGINE_H
@ -205,6 +229,15 @@
/* Define to 1 if you have the `RAND_pseudo_bytes' function. */ /* Define to 1 if you have the `RAND_pseudo_bytes' function. */
#undef HAVE_RAND_PSEUDO_BYTES #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. */ /* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT #undef HAVE_SELECT

74
config.sub vendored
View file

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

459
configure vendored
View file

@ -1,11 +1,9 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # 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, # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
# Foundation, Inc.
# #
# #
# This configure script is free software; the Free Software Foundation # This configure script is free software; the Free Software Foundation
@ -134,6 +132,31 @@ export LANGUAGE
# CDPATH. # CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset 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 if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh emulate sh
@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
else else
exitcode=1; echo positional parameters were not saved. exitcode=1; echo positional parameters were not saved.
fi 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_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 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'\" && 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 : 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 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*x* | *x*v* ) as_opts=-vx ;;
*v* ) as_opts=-v ;; *v* ) as_opts=-v ;;
*x* ) as_opts=-x ;; *x* ) as_opts=-x ;;
* ) as_opts= ;; * ) as_opts= ;;
esac esac
exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} 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 fi
if test x$as_have_required = xno; then : if test x$as_have_required = xno; then :
@ -328,6 +356,14 @@ $as_echo X"$as_dir" |
} # as_fn_mkdir_p } # 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 # as_fn_append VAR VALUE
# ---------------------- # ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take # 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" || 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; } { $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 # 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 # (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this). # 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: # ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 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. # 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 || 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 elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln as_ln_s=ln
else else
as_ln_s='cp -p' as_ln_s='cp -pR'
fi fi
else else
as_ln_s='cp -p' as_ln_s='cp -pR'
fi fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null rmdir conf$$.dir 2>/dev/null
@ -504,28 +544,8 @@ else
as_mkdir_p=false as_mkdir_p=false
fi fi
if test -x / >/dev/null 2>&1; then as_test_x='test -x'
as_test_x='test -x' as_executable_p=as_fn_executable_p
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
# Sed expression to map a string onto a valid CPP name. # 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'" 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_LIBS
LIBGCRYPT_CFLAGS LIBGCRYPT_CFLAGS
LIBGCRYPT_CONFIG LIBGCRYPT_CONFIG
READLINE_LIBS
CURSES_LIBS CURSES_LIBS
TUNEMU_FALSE TUNEMU_FALSE
TUNEMU_TRUE TUNEMU_TRUE
VDE_FALSE
VDE_TRUE
UML_FALSE
UML_TRUE
host_os host_os
host_vendor host_vendor
host_cpu host_cpu
@ -626,6 +651,7 @@ MAINTAINER_MODE_TRUE
am__fastdepCC_FALSE am__fastdepCC_FALSE
am__fastdepCC_TRUE am__fastdepCC_TRUE
CCDEPMODE CCDEPMODE
am__nodep
AMDEPBACKSLASH AMDEPBACKSLASH
AMDEP_FALSE AMDEP_FALSE
AMDEP_TRUE AMDEP_TRUE
@ -708,6 +734,8 @@ ac_user_opts='
enable_option_checking enable_option_checking
enable_dependency_tracking enable_dependency_tracking
enable_maintainer_mode enable_maintainer_mode
enable_uml
enable_vde
enable_tunemu enable_tunemu
with_windows2000 with_windows2000
with_libgcrypt with_libgcrypt
@ -715,6 +743,10 @@ enable_curses
with_curses with_curses
with_curses_include with_curses_include
with_curses_lib with_curses_lib
enable_readline
with_readline
with_readline_include
with_readline_lib
with_libevent with_libevent
with_libevent_include with_libevent_include
with_libevent_lib with_libevent_lib
@ -1196,8 +1228,6 @@ target=$target_alias
if test "x$host_alias" != x; then if test "x$host_alias" != x; then
if test "x$build_alias" = x; then if test "x$build_alias" = x; then
cross_compiling=maybe 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 elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes cross_compiling=yes
fi fi
@ -1363,23 +1393,30 @@ Optional Features:
--enable-dependency-tracking do not reject slow dependency extractors --enable-dependency-tracking do not reject slow dependency extractors
--enable-maintainer-mode enable make rules and dependencies not useful --enable-maintainer-mode enable make rules and dependencies not useful
(and sometimes confusing) to the casual installer (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-curses disable curses support
--disable-readline disable readline support
--disable-zlib disable zlib compression support --disable-zlib disable zlib compression support
--disable-lzo disable lzo 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) bytes)
Optional Packages: Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --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. support for tunneling over existing IPv6 networks.
--with-libgcrypt enable use of libgcrypt instead of OpenSSL] --with-libgcrypt enable use of libgcrypt instead of OpenSSL]
--with-curses=DIR curses base directory, or: --with-curses=DIR curses base directory, or:
--with-curses-include=DIR --with-curses-include=DIR
curses headers directory curses headers directory
--with-curses-lib=DIR curses library 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=DIR libevent base directory, or:
--with-libevent-include=DIR --with-libevent-include=DIR
libevent headers directory libevent headers directory
@ -1475,9 +1512,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
configure 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 This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it. gives unlimited permission to copy, distribute and modify it.
_ACEOF _ACEOF
@ -1804,7 +1841,7 @@ $as_echo "$ac_try_echo"; } >&5
test ! -s conftest.err test ! -s conftest.err
} && test -s conftest$ac_exeext && { } && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes || test "$cross_compiling" = yes ||
$as_test_x conftest$ac_exeext test -x conftest$ac_exeext
}; then : }; then :
ac_retval=0 ac_retval=0
else else
@ -1940,7 +1977,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was 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 $@ $ $0 $@
@ -2310,7 +2347,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -2350,7 +2387,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -2403,7 +2440,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -2444,7 +2481,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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 if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes ac_prog_rejected=yes
continue continue
@ -2502,7 +2539,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" 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 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -2546,7 +2583,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -2992,8 +3029,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */ /* end confdefs.h. */
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> struct stat;
#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; }; struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int); FILE * (*rcsopen) (struct buf *, struct stat *, int);
@ -3233,7 +3269,7 @@ do
for ac_prog in grep ggrep; do for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" 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 and select it if it is found.
# Check for GNU $ac_path_GREP # Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in case `"$ac_path_GREP" --version 2>&1` in
@ -3299,7 +3335,7 @@ do
for ac_prog in egrep; do for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" 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 and select it if it is found.
# Check for GNU $ac_path_EGREP # Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in case `"$ac_path_EGREP" --version 2>&1` in
@ -3606,7 +3642,7 @@ case $as_dir/ in #((
# by default. # by default.
for ac_prog in ginstall scoinst install; do for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; 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 && if test $ac_prog = install &&
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention. # AIX install. It has an incompatible calling convention.
@ -3775,7 +3811,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_STRIP="${ac_tool_prefix}strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -3815,7 +3851,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_ac_ct_STRIP="strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -3866,7 +3902,7 @@ do
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_prog in mkdir gmkdir; do for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; 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 #( case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
'mkdir (GNU coreutils) '* | \ 'mkdir (GNU coreutils) '* | \
'mkdir (coreutils) '* | \ 'mkdir (coreutils) '* | \
@ -3919,7 +3955,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -4035,6 +4071,7 @@ fi
if test "x$enable_dependency_tracking" != xno; then if test "x$enable_dependency_tracking" != xno; then
am_depcomp="$ac_aux_dir/depcomp" am_depcomp="$ac_aux_dir/depcomp"
AMDEPBACKSLASH='\' AMDEPBACKSLASH='\'
am__nodep='_no'
fi fi
if test "x$enable_dependency_tracking" != xno; then if test "x$enable_dependency_tracking" != xno; then
AMDEP_TRUE= AMDEP_TRUE=
@ -4067,7 +4104,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE=tinc PACKAGE=tinc
VERSION=1.1pre2 VERSION=1.1pre3
cat >>confdefs.h <<_ACEOF 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 # We need awk for the "check" target. The system "awk" is bad on
# some platforms. # 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='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
@ -4119,6 +4156,7 @@ else
# instance it was reported that on HP-UX the gcc test will end up # 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 # making a dummy file named `D' -- because `-MD' means `put the output
# in D'. # in D'.
rm -rf conftest.dir
mkdir conftest.dir mkdir conftest.dir
# Copy depcomp to subdir because otherwise we won't find it if we're # Copy depcomp to subdir because otherwise we won't find it if we're
# using a relative directory. # using a relative directory.
@ -4178,7 +4216,7 @@ else
break break
fi fi
;; ;;
msvisualcpp | msvcmsys) msvc7 | msvc7msys | msvisualcpp | msvcmsys)
# This compiler won't grok `-c -o', but also, the minuso test has # 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 # not run yet. These depmodes are late enough in the game, and
# so weak that their functioning should not be impacted. # so weak that their functioning should not be impacted.
@ -4414,7 +4452,7 @@ main ()
return 0; return 0;
} }
_ACEOF _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 do
CC="$ac_save_CC $ac_arg" CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"; then : if ac_fn_c_try_compile "$LINENO"; then :
@ -4611,7 +4649,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -4651,7 +4689,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" ac_cv_prog_ac_ct_RANLIB="ranlib"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -4829,13 +4867,70 @@ $as_echo "#define HAVE_MINGW 1" >>confdefs.h
;; ;;
esac 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. # Check whether --enable-tunemu was given.
if test "${enable_tunemu+set}" = set; then : 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 $as_echo "#define ENABLE_TUNEMU 1" >>confdefs.h
tunemu=true tunemu=true
else
tunemu=false
fi
else
tunemu=false
fi fi
@ -4843,13 +4938,32 @@ fi
# Check whether --with-windows2000 was given. # Check whether --with-windows2000 was given.
if test "${with_windows2000+set}" = set; then : 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 $as_echo "#define WITH_WINDOWS2000 1" >>confdefs.h
fi
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 if test "$tunemu" = true; then
TUNEMU_TRUE= TUNEMU_TRUE=
TUNEMU_FALSE='#' TUNEMU_FALSE='#'
@ -5078,7 +5192,7 @@ fi
done 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 : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` 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\" ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"have.h\"
@ -5135,11 +5249,11 @@ else
int int
main () main ()
{ {
/* FIXME: Include the comments suggested by Paul. */
#ifndef __cplusplus #ifndef __cplusplus
/* Ultrix mips cc rejects this. */ /* Ultrix mips cc rejects this sort of thing. */
typedef int charset[2]; typedef int charset[2];
const charset cs; const charset cs = { 0, 0 };
/* SunOS 4.1.1 cc rejects this. */ /* SunOS 4.1.1 cc rejects this. */
char const *const *pcpcc; char const *const *pcpcc;
char **ppc; char **ppc;
@ -5156,8 +5270,9 @@ main ()
++pcpcc; ++pcpcc;
ppc = (char**) pcpcc; ppc = (char**) pcpcc;
pcpcc = (char const *const *) ppc; pcpcc = (char const *const *) ppc;
{ /* SCO 3.2v4 cc rejects this. */ { /* SCO 3.2v4 cc rejects this sort of thing. */
char *t; char tx;
char *t = &tx;
char const *s = 0 ? (char *) 0 : (char const *) 0; char const *s = 0 ? (char *) 0 : (char const *) 0;
*t++ = 0; *t++ = 0;
@ -5173,10 +5288,10 @@ main ()
iptr p = 0; iptr p = 0;
++p; ++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. */ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
struct s { int j; const int *ap[3]; }; struct s { int j; const int *ap[3]; } bx;
struct s *b; b->j = 5; struct s *b = &bx; b->j = 5;
} }
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10; 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. # Check whether --with-libevent was given.
if test "${with_libevent+set}" = set; then : if test "${with_libevent+set}" = set; then :
@ -6326,7 +6546,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" 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 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -6369,7 +6589,7 @@ do
IFS=$as_save_IFS IFS=$as_save_IFS
test -z "$as_dir" && as_dir=. test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do 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" 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 $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2 break 2
@ -6596,7 +6816,7 @@ if test "${with_openssl_lib+set}" = set; then :
fi 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 : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` 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" ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@ -6657,7 +6877,7 @@ else
fi 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 : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -6688,9 +6908,12 @@ fi
# Check whether --enable-jumbograms was given. # Check whether --enable-jumbograms was given.
if test "${enable_jumbograms+set}" = set; then : 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 $as_echo "#define ENABLE_JUMBOGRAMS 1" >>confdefs.h
fi
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. as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi 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 if test -z "${TUNEMU_TRUE}" && test -z "${TUNEMU_FALSE}"; then
as_fn_error $? "conditional \"TUNEMU\" was never defined. as_fn_error $? "conditional \"TUNEMU\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 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: # ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 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. # 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 || 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 elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln as_ln_s=ln
else else
as_ln_s='cp -p' as_ln_s='cp -pR'
fi fi
else else
as_ln_s='cp -p' as_ln_s='cp -pR'
fi fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null rmdir conf$$.dir 2>/dev/null
@ -7200,28 +7431,16 @@ else
as_mkdir_p=false as_mkdir_p=false
fi fi
if test -x / >/dev/null 2>&1; then
as_test_x='test -x' # as_fn_executable_p FILE
else # -----------------------
if ls -dL / >/dev/null 2>&1; then # Test if FILE is an executable regular file.
as_ls_L_option=L as_fn_executable_p ()
else {
as_ls_L_option= test -f "$1" && test -x "$1"
fi } # as_fn_executable_p
as_test_x=' as_test_x='test -x'
eval sh -c '\'' as_executable_p=as_fn_executable_p
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
# Sed expression to map a string onto a valid CPP name. # 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'" 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. # values after options handling.
ac_log=" ac_log="
This file was extended by $as_me, which was 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_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS 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_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
config.status 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\\" 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 This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it." gives unlimited permission to copy, distribute and modify it."
@ -7403,7 +7622,7 @@ fi
_ACEOF _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then 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 shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL' CONFIG_SHELL='$SHELL'

View file

@ -4,7 +4,7 @@ AC_PREREQ(2.61)
AC_INIT AC_INIT
AC_CONFIG_SRCDIR([src/tincd.c]) AC_CONFIG_SRCDIR([src/tincd.c])
AC_GNU_SOURCE AC_GNU_SOURCE
AM_INIT_AUTOMAKE(tinc, 1.1pre2) AM_INIT_AUTOMAKE(tinc, 1.1pre3)
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE AM_MAINTAINER_MODE
@ -73,18 +73,49 @@ case $host_os in
;; ;;
esac 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, 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]) [ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
tunemu=true tunemu=true
] ],
[tunemu=false])
],
[tunemu=false]
) )
AC_ARG_WITH(windows2000, AC_ARG_WITH(windows2000,
AS_HELP_STRING([--with-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]), AS_HELP_STRING([--without-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_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) AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
AC_CACHE_SAVE 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_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([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"] [], [], [#include "have.h"]
) )
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.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])], []) AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
tinc_CURSES tinc_CURSES
tinc_READLINE
tinc_LIBEVENT tinc_LIBEVENT
tinc_ZLIB tinc_ZLIB
tinc_LZO tinc_LZO
@ -166,8 +198,10 @@ fi
dnl Check if support for jumbograms is requested dnl Check if support for jumbograms is requested
AC_ARG_ENABLE(jumbograms, AC_ARG_ENABLE(jumbograms,
AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]), AS_HELP_STRING([--disable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [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) AC_SUBST(INCLUDES)

2
debian/NEWS vendored
View file

@ -1,6 +1,6 @@
tinc (1.1~pre2-1) experimental; urgency=low 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 to start/stop tinc instances, to reload configuration, to get
various information about running tincd (including dump of nodes various information about running tincd (including dump of nodes
and connections) and so on. tincd still reacts to some signals 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 tinc (1.1~pre2-2) experimental; urgency=low
* add forgotten build-depend on libncurses5-dev for new `tincctl top' * 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 Section: net
Priority: optional Priority: optional
Maintainer: Guus Sliepen <guus@debian.org> Maintainer: Guus Sliepen <guus@debian.org>
Standards-Version: 3.9.2 Standards-Version: 3.9.3
Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 7.0.50~), texi2html, texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libevent-dev 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/ Homepage: http://www.tinc-vpn.org/
Package: tinc Package: tinc
@ -14,3 +14,15 @@ Description: Virtual Private Network daemon
(VPN). One daemon can handle multiple connections, so you can (VPN). One daemon can handle multiple connections, so you can
create an entire (moderately sized) VPN with only one daemon per create an entire (moderately sized) VPN with only one daemon per
participating computer. 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. # Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1 #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: override_dh_auto_build:
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 #! /bin/sh
# depcomp - compile a program generating dependencies as side-effects # 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 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# Software Foundation, Inc. # 2011, 2012 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -28,7 +28,7 @@ scriptversion=2009-04-28.21; # UTC
case $1 in 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; exit 1;
;; ;;
-h | --h*) -h | --h*)
@ -40,11 +40,11 @@ as side-effects.
Environment variables: Environment variables:
depmode Dependency tracking mode. depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'. source Source file read by 'PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies. DEPDIR directory where to store dependencies.
depfile Dependency file to output. 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). libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>. Report bugs to <bug-automake@gnu.org>.
@ -57,6 +57,12 @@ EOF
;; ;;
esac esac
# A tabulation character.
tab=' '
# A newline character.
nl='
'
if test -z "$depmode" || test -z "$source" || test -z "$object"; then if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2 echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1 exit 1
@ -90,10 +96,24 @@ if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation. # This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward # Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4 # slashes to satisfy depend.m4
cygpath_u="sed s,\\\\\\\\,/,g" cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp depmode=msvisualcpp
fi 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 case "$depmode" in
gcc3) gcc3)
## gcc 3 implements dependency tracking that does exactly what ## 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. ## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \ sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" -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 ## 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 ## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding ## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do ## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly. ## this for us directly.
tr ' ' ' tr ' ' "$nl" < "$tmpdepfile" |
' < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory
## 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 ## 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 ## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround. ## 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" rm -f "$tmpdepfile"
;; ;;
@ -193,18 +214,15 @@ sgi)
# clever and replace this with sed code, as IRIX sed won't handle # clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in # 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; # 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. # dependency line.
tr ' ' ' tr ' ' "$nl" < "$tmpdepfile" \
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr ' tr "$nl" ' ' >> "$depfile"
' ' ' >> "$depfile"
echo >> "$depfile" echo >> "$depfile"
# The second pass generates a dummy entry for each header file. # The second pass generates a dummy entry for each header file.
tr ' ' ' tr ' ' "$nl" < "$tmpdepfile" \
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile" >> "$depfile"
else else
@ -216,10 +234,17 @@ sgi)
rm -f "$tmpdepfile" 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) aix)
# The C for AIX Compiler uses -M and outputs the dependencies # The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the # 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. # start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases. # Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
@ -249,12 +274,11 @@ aix)
test -f "$tmpdepfile" && break test -f "$tmpdepfile" && break
done done
if test -f "$tmpdepfile"; then 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 # 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" sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else else
# The sourcefile does not contain any dependencies, so just # The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile # store a dummy comment line, to avoid errors with the Makefile
@ -265,23 +289,26 @@ aix)
;; ;;
icc) icc)
# Intel's C compiler understands `-MD -MF file'. However on # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # 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 # ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c # foo.o: sub/foo.c
# foo.o: sub/foo.h # 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.c
# sub/foo.o: sub/foo.h # sub/foo.o: sub/foo.h
# sub/foo.c: # sub/foo.c:
# sub/foo.h: # sub/foo.h:
# ICC 7.1 will output # ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h # 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 ... \ # foo.o: sub/foo.c ... \
# sub/foo.h ... \ # 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" "$@" -MD -MF "$tmpdepfile"
stat=$? stat=$?
if test $stat -eq 0; then : if test $stat -eq 0; then :
@ -290,15 +317,21 @@ icc)
exit $stat exit $stat
fi fi
rm -f "$depfile" rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h', # Each line is of the form 'foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
# Do two passes, one to just change these to # 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 "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
# Some versions of the HPUX 10.20 sed can't process this invocation < "$tmpdepfile" > "$depfile"
# correctly. Breaking it into two sed invocations is a workaround. sed '
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | s/[ '"$tab"'][ '"$tab"']*/ /g
sed -e 's/$/ :/' >> "$depfile" s/^ *//
s/ *\\*$//
s/^[^:]*: *//
/^$/d
/:$/d
s/$/ :/
' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile" rm -f "$tmpdepfile"
;; ;;
@ -334,7 +367,7 @@ hp2)
done done
if test -f "$tmpdepfile"; then if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add `dependent.h:' lines. # Add 'dependent.h:' lines.
sed -ne '2,${ sed -ne '2,${
s/^ *// s/^ *//
s/ \\*$// s/ \\*$//
@ -349,9 +382,9 @@ hp2)
tru64) tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side # 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 # 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. # Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir= test "x$dir" = "x$object" && dir=
@ -397,14 +430,59 @@ tru64)
done done
if test -f "$tmpdepfile"; then if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else else
echo "#dummy" > "$depfile" echo "#dummy" > "$depfile"
fi fi
rm -f "$tmpdepfile" 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) #nosideeffect)
# This comment above is used by automake to tell side-effect # This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones. # dependency tracking mechanisms from slower ones.
@ -422,7 +500,7 @@ dashmstdout)
shift shift
fi fi
# Remove `-o $object'. # Remove '-o $object'.
IFS=" " IFS=" "
for arg for arg
do do
@ -442,15 +520,14 @@ dashmstdout)
done done
test -z "$dashmflag" && dashmflag=-M 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: # 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 | "$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile" rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile" cat < "$tmpdepfile" > "$depfile"
tr ' ' ' tr ' ' "$nl" < "$tmpdepfile" | \
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation ## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround. ## 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 '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@ -503,9 +580,10 @@ makedepend)
touch "$tmpdepfile" touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile" rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile" # makedepend may prepend the VPATH from the source file name to the object.
sed '1,2d' "$tmpdepfile" | tr ' ' ' # 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 ## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround. ## 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 '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@ -525,7 +603,7 @@ cpp)
shift shift
fi fi
# Remove `-o $object'. # Remove '-o $object'.
IFS=" " IFS=" "
for arg for arg
do do
@ -594,8 +672,8 @@ msvisualcpp)
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile" rm -f "$depfile"
echo "$object : \\" > "$depfile" echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo " " >> "$depfile" echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile" rm -f "$tmpdepfile"
;; ;;

View file

@ -23,16 +23,16 @@ texi2html: tinc.texi
texi2html -split=chapter tinc.texi texi2html -split=chapter tinc.texi
tincd.8.html: tincd.8 tincd.8.html: tincd.8
w3mman2html $< > $@ w3mman2html $? > $@
tincctl.8.html: tincctl.8 tincctl.8.html: tincctl.8
w3mman2html $< > $@ w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8 tinc-gui.8.html: tinc-gui.8
w3mman2html $< > $@ w3mman2html $? > $@
tinc.conf.5.html: tinc.conf.5 tinc.conf.5.html: tinc.conf.5
w3mman2html $< > $@ w3mman2html $? > $@
substitute = sed \ substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \ -e s,'@PACKAGE\@',"$(PACKAGE)",g \
@ -41,18 +41,18 @@ substitute = sed \
-e s,'@localstatedir\@',"$(localstatedir)",g -e s,'@localstatedir\@',"$(localstatedir)",g
tincd.8: tincd.8.in tincd.8: tincd.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tincctl.8: tincctl.8.in tincctl.8: tincctl.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in tinc-gui.8: tinc-gui.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc.conf.5: tinc.conf.5.in tinc.conf.5: tinc.conf.5.in
$(substitute) $< > $@ $(substitute) $? > $@
tincinclude.texi: tincinclude.texi.in tincinclude.texi: tincinclude.texi.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc.texi: tincinclude.texi 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@ # @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Inc. # Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@ @SET_MAKE@
VPATH = @srcdir@ 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@ pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@
@ -38,7 +55,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.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) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d mkinstalldirs = $(install_sh) -d
@ -59,6 +77,11 @@ TEXI2PDF = $(TEXI2DVI) --pdf --batch
MAKEINFOHTML = $(MAKEINFO) --html MAKEINFOHTML = $(MAKEINFO) --html
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
DVIPS = dvips 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)" \ am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man5dir)" \
"$(DESTDIR)$(man8dir)" "$(DESTDIR)$(man8dir)"
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@ -82,6 +105,12 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!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 man5dir = $(mandir)/man5
man8dir = $(mandir)/man8 man8dir = $(mandir)/man8
NROFF = nroff NROFF = nroff
@ -140,6 +169,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
STRIP = @STRIP@ STRIP = @STRIP@
@ -304,9 +334,7 @@ uninstall-html-am:
uninstall-info-am: uninstall-info-am:
@$(PRE_UNINSTALL) @$(PRE_UNINSTALL)
@if test -d '$(DESTDIR)$(infodir)' && \ @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
(install-info --version && \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
list='$(INFO_DEPS)'; \ list='$(INFO_DEPS)'; \
for file in $$list; do \ for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile=`echo "$$file" | sed 's|^.*/||'`; \
@ -379,11 +407,18 @@ maintainer-clean-aminfo:
done done
install-man5: $(man_MANS) install-man5: $(man_MANS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" @list1=''; \
@list=''; test -n "$(man5dir)" || exit 0; \ list2='$(man_MANS)'; \
{ for i in $$list; do echo "$$i"; done; \ test -n "$(man5dir)" \
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ && test -n "`echo $$list1$$list2`" \
sed -n '/\.5[a-z]*$$/p'; \ || 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 \ } | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \ echo "$$d$$p"; echo "$$p"; \
@ -412,16 +447,21 @@ uninstall-man5:
sed -n '/\.5[a-z]*$$/p'; \ sed -n '/\.5[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
test -z "$$files" || { \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
install-man8: $(man_MANS) install-man8: $(man_MANS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @list1=''; \
@list=''; test -n "$(man8dir)" || exit 0; \ list2='$(man_MANS)'; \
{ for i in $$list; do echo "$$i"; done; \ test -n "$(man8dir)" \
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ && test -n "`echo $$list1$$list2`" \
sed -n '/\.8[a-z]*$$/p'; \ || 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 \ } | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \ echo "$$d$$p"; echo "$$p"; \
@ -450,9 +490,7 @@ uninstall-man8:
sed -n '/\.8[a-z]*$$/p'; \ sed -n '/\.8[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
test -z "$$files" || { \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(man8dir)" && rm -f $$files; }
tags: TAGS tags: TAGS
TAGS: TAGS:
@ -523,10 +561,15 @@ install-am: all-am
installcheck: installcheck-am installcheck: installcheck-am
install-strip: install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \ install; \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` 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: mostlyclean-generic:
clean-generic: clean-generic:
@ -565,8 +608,11 @@ install-dvi: install-dvi-am
install-dvi-am: $(DVIS) install-dvi-am: $(DVIS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)"
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \ @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 \ for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \ echo "$$d$$p"; \
@ -581,18 +627,22 @@ install-html: install-html-am
install-html-am: $(HTMLS) install-html-am: $(HTMLS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)"
@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ @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 \ for p in $$list; do \
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
$(am__strip_dir) \ $(am__strip_dir) \
if test -d "$$d$$p"; then \ d2=$$d$$p; \
if test -d "$$d2"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
else \ else \
list2="$$list2 $$d$$p"; \ list2="$$list2 $$d2"; \
fi; \ fi; \
done; \ done; \
test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
@ -604,9 +654,12 @@ install-info: install-info-am
install-info-am: $(INFO_DEPS) install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ 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 \ for file in $$list; do \
case $$file in \ case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
@ -624,8 +677,7 @@ install-info-am: $(INFO_DEPS)
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
@$(POST_INSTALL) @$(POST_INSTALL)
@if (install-info --version && \ @if $(am__can_run_installinfo); then \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
for file in $$list; do \ for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile=`echo "$$file" | sed 's|^.*/||'`; \
@ -639,8 +691,11 @@ install-pdf: install-pdf-am
install-pdf-am: $(PDFS) install-pdf-am: $(PDFS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)"
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ @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 \ for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \ echo "$$d$$p"; \
@ -652,8 +707,11 @@ install-ps: install-ps-am
install-ps-am: $(PSS) install-ps-am: $(PSS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)"
@list='$(PSS)'; test -n "$(psdir)" || list=; \ @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 \ for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \ echo "$$d$$p"; \
@ -713,31 +771,31 @@ texi2html: tinc.texi
texi2html -split=chapter tinc.texi texi2html -split=chapter tinc.texi
tincd.8.html: tincd.8 tincd.8.html: tincd.8
w3mman2html $< > $@ w3mman2html $? > $@
tincctl.8.html: tincctl.8 tincctl.8.html: tincctl.8
w3mman2html $< > $@ w3mman2html $? > $@
tinc-gui.8.html: tinc-gui.8 tinc-gui.8.html: tinc-gui.8
w3mman2html $< > $@ w3mman2html $? > $@
tinc.conf.5.html: tinc.conf.5 tinc.conf.5.html: tinc.conf.5
w3mman2html $< > $@ w3mman2html $? > $@
tincd.8: tincd.8.in tincd.8: tincd.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tincctl.8: tincctl.8.in tincctl.8: tincctl.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc-gui.8: tinc-gui.8.in tinc-gui.8: tinc-gui.8.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc.conf.5: tinc.conf.5.in tinc.conf.5: tinc.conf.5.in
$(substitute) $< > $@ $(substitute) $? > $@
tincinclude.texi: tincinclude.texi.in tincinclude.texi: tincinclude.texi.in
$(substitute) $< > $@ $(substitute) $? > $@
tinc.texi: tincinclude.texi 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 .Dt TINC.CONF 5
.\" Manual page created by: .\" Manual page created by:
.\" Ivo Timmermans .\" Ivo Timmermans
@ -14,22 +14,12 @@ The files in the
directory contain runtime and security information for the tinc daemon. directory contain runtime and security information for the tinc daemon.
.Sh NETWORKS .Sh NETWORKS
It is perfectly ok for you to run more than one tinc daemon. To distinguish multiple instances of tinc running on one computer,
However, in its default form, you can use the
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
.Fl n .Fl n
option, which will assign a name to this daemon. option to assign a network name to each tinc daemon.
.Pp .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 / , .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
where where
.Ar NETNAME .Ar NETNAME
@ -37,14 +27,14 @@ is your argument to the
.Fl n .Fl n
option. option.
You'll notice that messages appear in syslog as coming from You'll notice that messages appear in syslog as coming from
.Nm tincd. Ns Ar NETNAME . .Nm tincd. Ns Ar NETNAME ,
and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name.
.Pp .Pp
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 .Fl n
option. option.
In this case, the network name would just be empty, In this case, the network name would just be empty, and
and it will be used as such.
.Nm tinc .Nm tinc
now looks for files in now looks for files in
.Pa @sysconfdir@/tinc/ , .Pa @sysconfdir@/tinc/ ,
@ -55,12 +45,6 @@ the configuration file should be
and the host configuration files are now expected to be in and the host configuration files are now expected to be in
.Pa @sysconfdir@/tinc/hosts/ . .Pa @sysconfdir@/tinc/hosts/ .
.Pp
But it is highly recommended that you use this feature of
.Nm tinc ,
because it will be so much clearer whom your daemon talks to.
Hence, we will assume that you use it.
.Sh NAMES .Sh NAMES
Each tinc daemon should have a name that is unique in the network which it will be part of. 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. The name will be used by other tinc daemons for identification.
@ -72,25 +56,38 @@ file.
To make things easy, To make things easy,
choose something that will give unique and easy to remember names to your tinc daemon(s). choose something that will give unique and easy to remember names to your tinc daemon(s).
You could try things like hostnames, owner surnames or location names. You could try things like hostnames, owner surnames or location names.
However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-9) and underscores (_) in the name.
.Sh INITIAL CONFIGURATION
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
.Bd -literal -offset indent
.Nm 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 .Sh PUBLIC/PRIVATE KEYS
You should use The
.Ic tincd -K .Nm tincctl Li init
to generate public/private keypairs. command will have generated both RSA and ECDSA public/private keypairs.
It will generate two keys. The private keys should be stored in files named
The private key should be stored in a separate file .Pa rsa_key.priv
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv and
\-\- where .Pa ecdsa_key.priv
.Ar NETNAME in the directory
stands for the network (see .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /
.Sx NETWORKS ) The public keys should be stored in the host configuration file
above. .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME .
The public key 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.
\-\- where If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files,
.Va NAME but you will need to create ECDSA keys using the following command:
stands for the name of the local tinc daemon (see .Bd -literal -offset indent
.Sx NAMES ) . .Nm tincctl Fl n Ar NETNAME Li generate-ecdsa-keys
.Ed
.Sh SERVER CONFIGURATION .Sh SERVER CONFIGURATION
The server configuration of the daemon is done in the file The server configuration of the daemon is done in the file
@ -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, it is recommended to put host specific configuration options in the host configuration file,
as this makes it easy to exchange with other nodes. as this makes it easy to exchange with other nodes.
.Pp
You can edit the config file manually, but it is recommended that you use
.Xr tincctl 8
to change configuration variables for you.
.Pp .Pp
Here are all valid variables, listed in alphabetical order. Here are all valid variables, listed in alphabetical order.
The default value is given between parentheses. 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 is selected, then depending on the operating system both IPv4 and IPv6 or just
IPv6 listening sockets will be created. IPv6 listening sockets will be created.
.It Va 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, If your computer has more than one IPv4 or IPv6 address,
.Nm tinc .Nm tinc
will by default listen on all of them for incoming connections. 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 .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 .It Va BindToInterface Li = Ar interface Bq experimental
If your computer has more than one network interface, If your computer has more than one network interface,
@ -146,6 +158,28 @@ It is possible to bind only to a single interface with this variable.
.Pp .Pp
This option may not work on all platforms. 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 .It Va ConnectTo Li = Ar name
Specifies which other tinc daemon to connect to on startup. Specifies which other tinc daemon to connect to on startup.
@ -165,6 +199,16 @@ If you don't specify a host with
won't try to connect to other daemons at all, won't try to connect to other daemons at all,
and will instead just listen for incoming connections. and will instead just listen for incoming connections.
.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 .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. The virtual network device to use.
.Nm tinc .Nm tinc
@ -177,30 +221,75 @@ instead of
The info pages of the tinc package contain more information The info pages of the tinc package contain more information
about configuring the virtual network device. about configuring the virtual network device.
.It Va 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. The type of the virtual network device.
Tinc will normally automatically select the right type, and this option should not be used. Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
However, in case tinc does not seem to correctly interpret packets received from the virtual network device, However, this option can be used to select one of the special interface types, if support for them is compiled in.
using this option might help.
.Bl -tag -width indent .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. Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below). 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. 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. 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. 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. Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family, to start with a four byte header containing the address family,
followed by an IP header. followed by an IP header.
This mode should support both IPv4 and IPv6 packets. This mode should support both IPv4 and IPv6 packets.
.It tap .It tap Pq BSD and Linux
Set type to tap. Set type to tap.
Tinc will expect packets read from the virtual network device Tinc will expect packets read from the virtual network device
to start with an Ethernet header. 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. and can also help debugging.
.El .El
.It Va GraphDumpFile Li = Ar filename Bq experimental .It Va GraphDumpFile Li = Ar filename
If this option is present, If this option is present,
.Nm tinc .Nm tinc
will dump the current network graph to the file will dump the current network graph to the file
@ -268,7 +357,7 @@ a lookup if your DNS server is not responding.
.Pp .Pp
This does not affect resolving hostnames to IP addresses from the 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 .It Va IffOneQueue Li = yes | no Po no Pc Bq experimental
(Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices. (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, It is common practice to change keys at regular intervals to make it even harder for crackers,
even though it is thought to be nearly impossible to crack a single key. even though it is thought to be nearly impossible to crack a single key.
.It Va 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 .It Va MACExpire Li = Ar seconds Pq 600
This option controls the amount of time MAC addresses are kept before they are removed. This option controls the amount of time MAC addresses are kept before they are removed.
This only has effect when This only has effect when
@ -327,6 +428,19 @@ while no routing table is managed.
.It Va Name Li = Ar name Bq required .It Va Name Li = Ar name Bq required
This is the name which identifies this tinc daemon. This is the name which identifies this tinc daemon.
It must be unique for the virtual private network this daemon will connect to. It must be unique for the virtual private network this daemon will connect to.
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 .It Va PingInterval Li = Ar seconds Pq 60
The number of seconds of inactivity that The number of seconds of inactivity that
@ -356,11 +470,46 @@ or
specified in the configuration file. specified in the configuration file.
.It Va ProcessPriority Li = low | normal | high .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. 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 .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 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 the default setting of 16 will track up to 128 packets in the window. In high
bandwidth scenarios, setting this to a higher value can reduce packet loss from bandwidth scenarios, setting this to a higher value can reduce packet loss from
@ -406,7 +555,7 @@ Since host configuration files only contain public keys,
no secrets are revealed by sending out this information. no secrets are revealed by sending out this information.
.Bl -tag -width indent .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. 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. 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. 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, Subnets can either be single MAC, IPv4 or IPv6 addresses,
in which case a subnet consisting of only that single address is assumed, 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. 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, 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. 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! Note that subnets like 192.168.1.1/24 are invalid!
Read a networking HOWTO/FAQ/guide if you don't understand this. 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. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
.Pp .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. When a subnet becomes (un)reachable, this is set to the subnet weight.
.El .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 .Sh FILES
The most important files are: The most important files are:
.Bl -tag -width indent .Bl -tag -width indent
@ -636,8 +788,9 @@ its connection to the virtual network device.
.Sh SEE ALSO .Sh SEE ALSO
.Xr tincd 8 , .Xr tincd 8 ,
.Xr tincctl 8 ,
.Pa http://www.tinc-vpn.org/ , .Pa http://www.tinc-vpn.org/ ,
.Pa http://www.linuxdoc.org/LDP/nag2/ . .Pa http://www.tldp.org/LDP/nag2/ .
.Pp .Pp
The full documentation for 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. 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 Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>. Wessel Dankers <wsl@@tinc-vpn.org>.
@ -39,7 +39,7 @@ permission notice identical to this one.
@vskip 0pt plus 1filll @vskip 0pt plus 1filll
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon. 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 Guus Sliepen <guus@@tinc-vpn.org> and
Wessel Dankers <wsl@@tinc-vpn.org>. Wessel Dankers <wsl@@tinc-vpn.org>.
@ -187,7 +187,7 @@ packets.
@cindex release @cindex release
For an up to date list of supported platforms, please check the list on For an up to date list of supported platforms, please check the list on
our website: our website:
@uref{http://www.tinc-vpn.org/platforms}. @uref{http://www.tinc-vpn.org/platforms/}.
@c @c
@c @c
@ -262,7 +262,7 @@ alias char-major-10-200 tun
@subsection Configuration of FreeBSD kernels @subsection Configuration of FreeBSD kernels
For FreeBSD version 4.1 and higher, tun and tap drivers are included in the default kernel configuration. 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 ================================================================== @c ==================================================================
@ -276,6 +276,7 @@ which adds a tap device to OpenBSD which should work with tinc,
but with recent versions of OpenBSD, but with recent versions of OpenBSD,
a tun device can act as a tap device by setting the link0 option with ifconfig. a tun device can act as a tap device by setting the link0 option with ifconfig.
@c ================================================================== @c ==================================================================
@node Configuration of NetBSD kernels @node Configuration of NetBSD kernels
@subsection 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. of this package.
If you have to install libevent manually, you can get the source code 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 build and install this package are included within the package. Please
make sure you build development and runtime libraries (which is the make sure you build development and runtime libraries (which is the
default). 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 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 for yourself, you can use the source. The source is distributed under
the GNU General Public License (GPL). Download the source from the 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 the checksums of these files listed; you may wish to check these with
md5sum before continuing. 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 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 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: After installation use fink to download and install the following packages:
autoconf25, automake, dlcompat, m4, openssl, zlib and lzo. autoconf25, automake, dlcompat, m4, openssl, zlib and lzo.
@ -638,7 +639,6 @@ tinc 655/udp TINC
* Multiple networks:: * Multiple networks::
* How connections work:: * How connections work::
* Configuration files:: * Configuration files::
* Generating keypairs::
* Network interfaces:: * Network interfaces::
* Example configuration:: * Example configuration::
@end menu @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. Make sure you have an adequate understanding of networks in general.
@cindex Network Administrators Guide @cindex Network Administrators Guide
A good resource on networking is the 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, If you have everything clearly pictured in your mind,
proceed in the following order: 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}). First, create the initial configuration files and public/private keypairs using the following command:
Then generate the keypairs. @example
Finally, distribute the host configuration files. 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. These steps are described in the subsections below.
@ -677,30 +683,29 @@ These steps are described in the subsections below.
@cindex multiple networks @cindex multiple networks
@cindex netname @cindex netname
In order to allow you to run more than one tinc daemon on one computer, 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, for instance if your computer is part of more than one VPN,
you can assign a @var{netname} to your VPN. you can assign a @var{netname} to your VPN.
It is not required if you only run one tinc daemon, 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. but it is recommended that you choose one anyway.
We will asume you use a netname throughout this document. We will asume you use a netname throughout this document.
This means that you call tincd with the -n argument, This means that you call tincctl with the -n argument,
which will assign a netname to this daemon. which will specify the netname.
The effect of this is that the daemon will set its configuration 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 root to @file{@value{sysconfdir}/tinc/@var{netname}/}, where @var{netname} is your argument to the -n option.
option. You'll notice that it appears in syslog as @file{tinc.@var{netname}}. 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 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 option. If you don not use it, the network name will just be empty, and
be used as such. tinc now looks for files in @file{@value{sysconfdir}/tinc/}, instead of tinc will look 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}, @file{@value{sysconfdir}/tinc/@var{netname}/};
and the host configuration files are now expected to be in @file{@value{sysconfdir}/tinc/hosts/}. 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/}.
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.
@c ================================================================== @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. 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. 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 ================================================================== @c ==================================================================
@node Configuration files @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 put host specific configuration options in the host configuration file, as this
makes it easy to exchange with other nodes. makes it easy to exchange with other nodes.
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, The default value is given between parentheses,
other comments are between square brackets. 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. both IPv4 and IPv6 or just IPv6 listening sockets will be created.
@cindex BindToAddress @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 If your computer has more than one IPv4 or IPv6 address, tinc
will by default listen on all of them for incoming connections. 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 @cindex BindToInterface
@item BindToInterface = <@var{interface}> [experimental] @item BindToInterface = <@var{interface}> [experimental]
@ -794,6 +824,27 @@ possible to bind tinc to a single interface like eth0 or ppp0 with this
variable. variable.
This option may not work on all platforms. 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 @cindex ConnectTo
@item ConnectTo = <@var{name}> @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, tinc won't try to connect to other daemons at all,
and will instead just listen for incoming connections. and will instead just listen for incoming connections.
@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 @cindex Device
@item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform) @item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
The virtual network device to use. 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}. See also @ref{Device files}.
@cindex DeviceType @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. The type of the virtual network device.
Tinc will normally automatically select the right type, and this option should not be used. Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
However, in case tinc does not seem to correctly interpret packets received from the virtual network device, However, this option can be used to select one of the special interface types, if support for them is compiled in.
using this option might help.
@table @asis @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. Set type to tun.
Depending on the platform, this can either be with or without an address family header (see below). Depending on the platform, this can either be with or without an address family header (see below).
@cindex tunnohead @cindex tunnohead
@item tunnohead @item tunnohead (BSD)
Set type to tun without an address family header. 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. 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. On some platforms IPv6 packets cannot be read from or written to the device in this mode.
@cindex tunifhead @cindex tunifhead
@item tunifhead @item tunifhead (BSD)
Set type to tun with an address family header. Set type to tun with an address family header.
Tinc will expect packets read from the virtual network device Tinc will expect packets read from the virtual network device
to start with a four byte header containing the address family, to start with a four byte header containing the address family,
followed by an IP header. followed by an IP header.
This mode should support both IPv4 and IPv6 packets. This mode should support both IPv4 and IPv6 packets.
@item tap @item tap (BSD and Linux)
Set type to tap. Set type to tap.
Tinc will expect packets read from the virtual network device Tinc will expect packets read from the virtual network device
to start with an Ethernet header. to start with an Ethernet header.
@ -891,7 +991,7 @@ and can also help debugging.
@end table @end table
@cindex GraphDumpFile @cindex GraphDumpFile
@item GraphDumpFile = <@var{filename}> [experimental] @item GraphDumpFile = <@var{filename}>
If this option is present, If this option is present,
tinc will dump the current network graph to the file @var{filename} tinc will dump the current network graph to the file @var{filename}
every minute, unless there were no changes to the graph. 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. it does a lookup if your DNS server is not responding.
This does not affect resolving hostnames to IP addresses from the 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 @cindex Interface
@item Interface = <@var{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. 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. 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 @cindex Mode
@item Mode = <router|switch|hub> (router) @item Mode = <router|switch|hub> (router)
This option selects the way packets are routed to other daemons. 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. 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 _). 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 @cindex PingInterval
@item PingInterval = <@var{seconds}> (60) @item PingInterval = <@var{seconds}> (60)
The number of seconds of inactivity that tinc will wait before sending a 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. 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. 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 @cindex ReplayWindow
@item ReplayWindow = <bytes> (16) @item ReplayWindow = <bytes> (16)
This is the size of the replay tracking window for each remote node, in bytes. This is the size of the replay tracking window for each remote node, in bytes.
@ -1132,19 +1274,18 @@ Multiple subnet lines can be specified for each daemon.
Subnets can either be single MAC, IPv4 or IPv6 addresses, Subnets can either be single MAC, IPv4 or IPv6 addresses,
in which case a subnet consisting of only that single address is assumed, 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. 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, 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. 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! Note that subnets like 192.168.1.1/24 are invalid!
Read a networking HOWTO/FAQ/guide if you don't understand this. 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. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
@cindex CIDR notation @cindex CIDR notation
Prefixlength is the number of bits set to 1 in the netmask part; for 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 example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes
/22. This conforms to standard CIDR notation as described in /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 A Subnet can be given a weight to indicate its priority over identical Subnets
owned by different nodes. The default weight is 10. Lower values indicate owned by different nodes. The default weight is 10. Lower values indicate
@ -1254,50 +1395,115 @@ When a subnet becomes (un)reachable, this is set to the subnet.
@node How to configure @node How to configure
@subsection 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}. The initial directory structure, configuration files and public/private keypairs are created using the following command:
Adapt the following example to create a basic configuration file:
@example @example
Name = @var{yourname} tincctl -n @var{netname} init @var{name}
Device = @file{/dev/tap0}
@end example @end example
Then, if you know to which other tinc daemon(s) yours is going to connect, (You will need to run this as root, or use "sudo".)
add `ConnectTo' values. This will create the configuration directory @file{@value{sysconfdir}/tinc/@var{netname}.},
and inside it will create another directory named @file{hosts/}.
@subsubheading Step 2. Creating your host configuration file In the configuration directory, it will create the file @file{tinc.conf} with the following contents:
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:
@example @example
Address = your.real.hostname.org Name = @var{name}
Subnet = 192.168.1.0/24
@end example @end example
You can also use an IP address instead of a hostname. 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}.
The `Subnet' specifies the address range that is local for @emph{your part of the VPN only}. It will also create a host configuration file @file{hosts/@var{name}},
If you have multiple address ranges you can specify more than one `Subnet'. which will contain the corresponding public RSA and ECDSA keys.
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).
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 ================================================================== @subsubheading Step 2. Modifying the initial configuration.
@node Generating keypairs
@section Generating keypairs
@cindex key generation Unless you want to use tinc in switch mode,
Now that you have already created the main configuration file and your host configuration file, you should now configure which range of addresses you will use on the VPN.
you can easily create a public/private keypair by entering the following command: 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 @example
tincctl -n @var{netname} generate-keys tincctl -n @var{netname} config add subnet 192.168.2.0/24
@end example @end example
Tinc will generate a public and a private key and ask you where to put them. This will add a Subnet statement to your host configuration file.
Just press enter to accept the defaults. 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 ================================================================== @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}. 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 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. @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 @example
#!/bin/sh #!/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 @end example
This script gives the interface an IP address and a netmask. The first command gives the interface an IPv4 address and a netmask.
The kernel will also automatically add a route to this interface, so normally you don't need 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. to add route commands to the @file{tinc-up} script.
The kernel will also bring the interface up after this command. The kernel will also bring the interface up after this command.
@cindex netmask @cindex netmask
The netmask is the mask of the @emph{entire} VPN network, not just your The netmask is the mask of the @emph{entire} VPN network, not just your
own subnet. 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. 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}, 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' how these example host is set up. All branches use the netname `company'
for this particular VPN. for this particular VPN.
Each branch is set up using the @samp{tincctl init} and @samp{tincctl config} commands,
here we just show the end results:
@subsubheading For Branch A @subsubheading For Branch A
@emph{BranchA} would be configured like this: @emph{BranchA} would be configured like this:
@ -1381,6 +1600,8 @@ for this particular VPN.
In @file{@value{sysconfdir}/tinc/company/tinc-up}: In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example @example
#!/bin/sh
# Real interface of internal network: # Real interface of internal network:
# ifconfig eth0 10.1.54.1 netmask 255.255.0.0 # 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 @example
Name = BranchA Name = BranchA
Device = /dev/tap0
@end example @end example
On all hosts, @file{@value{sysconfdir}/tinc/company/hosts/BranchA} contains: 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 RSA PUBLIC KEY-----
@end example @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. 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. 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}: In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example @example
#!/bin/sh
# Real interface of internal network: # Real interface of internal network:
# ifconfig eth0 10.2.43.8 netmask 255.255.0.0 # ifconfig eth0 10.2.43.8 netmask 255.255.0.0
@ -1430,7 +1652,7 @@ ConnectTo = BranchA
@end example @end example
Note here that the internal address (on eth0) doesn't have to be the 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. always try to connect to BranchA.
On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchB}: 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}: In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example @example
#!/bin/sh
# Real interface of internal network: # Real interface of internal network:
# ifconfig eth0 10.3.69.254 netmask 255.255.0.0 # 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 @example
Name = BranchC Name = BranchC
ConnectTo = BranchA ConnectTo = BranchA
Device = /dev/tap1
@end example @end example
C already has another daemon that runs on port 655, so they have to 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}: In @file{@value{sysconfdir}/tinc/company/tinc-up}:
@example @example
#!/bin/sh
# Real interface of internal network: # Real interface of internal network:
# ifconfig eth0 10.4.3.32 netmask 255.255.0.0 # 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 @example
Name = BranchD Name = BranchD
ConnectTo = BranchC ConnectTo = BranchC
Device = /dev/net/tun
@end example @end example
D will be connecting to C, which has a tincd running for this network on 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. 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}: On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchD}:
@ -1519,16 +1740,11 @@ Address = 4.5.6.7
@subsubheading Key files @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 The private RSA key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
tincctl -n company generate-keys the private ECDSA key is stored in @file{@value{sysconfdir}/tinc/company/ecdsa_key.priv},
@end example and the public RSA and ECDSA keys are put into the host configuration file in the @file{@value{sysconfdir}/tinc/company/hosts/} directory.
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).
@subsubheading Starting @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: If everything else is done, you can start tinc by typing the following command:
@example @example
tincd -n @var{netname} tincctl -n @var{netname} start
@end example @end example
@cindex daemon @cindex daemon
@ -1600,6 +1816,12 @@ Store a cookie in @var{filename} which allows tincctl to authenticate.
If unspecified, the default is If unspecified, the default is
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}. @file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
@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 @item -L, --mlock
Lock tinc into main memory. Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions. This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
@ -1868,6 +2090,7 @@ tincctl -n @var{netname} reload
@menu @menu
* tincctl runtime options:: * tincctl runtime options::
* tincctl environment variables::
* tincctl commands:: * tincctl commands::
* tincctl examples:: * tincctl examples::
* tincctl top:: * tincctl top::
@ -1900,6 +2123,16 @@ Output version information and exit.
@end table @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 ================================================================== @c ==================================================================
@node tincctl commands @node tincctl commands
@ -1908,8 +2141,43 @@ Output version information and exit.
@c from the manpage @c from the manpage
@table @code @table @code
@item start @item init [@var{name}]
Start @samp{tincd}. 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 @item stop
Stop @samp{tincd}. Stop @samp{tincd}.
@ -1943,8 +2211,15 @@ Dump a list of all known subnets in the VPN.
@item dump connections @item dump connections
Dump a list of all meta connections with ourself. 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. 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 @item purge
Purges all information remembered about unreachable nodes. Purges all information remembered about unreachable nodes.
@ -1952,6 +2227,10 @@ Purges all information remembered about unreachable nodes.
@item debug @var{level} @item debug @var{level}
Sets debug level to @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 @item retry
Forces tinc to try to connect to all uplinks immediately. Forces tinc to try to connect to all uplinks immediately.
Usually tinc attempts to do this itself, Usually tinc attempts to do this itself,
@ -1986,6 +2265,16 @@ tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top tincctl -n vpn top
@end example @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 ================================================================== @c ==================================================================
@node tincctl top @node tincctl top
@section 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} @tab @code{netsh interface ip set address} @var{interface} @code{static} @var{address} @var{netmask}
@end multitable @end multitable
For IPv6 addresses: For IPv6 addresses:
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface} @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} @tab @code{netsh interface ipv6 add address} @var{interface} @code{static} @var{address}/@var{prefixlength}
@end multitable @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 ================================================================== @c ==================================================================
@node Routes @node Routes

View file

@ -1,4 +1,4 @@
.Dd 2011-06-25 .Dd 2012-10-14
.Dt TINCCTL 8 .Dt TINCCTL 8
.\" Manual page created by: .\" Manual page created by:
.\" Scott Lamb .\" Scott Lamb
@ -37,12 +37,58 @@ Display short list of options.
.It Fl -version .It Fl -version
Output version information and exit. Output version information and exit.
.El .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 .Sh COMMANDS
.zZ .zZ
.Bl -tag -width indent .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 Start
.Xr tincd 8 . .Xr tincd 8 ,
optionally with the given extra options.
.It stop .It stop
Stop Stop
.Xr tincd 8 . .Xr tincd 8 .
@ -69,6 +115,7 @@ If
is omitted, the default length will be 2048 bits. is omitted, the default length will be 2048 bits.
When saving keys to existing files, tinc will not delete the old keys; When saving keys to existing files, tinc will not delete the old keys;
you have to remove them manually. you have to remove them manually.
.It dump nodes .It dump nodes
Dump a list of all known nodes in the VPN. Dump a list of all known nodes in the VPN.
.It dump edges .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. Dump a list of all known subnets in the VPN.
.It dump connections .It dump connections
Dump a list of all meta connections with ourself. Dump a list of all meta connections with ourself.
.It dump graph .It dump graph | digraph
Dump a graph of the VPN in Dump a graph of the VPN in
.Xr dotty 1 .Xr dotty 1
format. 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 .It purge
Purges all information remembered about unreachable nodes. Purges all information remembered about unreachable nodes.
.It debug Ar N .It debug Ar N
Sets debug level to Sets debug level to
.Ar N . .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 .It retry
Forces Forces
.Xr tincd 8 .Xr tincd 8
@ -123,7 +180,16 @@ Examples of some commands:
tincctl -n vpn dump graph | circo -Txlib tincctl -n vpn dump graph | circo -Txlib
tincctl -n vpn pcap | tcpdump -r - tincctl -n vpn pcap | tcpdump -r -
tincctl -n vpn top tincctl -n vpn top
.Pp
.Ed .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 .Sh TOP
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters. The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
It displays a list of all the known nodes in the left-most column, It displays a list of all the known nodes in the left-most column,
@ -172,7 +238,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
.Xr tincd 8 , .Xr tincd 8 ,
.Xr tinc.conf 5 , .Xr tinc.conf 5 ,
.Xr dotty 1 , .Xr dotty 1 ,
.Xr pcap-savefile 7 , .Xr pcap-savefile 5 ,
.Xr tcpdump 8 , .Xr tcpdump 8 ,
.Xr top 1 , .Xr top 1 ,
.Pa http://www.tinc-vpn.org/ , .Pa http://www.tinc-vpn.org/ ,

View file

@ -1,4 +1,4 @@
.Dd 2011-06-25 .Dd 2012-02-22
.Dt TINCD 8 .Dt TINCD 8
.\" Manual page created by: .\" Manual page created by:
.\" Ivo Timmermans .\" Ivo Timmermans
@ -8,11 +8,12 @@
.Nd tinc VPN daemon .Nd tinc VPN daemon
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl cdDKnLRU .Op Fl cdDKnoLRU
.Op Fl -config Ns = Ns Ar DIR .Op Fl -config Ns = Ns Ar DIR
.Op Fl -no-detach .Op Fl -no-detach
.Op Fl -debug Ns Op = Ns Ar LEVEL .Op Fl -debug Ns Op = Ns Ar LEVEL
.Op Fl -net Ns = Ns Ar NETNAME .Op Fl -net Ns = Ns Ar NETNAME
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
.Op Fl -mlock .Op Fl -mlock
.Op Fl -logfile Ns Op = Ns Ar FILE .Op Fl -logfile Ns Op = Ns Ar FILE
.Op Fl -bypass-security .Op Fl -bypass-security
@ -61,6 +62,22 @@ for
.Ar NETNAME .Ar NETNAME
is the same as not specifying any is the same as not specifying any
.Ar NETNAME . .Ar NETNAME .
.It Fl 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 .It Fl L, -mlock
Lock tinc into main memory. Lock tinc into main memory.
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions. This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.

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@ # @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Inc. # Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -16,6 +16,23 @@
@SET_MAKE@ @SET_MAKE@
VPATH = @srcdir@ 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@ pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@
@ -41,7 +58,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.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) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d mkinstalldirs = $(install_sh) -d
@ -69,10 +87,21 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!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)" am__installdirs = "$(DESTDIR)$(bindir)"
SCRIPTS = $(dist_bin_SCRIPTS) SCRIPTS = $(dist_bin_SCRIPTS)
SOURCES = SOURCES =
DIST_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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@ ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
@ -122,6 +151,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
STRIP = @STRIP@ STRIP = @STRIP@
@ -213,8 +243,11 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) install-dist_binSCRIPTS: $(dist_bin_SCRIPTS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ @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 \ for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; 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; \ @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
files=`for p in $$list; do echo "$$p"; done | \ files=`for p in $$list; do echo "$$p"; done | \
sed -e 's,.*/,,;$(transform)'`; \ sed -e 's,.*/,,;$(transform)'`; \
test -n "$$list" || exit 0; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
tags: TAGS tags: TAGS
TAGS: TAGS:
@ -299,10 +330,15 @@ install-am: all-am
installcheck: installcheck-am installcheck: installcheck-am
install-strip: install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \ install; \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` 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: mostlyclean-generic:
clean-generic: clean-generic:

View file

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

9
have.h
View file

@ -1,7 +1,7 @@
/* /*
have.h -- include headers which are known to exist have.h -- include headers which are known to exist
Copyright (C) 1998-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -42,6 +42,7 @@
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
#include <w32api.h> #include <w32api.h>
#include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#endif #endif
@ -199,4 +200,10 @@
#include <event.h> #include <event.h>
#endif #endif
#ifdef HAVE_MINGW
#define SLASH "\\"
#else
#define SLASH "/"
#endif
#endif /* __TINC_SYSTEM_H__ */ #endif /* __TINC_SYSTEM_H__ */

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# install - install a program, script, or datafile # 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 # This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the # later released in X11R6 (xc/config/util/install.sh) with the
@ -156,6 +156,10 @@ while test $# -ne 0; do
-s) stripcmd=$stripprog;; -s) stripcmd=$stripprog;;
-t) dst_arg=$2 -t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;; shift;;
-T) no_target_directory=true;; -T) no_target_directory=true;;
@ -186,6 +190,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
fi fi
shift # arg shift # arg
dst_arg=$arg dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done done
fi fi
@ -200,7 +208,11 @@ if test $# -eq 0; then
fi fi
if test -z "$dir_arg"; then 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. # Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps. # However, 'strip' requires both read and write access to temps.
@ -228,9 +240,9 @@ fi
for src for src
do do
# Protect names starting with `-'. # Protect names problematic for `test' and other utilities.
case $src in case $src in
-*) src=./$src;; -* | [=\(\)!]) src=./$src;;
esac esac
if test -n "$dir_arg"; then if test -n "$dir_arg"; then
@ -252,12 +264,7 @@ do
echo "$0: no destination specified." >&2 echo "$0: no destination specified." >&2
exit 1 exit 1
fi fi
dst=$dst_arg 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 destination is a directory, append the input filename; won't work
# if double slashes aren't ignored. # if double slashes aren't ignored.
@ -385,7 +392,7 @@ do
case $dstdir in case $dstdir in
/*) prefix='/';; /*) prefix='/';;
-*) prefix='./';; [-=\(\)!]*) prefix='./';;
*) prefix='';; *) prefix='';;
esac esac
@ -403,7 +410,7 @@ do
for d for d
do do
test -z "$d" && continue test X"$d" = X && continue
prefix=$prefix$d prefix=$prefix$d
if test -d "$prefix"; then 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@ # @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Inc. # Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -15,6 +15,23 @@
@SET_MAKE@ @SET_MAKE@
VPATH = @srcdir@ 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@ pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@
@ -39,7 +56,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.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) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d mkinstalldirs = $(install_sh) -d
@ -48,6 +66,11 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
SOURCES = SOURCES =
DIST_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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@ ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
@ -97,6 +120,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
STRIP = @STRIP@ STRIP = @STRIP@
@ -236,10 +260,15 @@ install-am: all-am
installcheck: installcheck-am installcheck: installcheck-am
install-strip: install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \ install; \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` 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: mostlyclean-generic:
clean-generic: clean-generic:

View file

@ -35,7 +35,7 @@ AC_DEFUN([tinc_OPENSSL],
LDFLAGS="$LDFLAGS -L$withval"] LDFLAGS="$LDFLAGS -L$withval"]
) )
AC_CHECK_HEADERS(openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h, AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h openssl/ecdh.h openssl/ec.h],
[], [],
[AC_MSG_ERROR([OpenSSL header files not found.]); break] [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_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], [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 #! /bin/sh
# Common stub for a few missing GNU programs while installing. # 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, # 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. # Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
@ -84,7 +84,6 @@ Supported PROGRAM values:
help2man touch the output file help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file 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] yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and 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. # 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 if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed. # 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." \`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h rm -f y.tab.c y.tab.h
if test $# -ne 1; then if test $# -ne 1; then
eval LASTARG="\${$#}" eval LASTARG=\${$#}
case $LASTARG in case $LASTARG in
*.y) *.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 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." \`Flex' from any GNU archive site."
rm -f lex.yy.c rm -f lex.yy.c
if test $# -ne 1; then if test $# -ne 1; then
eval LASTARG="\${$#}" eval LASTARG=\${$#}
case $LASTARG in case $LASTARG in
*.l) *.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
@ -318,41 +308,6 @@ WARNING: \`$1' is $msg. You should only need it if
touch $file 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 "\ echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg. WARNING: \`$1' is needed, and is $msg.

View file

@ -1,30 +1,43 @@
## Produce this file with automake to get Makefile.in ## 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 = \ 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 \ 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 \ 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 = \ nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \ tincctl_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \ 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 = \ nodist_tincctl_SOURCES = \
ecdsagen.c rsagen.c 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 if TUNEMU
tincd_SOURCES += bsd/tunemu.c tincd_SOURCES += bsd/tunemu.c
endif endif
tincctl_LDADD = $(CURSES_LIBS) tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
DEFAULT_INCLUDES = DEFAULT_INCLUDES =
@ -32,8 +45,8 @@ INCLUDES = @INCLUDES@ -I$(top_builddir)
noinst_HEADERS = \ noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
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 \ 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 tincctl.h top.h bsd/tunemu.h protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
nodist_noinst_HEADERS = \ nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h 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@ # @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Inc. # Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation # This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved. # with or without modifications, as long as this notice is preserved.
@ -17,6 +17,23 @@
VPATH = @srcdir@ 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@ pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@
@ -35,9 +52,11 @@ PRE_UNINSTALL = :
POST_UNINSTALL = : POST_UNINSTALL = :
build_triplet = @build@ build_triplet = @build@
host_triplet = @host@ host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sptps_test$(EXEEXT)
@TUNEMU_TRUE@am__append_1 = bsd/tunemu.c @UML_TRUE@am__append_1 = uml_device.c
@TUNEMU_TRUE@am__append_2 = -lpcap @VDE_TRUE@am__append_2 = vde_device.c
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c
@TUNEMU_TRUE@am__append_4 = -lpcap
subdir = src subdir = src
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/Makefile.in
@ -45,7 +64,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.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) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d mkinstalldirs = $(install_sh) -d
@ -54,34 +74,47 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)" am__installdirs = "$(DESTDIR)$(sbindir)"
PROGRAMS = $(sbin_PROGRAMS) 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) \ am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
getopt1.$(OBJEXT) dropin.$(OBJEXT) list.$(OBJEXT) \ getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
tincctl.$(OBJEXT) top.$(OBJEXT) list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
top.$(OBJEXT)
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT) nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS) tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
am__DEPENDENCIES_1 = 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 \ am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \ splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
buffer.c conf.c connection.c control.c edge.c graph.c logger.c \ hash.c buffer.c conf.c connection.c control.c edge.c graph.c \
meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \ logger.c meta.c net.c net_packet.c net_setup.c net_socket.c \
node.c process.c protocol.c protocol_auth.c protocol_edge.c \ netutl.c node.c process.c protocol.c protocol_auth.c \
protocol_misc.c protocol_key.c protocol_subnet.c route.c \ protocol_edge.c protocol_misc.c protocol_key.c \
subnet.c tincd.c bsd/tunemu.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c \
@TUNEMU_TRUE@am__objects_1 = tunemu.$(OBJEXT) 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) \ am_tincd_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
list.$(OBJEXT) splay_tree.$(OBJEXT) dropin.$(OBJEXT) \ list.$(OBJEXT) splay_tree.$(OBJEXT) dropin.$(OBJEXT) \
fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \ fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \
buffer.$(OBJEXT) conf.$(OBJEXT) connection.$(OBJEXT) \ hash.$(OBJEXT) buffer.$(OBJEXT) conf.$(OBJEXT) \
control.$(OBJEXT) edge.$(OBJEXT) graph.$(OBJEXT) \ connection.$(OBJEXT) control.$(OBJEXT) edge.$(OBJEXT) \
logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \ graph.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \
net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \ net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \
netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \ netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \
protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \ protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \ protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \
protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \ protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \
route.$(OBJEXT) subnet.$(OBJEXT) tincd.$(OBJEXT) \ route.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
$(am__objects_1) 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) \ nodist_tincd_OBJECTS = device.$(OBJEXT) cipher.$(OBJEXT) \
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \ crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT) digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT)
@ -94,9 +127,16 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC) CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(tincctl_SOURCES) $(nodist_tincctl_SOURCES) \ SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
$(tincd_SOURCES) $(nodist_tincd_SOURCES) $(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
DIST_SOURCES = $(tincctl_SOURCES) $(am__tincd_SOURCES_DIST) $(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) HEADERS = $(nodist_noinst_HEADERS) $(noinst_HEADERS)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
@ -133,7 +173,7 @@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_2) LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_4)
LN_S = @LN_S@ LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@ LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@ MAINT = @MAINT@
@ -149,6 +189,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
STRIP = @STRIP@ STRIP = @STRIP@
@ -203,30 +244,36 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ 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 \ 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 \ dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c buffer.c \
connection.c control.c edge.c graph.c logger.c meta.c net.c \ conf.c connection.c control.c edge.c graph.c logger.c meta.c \
net_packet.c net_setup.c net_socket.c netutl.c node.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 \ process.c protocol.c protocol_auth.c protocol_edge.c \
protocol_misc.c protocol_key.c protocol_subnet.c route.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 = \ nodist_tincd_SOURCES = \
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
tincctl_SOURCES = \ tincctl_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \ 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 = \ nodist_tincctl_SOURCES = \
ecdsagen.c rsagen.c 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 = DEFAULT_INCLUDES =
noinst_HEADERS = \ noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
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 \ 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 tincctl.h top.h bsd/tunemu.h protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
nodist_noinst_HEADERS = \ nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h 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): $(am__aclocal_m4_deps):
install-sbinPROGRAMS: $(sbin_PROGRAMS) install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ @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 | \ for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \ sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \ while read p p1; do if test -f $$p; \
@ -303,10 +353,13 @@ uninstall-sbinPROGRAMS:
clean-sbinPROGRAMS: clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) -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) @rm -f tincctl$(EXEEXT)
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS) $(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) @rm -f tincd$(EXEEXT)
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS) $(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)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/digest.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)/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)/ecdh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsa.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@ @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)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.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)/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)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.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)/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.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_packet.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@ @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_key.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_misc.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)/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)/route.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.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)/rsagen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay_tree.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.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)/tincctl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.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)/top.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tunemu.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)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
.c.o: .c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -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 installcheck: installcheck-am
install-strip: install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \ install; \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` 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: mostlyclean-generic:
clean-generic: clean-generic:

View file

@ -1,7 +1,7 @@
/* /*
device.c -- Interaction BSD tun/tap device device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans, Copyright (C) 2001-2005 Ivo Timmermans,
2001-2011 Guus Sliepen <guus@tinc-vpn.org> 2001-2012 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com> 2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -33,7 +33,12 @@
#include "bsd/tunemu.h" #include "bsd/tunemu.h"
#endif #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 { typedef enum device_type {
DEVICE_TYPE_TUN, 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; static device_type_t device_type = DEVICE_TYPE_TUN;
#endif #endif
bool setup_device(void) { static bool setup_device(void) {
char *type; char *type;
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
device = xstrdup(DEFAULT_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)) if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
@ -81,7 +90,7 @@ bool setup_device(void) {
else if(!strcasecmp(type, "tap")) else if(!strcasecmp(type, "tap"))
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
else { else {
logger(LOG_ERR, "Unknown device type %s!", type); logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
return false; return false;
} }
} else { } else {
@ -102,10 +111,14 @@ bool setup_device(void) {
} }
if(device_fd < 0) { 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; return false;
} }
#ifdef FD_CLOEXEC
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
switch(device_type) { switch(device_type) {
default: default:
device_type = DEVICE_TYPE_TUN; device_type = DEVICE_TYPE_TUN;
@ -114,7 +127,7 @@ bool setup_device(void) {
{ {
const int zero = 0; const int zero = 0;
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) { if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
logger(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; return false;
} }
} }
@ -133,7 +146,7 @@ bool setup_device(void) {
{ {
const int one = 1; const int one = 1;
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) { if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
logger(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; return false;
} }
} }
@ -170,12 +183,12 @@ bool setup_device(void) {
#endif #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; return true;
} }
void close_device(void) { static void close_device(void) {
switch(device_type) { switch(device_type) {
#ifdef HAVE_TUNEMU #ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU: case DEVICE_TYPE_TUNEMU:
@ -190,7 +203,7 @@ void close_device(void) {
free(iface); free(iface);
} }
bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
int inlen; int inlen;
switch(device_type) { switch(device_type) {
@ -204,7 +217,7 @@ bool read_packet(vpn_packet_t *packet) {
inlen = read(device_fd, packet->data + 14, MTU - 14); inlen = read(device_fd, packet->data + 14, MTU - 14);
if(inlen <= 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -219,12 +232,13 @@ bool read_packet(vpn_packet_t *packet) {
packet->data[13] = 0xDD; packet->data[13] = 0xDD;
break; break;
default: default:
ifdebug(TRAFFIC) logger(LOG_ERR, logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown IP version %d while reading packet from %s %s", "Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device); packet->data[14] >> 4, device_info, device);
return false; return false;
} }
memset(packet->data, 0, 12);
packet->len = inlen + 14; packet->len = inlen + 14;
break; break;
@ -233,7 +247,7 @@ bool read_packet(vpn_packet_t *packet) {
struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}}; struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
if((inlen = readv(device_fd, vector, 2)) <= 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -250,19 +264,20 @@ bool read_packet(vpn_packet_t *packet) {
break; break;
default: default:
ifdebug(TRAFFIC) logger(LOG_ERR, logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while reading packet from %s %s", "Unknown address family %x while reading packet from %s %s",
ntohl(type), device_info, device); ntohl(type), device_info, device);
return false; return false;
} }
memset(packet->data, 0, 12);
packet->len = inlen + 10; packet->len = inlen + 10;
break; break;
} }
case DEVICE_TYPE_TAP: case DEVICE_TYPE_TAP:
if((inlen = read(device_fd, packet->data, MTU)) <= 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -276,20 +291,20 @@ bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len; 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); packet->len, device_info);
return true; return true;
} }
bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
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); packet->len, device_info);
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -310,14 +325,14 @@ bool write_packet(vpn_packet_t *packet) {
type = htonl(AF_INET6); type = htonl(AF_INET6);
break; break;
default: default:
ifdebug(TRAFFIC) logger(LOG_ERR, logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while writing packet to %s %s", "Unknown address family %x while writing packet to %s %s",
af, device_info, device); af, device_info, device);
return false; return false;
} }
if(writev(device_fd, vector, 2) < 0) { 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)); strerror(errno));
return false; return false;
} }
@ -326,7 +341,7 @@ bool write_packet(vpn_packet_t *packet) {
case DEVICE_TYPE_TAP: case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -335,7 +350,7 @@ bool write_packet(vpn_packet_t *packet) {
#ifdef HAVE_TUNEMU #ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU: case DEVICE_TYPE_TUNEMU:
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -351,8 +366,16 @@ bool write_packet(vpn_packet_t *packet) {
return true; return true;
} }
void dump_device_stats(void) { static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in); logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out); 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 conf.c -- configuration code
Copyright (C) 1998 Robert van der Meulen Copyright (C) 1998 Robert van der Meulen
1998-2005 Ivo Timmermans 1998-2005 Ivo Timmermans
2000-2010 Guus Sliepen <guus@tinc-vpn.org> 2000-2012 Guus Sliepen <guus@tinc-vpn.org>
2010-2011 Julien Muchembled <jm@jmuchemb.eu> 2010-2011 Julien Muchembled <jm@jmuchemb.eu>
2000 Cris van Pelt 2000 Cris van Pelt
@ -141,7 +141,7 @@ bool get_config_bool(const config_t *cfg, bool *result) {
return true; 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); cfg->variable, cfg->file, cfg->line);
return false; return false;
@ -154,7 +154,7 @@ bool get_config_int(const config_t *cfg, int *result) {
if(sscanf(cfg->value, "%d", result) == 1) if(sscanf(cfg->value, "%d", result) == 1)
return true; 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); cfg->variable, cfg->file, cfg->line);
return false; return false;
@ -182,7 +182,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
return true; 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); cfg->variable, cfg->file, cfg->line);
return false; return false;
@ -195,7 +195,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
return false; return false;
if(!str2net(&subnet, cfg->value)) { 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); cfg->variable, cfg->file, cfg->line);
return false; 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)) && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
|| ((subnet.type == SUBNET_IPV6) || ((subnet.type == SUBNET_IPV6)
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) { && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof 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); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
@ -236,8 +236,9 @@ static char *readline(FILE * fp, char *buf, size_t buflen) {
if(!newline) if(!newline)
return buf; return buf;
*newline = '\0'; /* kill newline */ /* kill newline and carriage return if necessary */
if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */ *newline = '\0';
if(newline > p && newline[-1] == '\r')
newline[-1] = '\0'; newline[-1] = '\0';
return buf; return buf;
@ -265,10 +266,10 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
if(!*value) { if(!*value) {
const char err[] = "No value for variable"; const char err[] = "No value for variable";
if (fname) 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); err, variable, lineno, fname);
else 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); err, variable, lineno);
return NULL; return NULL;
} }
@ -298,7 +299,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if(!fp) { 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; 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) { 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; size_t prefix_len = prefix ? strlen(prefix) : 0;
for(node = cmdline_conf->tail; node; node = next) { for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
config_t *orig_cfg, *cfg = (config_t *)node->data; const config_t *cfg = node->data;
next = node->prev; config_t *new;
if(!prefix) { if(!prefix) {
if(strchr(cfg->variable, '.')) if(strchr(cfg->variable, '.'))
continue; continue;
node->data = NULL;
list_unlink_node(cmdline_conf, node);
} else { } else {
if(strncmp(prefix, cfg->variable, prefix_len) || if(strncmp(prefix, cfg->variable, prefix_len) ||
cfg->variable[prefix_len] != '.') cfg->variable[prefix_len] != '.')
continue; 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); 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); x = read_config_file(config_tree, fname);
if(!x) { /* System error: complain */ if(!x)
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno)); logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
}
free(fname); free(fname);
return x; return x;
} }
bool read_connection_config(connection_t *c) { bool read_host_config(splay_tree_t *config_tree, const char *name) {
char *fname; char *fname;
bool x; bool x;
read_config_options(c->config_tree, c->name); read_config_options(config_tree, name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name); xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
x = read_config_file(c->config_tree, fname); x = read_config_file(config_tree, fname);
free(fname); free(fname);
return x; 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) { bool append_config_file(const char *name, const char *key, const char *value) {
char *fname; char *fname;
xasprintf(&fname, "%s/hosts/%s", confbase, name); xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
FILE *fp = fopen(fname, "a"); FILE *fp = fopen(fname, "a");
if(!fp) { 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 { } else {
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value); fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
fclose(fp); fclose(fp);
@ -415,45 +413,5 @@ bool append_config_file(const char *name, const char *key, const char *value) {
free(fname); free(fname);
return fp; return fp != NULL;
}
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;
} }

View file

@ -1,7 +1,7 @@
/* /*
conf.h -- header for conf.c conf.h -- header for conf.c
Copyright (C) 1998-2005 Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans
2000-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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -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 bool read_config_file(splay_tree_t *, const char *);
extern void read_config_options(splay_tree_t *, const char *); extern void read_config_options(splay_tree_t *, const char *);
extern bool read_server_config(void); 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 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__ */ #endif /* __TINC_CONF_H__ */

View file

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

View file

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

View file

@ -1,6 +1,6 @@
/* /*
control.c -- Control socket handling. 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
#include "netutl.h" #include "netutl.h"
#include "protocol.h" #include "protocol.h"
#include "route.h" #include "route.h"
#include "splay_tree.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
@ -44,16 +43,16 @@ static bool control_ok(connection_t *c, int type) {
return control_return(c, type, 0); 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; int type;
if(!c->status.control || c->allow_request != CONTROL) { 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; return false;
} }
if(sscanf(request, "%*d %d", &type) != 1) { 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; return false;
} }
@ -93,22 +92,18 @@ bool control_h(connection_t *c, char *request) {
return control_ok(c, REQ_RETRY); return control_ok(c, REQ_RETRY);
case REQ_RELOAD: case REQ_RELOAD:
logger(LOG_NOTICE, "Got '%s' command", "reload"); logger(DEBUG_ALWAYS, LOG_NOTICE, "Got '%s' command", "reload");
int result = reload_configuration(); int result = reload_configuration();
return control_return(c, REQ_RELOAD, result); return control_return(c, REQ_RELOAD, result);
case REQ_DISCONNECT: { case REQ_DISCONNECT: {
char name[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE];
connection_t *other;
splay_node_t *node, *next;
bool found = false; bool found = false;
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1) if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1)
return control_return(c, REQ_DISCONNECT, -1); return control_return(c, REQ_DISCONNECT, -1);
for(node = connection_tree->head; node; node = next) { for list_each(connection_t, other, connection_list) {
next = node->next;
other = node->data;
if(strcmp(other->name, name)) if(strcmp(other->name, name))
continue; continue;
terminate_connection(other, other->status.active); terminate_connection(other, other->status.active);
@ -122,10 +117,17 @@ bool control_h(connection_t *c, char *request) {
return dump_traffic(c); return dump_traffic(c);
case REQ_PCAP: case REQ_PCAP:
sscanf(request, "%*d %*d %d", &c->outmaclength);
c->status.pcap = true; c->status.pcap = true;
pcap = true; pcap = true;
return true; return true;
case REQ_LOG:
sscanf(request, "%*d %*d %d", &c->outcompression);
c->status.log = true;
logcontrol = true;
return true;
default: default:
return send_request(c, "%d %d", CONTROL, REQ_INVALID); return send_request(c, "%d %d", CONTROL, REQ_INVALID);
} }
@ -137,7 +139,7 @@ bool init_control(void) {
FILE *f = fopen(pidfilename, "w"); FILE *f = fopen(pidfilename, "w");
if(!f) { 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; return false;
} }

View file

@ -1,6 +1,7 @@
/* /*
control_protocol.h -- control socket protocol. control_protocol.h -- control socket protocol.
Copyright (C) 2007 Scott Lamb <slamb@slamb.org> 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -39,6 +40,7 @@ enum request_type {
REQ_DISCONNECT, REQ_DISCONNECT,
REQ_DUMP_TRAFFIC, REQ_DUMP_TRAFFIC,
REQ_PCAP, REQ_PCAP,
REQ_LOG,
}; };
#define TINC_CTL_VERSION_CURRENT 0 #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 device.c -- Interaction with Windows tap driver in a Cygwin environment
Copyright (C) 2002-2005 Ivo Timmermans, 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -45,7 +45,7 @@ static uint64_t device_total_out = 0;
static pid_t reader_pid; static pid_t reader_pid;
static int sp[2]; static int sp[2];
bool setup_device(void) { static bool setup_device(void) {
HKEY key, key2; HKEY key, key2;
int i, err; int i, err;
@ -64,7 +64,7 @@ bool setup_device(void) {
/* Open registry and look for network adapters */ /* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError())); logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false; return false;
} }
@ -116,7 +116,7 @@ bool setup_device(void) {
RegCloseKey(key); RegCloseKey(key);
if(!found) { if(!found) {
logger(LOG_ERR, "No Windows tap device found!"); logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
return false; return false;
} }
@ -133,7 +133,7 @@ bool setup_device(void) {
Furthermore I don't really know how to do it the "Windows" way. */ Furthermore I don't really know how to do it the "Windows" way. */
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) { if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
logger(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; 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); device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
if(device_handle == INVALID_HANDLE_VALUE) { if(device_handle == INVALID_HANDLE_VALUE) {
logger(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; return false;
} }
@ -151,7 +151,7 @@ bool setup_device(void) {
/* Get MAC address from tap device */ /* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) { if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
logger(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; return false;
} }
@ -164,7 +164,7 @@ bool setup_device(void) {
reader_pid = fork(); reader_pid = fork();
if(reader_pid == -1) { 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; 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); device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(device_handle == INVALID_HANDLE_VALUE) { if(device_handle == INVALID_HANDLE_VALUE) {
logger(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; buf[0] = 0;
write(sp[1], buf, 1); write(sp[1], buf, 1);
exit(1); exit(1);
} }
logger(LOG_DEBUG, "Tap reader forked and running."); logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader forked and running.");
/* Notify success */ /* Notify success */
@ -203,18 +203,18 @@ bool setup_device(void) {
read(device_fd, &gelukt, 1); read(device_fd, &gelukt, 1);
if(gelukt != 1) { if(gelukt != 1) {
logger(LOG_DEBUG, "Tap reader failed!"); logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader failed!");
return false; return false;
} }
device_info = "Windows tap device"; 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; return true;
} }
void close_device(void) { static void close_device(void) {
close(sp[0]); close(sp[0]);
close(sp[1]); close(sp[1]);
CloseHandle(device_handle); CloseHandle(device_handle);
@ -225,11 +225,11 @@ void close_device(void) {
free(iface); free(iface);
} }
bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
int inlen; int inlen;
if((inlen = read(sp[0], packet->data, MTU)) <= 0) { 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)); device, strerror(errno));
return false; return false;
} }
@ -238,20 +238,20 @@ bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len; 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); device_info);
return true; return true;
} }
bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
long outlen; 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); packet->len, device_info);
if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) { 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; return false;
} }
@ -260,8 +260,16 @@ bool write_packet(vpn_packet_t *packet) {
return true; return true;
} }
void dump_device_stats(void) { static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in); logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out); 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 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -32,10 +32,20 @@ extern uint64_t device_in_bytes;
extern uint64_t device_out_packets; extern uint64_t device_out_packets;
extern uint64_t device_out_bytes; extern uint64_t device_out_bytes;
extern bool setup_device(void); typedef struct devops_t {
extern void close_device(void); bool (*setup)(void);
extern bool read_packet(struct vpn_packet_t *); void (*close)(void);
extern bool write_packet(struct vpn_packet_t *); bool (*read)(struct vpn_packet_t *);
extern void dump_device_stats(void); 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__ */ #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 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 2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -29,7 +29,7 @@
#include "utils.h" #include "utils.h"
#include "xalloc.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) { static int edge_compare(const edge_t *a, const edge_t *b) {
return strcmp(a->to->name, b->to->name); return strcmp(a->to->name, b->to->name);
@ -107,17 +107,10 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
} }
bool dump_edges(connection_t *c) { bool dump_edges(connection_t *c) {
splay_node_t *node, *node2; for splay_each(node_t, n, node_tree) {
node_t *n; for splay_each(edge_t, e, n->edge_tree) {
edge_t *e; char *address = sockaddr2hostname(&e->address);
char *address; send_request(c, "%d %d %s %s %s %x %d",
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",
CONTROL, REQ_DUMP_EDGES, CONTROL, REQ_DUMP_EDGES,
e->from->name, e->to->name, address, e->from->name, e->to->name, address,
e->options, e->weight); e->options, e->weight);

View file

@ -1,6 +1,6 @@
/* /*
edge.h -- header for edge.c 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 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify

View file

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

View file

@ -2,8 +2,7 @@
#define _FAKE_GETNAMEINFO_H #define _FAKE_GETNAMEINFO_H
#if !HAVE_DECL_GETNAMEINFO #if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
size_t hostlen, char *serv, size_t servlen, int flags);
#endif /* !HAVE_GETNAMEINFO */ #endif /* !HAVE_GETNAMEINFO */
#ifndef NI_MAXSERV #ifndef NI_MAXSERV

View file

@ -1,6 +1,6 @@
/* /*
cipher.c -- Symmetric block cipher handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -97,12 +97,12 @@ static bool cipher_open(cipher_t *cipher, int algo, int mode) {
gcry_error_t err; gcry_error_t err;
if(!ciphertonid(algo, mode, &cipher->nid)) { 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; return false;
} }
if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) { 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; return false;
} }
@ -118,7 +118,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
int algo, mode; int algo, mode;
if(!nametocipher(name, &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; return false;
} }
@ -129,7 +129,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
int algo, mode; int algo, mode;
if(!nidtocipher(nid, &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; 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; size_t reqlen = ((inlen + cipher->blklen) / cipher->blklen) * cipher->blklen;
if(*outlen < reqlen) { 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; 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); gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
if((err = gcry_cipher_encrypt(cipher->handle, outdata, *outlen, indata, inlen))) { 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; return false;
} }
if(cipher->padding) { if(cipher->padding) {
if((err = gcry_cipher_encrypt(cipher->handle, outdata + inlen, cipher->blklen, pad, cipher->blklen))) { 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; 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); gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
if((err = gcry_cipher_decrypt(cipher->handle, outdata, *outlen, indata, inlen))) { 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; 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]; uint8_t padbyte = ((uint8_t *)outdata)[inlen - 1];
if(padbyte == 0 || padbyte > cipher->blklen || padbyte > inlen) { 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; 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--) for(int i = inlen - 1; i >= origlen; i--)
if(((uint8_t *)outdata)[i] != padbyte) { 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; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
cipher.h -- header file cipher.c 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/* /*
crypto.h -- header for crypto.c 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/* /*
digest.c -- Digest handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -75,7 +75,7 @@ static bool digesttonid(int algo, int *nid) {
static bool digest_open(digest_t *digest, int algo, int maclength) { static bool digest_open(digest_t *digest, int algo, int maclength) {
if(!digesttonid(algo, &digest->nid)) { 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; return false;
} }
@ -96,7 +96,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
int algo; int algo;
if(!nametodigest(name, &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; return false;
} }
@ -107,7 +107,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
int algo; int algo;
if(!nidtodigest(nid, &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; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
digest.h -- header file digest.c 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/* /*
rsa.c -- RSA key handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -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); ?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
if(err) { 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; 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); ?: gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
if(err) { 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; return false;
} }
@ -216,7 +216,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
size_t derlen; size_t derlen;
if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &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; 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->n)
|| !ber_read_mpi(&derp, &derlen, &rsa->e) || !ber_read_mpi(&derp, &derlen, &rsa->e)
|| derlen) { || derlen) {
logger(LOG_ERR, "Error while decoding RSA public key"); logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA public key");
return NULL; return NULL;
} }
@ -236,7 +236,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
size_t derlen; size_t derlen;
if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &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; 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)
|| !ber_read_mpi(&derp, &derlen, NULL) // u || !ber_read_mpi(&derp, &derlen, NULL) // u
|| derlen) { || derlen) {
logger(LOG_ERR, "Error while decoding RSA private key"); logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA private key");
return NULL; 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 // 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) { bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
gcry_mpi_t inmpi; gcry_mpi_t inmpi;

View file

@ -1,6 +1,6 @@
/* /*
rsagen.c -- RSA key generation and export 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -164,12 +164,12 @@ bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
if(!ber_write_mpi(&derp1, &derlen1, &rsa->n) if(!ber_write_mpi(&derp1, &derlen1, &rsa->n)
|| !ber_write_mpi(&derp1, &derlen1, &rsa->e) || !ber_write_mpi(&derp1, &derlen1, &rsa->e)
|| !ber_write_sequence(&derp2, &derlen2, derbuf1, derlen1)) { || !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; return false;
} }
if(!pem_encode(fp, "RSA PUBLIC KEY", derbuf2, derlen2)) { 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; 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, &exp1)
|| ber_write_mpi(&derp1, &derlen1, &exp2) || ber_write_mpi(&derp1, &derlen1, &exp2)
|| ber_write_mpi(&derp1, &derlen1, &coeff)) || 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; return false;
} }
if(!pem_encode(fp, "RSA PRIVATE KEY", derbuf2, derlen2)) { 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; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
graph.c -- graph algorithms 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 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -44,12 +44,12 @@
#include "system.h" #include "system.h"
#include "splay_tree.h"
#include "config.h" #include "config.h"
#include "connection.h" #include "connection.h"
#include "device.h" #include "device.h"
#include "edge.h" #include "edge.h"
#include "graph.h" #include "graph.h"
#include "list.h"
#include "logger.h" #include "logger.h"
#include "netutl.h" #include "netutl.h"
#include "node.h" #include "node.h"
@ -65,34 +65,22 @@
Please note that sorting on weight is already done by add_edge(). Please note that sorting on weight is already done by add_edge().
*/ */
void mst_kruskal(void) { static void mst_kruskal(void) {
splay_node_t *node, *next;
edge_t *e;
node_t *n;
connection_t *c;
/* Clear MST status on connections */ /* Clear MST status on connections */
for(node = connection_tree->head; node; node = node->next) { for list_each(connection_t, c, connection_list)
c = node->data;
c->status.mst = false; 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 */ /* Clear visited status on nodes */
for(node = node_tree->head; node; node = node->next) { for splay_each(node_t, n, node_tree)
n = node->data;
n->status.visited = false; n->status.visited = false;
}
/* Add safe edges */ /* Add safe edges */
for(node = edge_weight_tree->head; node; node = next) { for splay_each(edge_t, e, edge_weight_tree) {
next = node->next;
e = node->data;
if(!e->reverse || (e->from->status.visited && e->to->status.visited)) if(!e->reverse || (e->from->status.visited && e->to->status.visited))
continue; continue;
@ -105,31 +93,21 @@ void mst_kruskal(void) {
if(e->reverse->connection) if(e->reverse->connection)
e->reverse->connection->status.mst = true; 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); e->to->name, e->weight);
} }
} }
/* Implementation of Dijkstra's algorithm. /* Implementation of a simple breadth-first search algorithm.
Running time: O(N^2) Running time: O(E)
*/ */
static void sssp_dijkstra(void) { static void sssp_bfs(void) {
splay_node_t *node, *to; list_t *todo_list = list_alloc(NULL);
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:");
/* Clear visited status on nodes */ /* Clear visited status on nodes */
for(node = node_tree->head; node; node = node->next) { for splay_each(node_t, n, node_tree) {
n = node->data;
n->status.visited = false; n->status.visited = false;
n->status.indirect = true; n->status.indirect = true;
n->distance = -1; n->distance = -1;
@ -137,119 +115,23 @@ static void sssp_dijkstra(void) {
/* Begin with myself */ /* Begin with myself */
myself->status.visited = true;
myself->status.indirect = false; myself->status.indirect = false;
myself->nexthop = myself; myself->nexthop = myself;
myself->prevedge = NULL;
myself->via = myself; myself->via = myself;
myself->distance = 0; myself->distance = 0;
list_insert_head(todo_list, myself); list_insert_head(todo_list, myself);
/* Loop while todo_list is filled */ /* Loop while todo_list is filled */
while(todo_list->head) { for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
n = NULL; logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Examining edges from %s", n->name);
nnode = NULL;
/* Select node from todo_list with smallest distance */ if(n->distance < 0)
abort();
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;
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
if(!e->reverse) if(!e->reverse)
continue; continue;
@ -270,61 +152,63 @@ void sssp_bfs(void) {
of nodes behind it. 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 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; continue;
e->to->status.visited = true; e->to->status.visited = true;
e->to->status.indirect = indirect; e->to->status.indirect = indirect;
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
e->to->prevedge = e;
e->to->via = indirect ? n->via : e->to; e->to->via = indirect ? n->via : e->to;
e->to->options = e->options; 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); update_node_udp(e->to, &e->address);
list_insert_tail(todo_list, e->to); list_insert_tail(todo_list, e->to);
} }
todonext = from->next; next = node->next; /* Because the list_insert_tail() above could have added something extra for us! */
list_delete_node(todo_list, from); list_delete_node(todo_list, node);
} }
list_free(todo_list); list_free(todo_list);
} }
static void check_reachability(void) { 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. */ /* Check reachability status. */
for(node = node_tree->head; node; node = next) { for splay_each(node_t, n, node_tree) {
next = node->next;
n = node->data;
if(n->status.visited != n->status.reachable) { if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable; n->status.reachable = !n->status.reachable;
n->last_state_change = time(NULL);
if(n->status.reachable) { 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); n->name, n->hostname);
} else { } 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); n->name, n->hostname);
} }
if(experimental && OPTION_VERSION(n->options) >= 2)
n->status.sptps = true;
/* TODO: only clear status.validkey if node is unreachable? */ /* TODO: only clear status.validkey if node is unreachable? */
n->status.validkey = false; n->status.validkey = false;
if(n->status.sptps) {
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
}
n->last_req_key = 0; n->last_req_key = 0;
n->status.udp_confirmed = false;
n->maxmtu = MTU; n->maxmtu = MTU;
n->minmtu = 0; n->minmtu = 0;
n->mtuprobes = 0; n->mtuprobes = 0;
@ -332,6 +216,11 @@ static void check_reachability(void) {
if(timeout_initialized(&n->mtuevent)) if(timeout_initialized(&n->mtuevent))
event_del(&n->mtuevent); event_del(&n->mtuevent);
char *name;
char *address;
char *port;
char *envp[7];
xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); 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); execute_script(n->status.reachable ? "host-up" : "host-down", envp);
xasprintf(&name, xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
n->name);
execute_script(name, envp); execute_script(name, envp);
free(name); free(name);
free(address); free(address);
free(port); free(port);
for(i = 0; i < 6; i++) for(int i = 0; i < 6; i++)
free(envp[i]); free(envp[i]);
subnet_update(n, NULL, n->status.reachable); subnet_update(n, NULL, n->status.reachable);
if(!n->status.reachable) if(!n->status.reachable) {
update_node_udp(n, NULL); 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); send_ans_key(n);
} }
} }
}
}
} }
void graph(void) { void graph(void) {
subnet_cache_flush(); subnet_cache_flush();
sssp_dijkstra(); sssp_bfs();
check_reachability(); check_reachability();
mst_kruskal(); mst_kruskal();
} }

View file

@ -1,6 +1,6 @@
/* /*
graph.h -- header for graph.c 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 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify

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 ipv4.h -- missing IPv4 related definitions
Copyright (C) 2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -41,6 +41,14 @@
#define ICMP_NET_UNKNOWN 6 #define ICMP_NET_UNKNOWN 6
#endif #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 #ifndef ICMP_NET_UNREACH
#define ICMP_NET_UNREACH 0 #define ICMP_NET_UNREACH 0
#endif #endif

View file

@ -1,7 +1,7 @@
/* /*
ipv6.h -- missing IPv6 related definitions ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -95,8 +95,10 @@ struct icmp6_hdr {
#define ICMP6_DST_UNREACH_NOROUTE 0 #define ICMP6_DST_UNREACH_NOROUTE 0
#define ICMP6_DST_UNREACH 1 #define ICMP6_DST_UNREACH 1
#define ICMP6_PACKET_TOO_BIG 2 #define ICMP6_PACKET_TOO_BIG 2
#define ICMP6_TIME_EXCEEDED 3
#define ICMP6_DST_UNREACH_ADMIN 1 #define ICMP6_DST_UNREACH_ADMIN 1
#define ICMP6_DST_UNREACH_ADDR 3 #define ICMP6_DST_UNREACH_ADDR 3
#define ICMP6_TIME_EXCEED_TRANSIT 0
#define ND_NEIGHBOR_SOLICIT 135 #define ND_NEIGHBOR_SOLICIT 135
#define ND_NEIGHBOR_ADVERT 136 #define ND_NEIGHBOR_ADVERT 136
#define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data32 icmp6_dataun.icmp6_un_data32

View file

@ -1,7 +1,7 @@
/* /*
device.c -- Interaction with Linux ethertap and tun/tap device device.c -- Interaction with Linux ethertap and tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans, 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -41,6 +41,7 @@ int device_fd = -1;
static device_type_t device_type; static device_type_t device_type;
char *device = NULL; char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *type = NULL;
static char ifrname[IFNAMSIZ]; static char ifrname[IFNAMSIZ];
static char *device_info; static char *device_info;
@ -49,27 +50,35 @@ uint64_t device_in_bytes = 0;
uint64_t device_out_packets = 0; uint64_t device_out_packets = 0;
uint64_t device_out_bytes = 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)) if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = xstrdup(DEFAULT_DEVICE); device = xstrdup(DEFAULT_DEVICE);
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
#ifdef HAVE_LINUX_IF_TUN_H if(netname)
if (netname != NULL)
iface = xstrdup(netname); iface = xstrdup(netname);
#else
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
#endif
device_fd = open(device, O_RDWR | O_NONBLOCK); device_fd = open(device, O_RDWR | O_NONBLOCK);
if(device_fd < 0) { 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; return false;
} }
#ifdef FD_CLOEXEC
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
struct ifreq ifr = {{{0}}}; 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; ifr.ifr_flags = IFF_TUN;
device_type = DEVICE_TYPE_TUN; device_type = DEVICE_TYPE_TUN;
device_info = "Linux tun/tap device (tun mode)"; device_info = "Linux tun/tap device (tun mode)";
@ -92,28 +101,24 @@ bool setup_device(void) {
if(!ioctl(device_fd, TUNSETIFF, &ifr)) { if(!ioctl(device_fd, TUNSETIFF, &ifr)) {
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ); strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
if(iface) free(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);
iface = xstrdup(ifrname); 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; return true;
} }
void close_device(void) { static void close_device(void) {
close(device_fd); close(device_fd);
free(type);
free(device); free(device);
free(iface); free(iface);
} }
bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
int inlen; int inlen;
switch(device_type) { switch(device_type) {
@ -121,18 +126,19 @@ bool read_packet(vpn_packet_t *packet) {
inlen = read(device_fd, packet->data + 10, MTU - 10); inlen = read(device_fd, packet->data + 10, MTU - 10);
if(inlen <= 0) { 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)); device_info, device, strerror(errno));
return false; return false;
} }
memset(packet->data, 0, 12);
packet->len = inlen + 10; packet->len = inlen + 10;
break; break;
case DEVICE_TYPE_TAP: case DEVICE_TYPE_TAP:
inlen = read(device_fd, packet->data, MTU); inlen = read(device_fd, packet->data, MTU);
if(inlen <= 0) { 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)); device_info, device, strerror(errno));
return false; return false;
} }
@ -146,28 +152,28 @@ bool read_packet(vpn_packet_t *packet) {
device_in_packets++; device_in_packets++;
device_in_bytes += packet->len; 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); device_info);
return true; return true;
} }
bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
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); packet->len, device_info);
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
packet->data[10] = packet->data[11] = 0; packet->data[10] = packet->data[11] = 0;
if(write(device_fd, packet->data + 10, packet->len - 10) < 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)); strerror(errno));
return false; return false;
} }
break; break;
case DEVICE_TYPE_TAP: case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) { 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)); strerror(errno));
return false; return false;
} }
@ -182,8 +188,16 @@ bool write_packet(vpn_packet_t *packet) {
return true; return true;
} }
void dump_device_stats(void) { static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes); logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_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 list.c -- functions to deal with double linked lists
Copyright (C) 2000-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -26,9 +26,7 @@
/* (De)constructors */ /* (De)constructors */
list_t *list_alloc(list_action_t delete) { list_t *list_alloc(list_action_t delete) {
list_t *list; list_t *list = xmalloc_and_zero(sizeof(list_t));
list = xmalloc_and_zero(sizeof(list_t));
list->delete = delete; list->delete = delete;
return list; return list;
@ -52,9 +50,7 @@ void list_free_node(list_t *list, list_node_t *node) {
/* Insertion and deletion */ /* Insertion and deletion */
list_node_t *list_insert_head(list_t *list, void *data) { list_node_t *list_insert_head(list_t *list, void *data) {
list_node_t *node; list_node_t *node = list_alloc_node();
node = list_alloc_node();
node->data = data; node->data = data;
node->prev = NULL; 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 *list_insert_tail(list_t *list, void *data) {
list_node_t *node; list_node_t *node = list_alloc_node();
node = list_alloc_node();
node->data = data; node->data = data;
node->next = NULL; 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 *list_insert_after(list_t *list, list_node_t *after, void *data) {
list_node_t *node; list_node_t *node = list_alloc_node();
node = list_alloc_node();
node->data = data; node->data = data;
node->next = after->next; node->next = after->next;
@ -158,6 +150,12 @@ void list_delete_tail(list_t *list) {
list_delete_node(list, list->tail); 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 */ /* Head/tail lookup */
void *list_get_head(list_t *list) { void *list_get_head(list_t *list) {
@ -177,12 +175,8 @@ void *list_get_tail(list_t *list) {
/* Fast list deletion */ /* Fast list deletion */
void list_delete_list(list_t *list) { void list_delete_list(list_t *list) {
list_node_t *node, *next; for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
for(node = list->head; node; node = next) {
next = node->next;
list_free_node(list, node); list_free_node(list, node);
}
list_free(list); list_free(list);
} }
@ -190,20 +184,12 @@ void list_delete_list(list_t *list) {
/* Traversing */ /* Traversing */
void list_foreach_node(list_t *list, list_action_node_t action) { void list_foreach_node(list_t *list, list_action_node_t action) {
list_node_t *node, *next; for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
for(node = list->head; node; node = next) {
next = node->next;
action(node); action(node);
}
} }
void list_foreach(list_t *list, list_action_t action) { void list_foreach(list_t *list, list_action_t action) {
list_node_t *node, *next; for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
for(node = list->head; node; node = next) {
next = node->next;
if(node->data) if(node->data)
action(node->data); action(node->data);
}
} }

View file

@ -1,7 +1,7 @@
/* /*
list.h -- header file for list.c list.h -- header file for list.c
Copyright (C) 2000-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -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_after(list_t *, list_node_t *, void *);
extern list_node_t *list_insert_before(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_unlink_node(list_t *, list_node_t *);
extern void list_delete_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(list_t *, list_action_t);
extern void list_foreach_node(list_t *, list_action_node_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__ */ #endif /* __TINC_LIST_H__ */

View file

@ -1,6 +1,6 @@
/* /*
logger.c -- logging code 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 2004-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -21,7 +21,11 @@
#include "system.h" #include "system.h"
#include "conf.h" #include "conf.h"
#include "meta.h"
#include "logger.h" #include "logger.h"
#include "connection.h"
#include "control_common.h"
#include "sptps.h"
debug_t debug_level = DEBUG_NOTHING; debug_t debug_level = DEBUG_NOTHING;
static logmode_t logmode = LOGMODE_STDERR; static logmode_t logmode = LOGMODE_STDERR;
@ -32,6 +36,89 @@ static FILE *logfile = NULL;
static HANDLE loghandle = NULL; static HANDLE loghandle = NULL;
#endif #endif
static const char *logident = NULL; 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) { void openlogger(const char *ident, logmode_t mode) {
logident = ident; logident = ident;
@ -66,6 +153,11 @@ void openlogger(const char *ident, logmode_t mode) {
case LOGMODE_NULL: case LOGMODE_NULL:
break; break;
} }
if(logmode != LOGMODE_NULL)
sptps_log = sptps_logger;
else
sptps_log = sptps_log_quiet;
} }
void reopenlogger() { void reopenlogger() {
@ -75,62 +167,13 @@ void reopenlogger() {
fflush(logfile); fflush(logfile);
FILE *newfile = fopen(logfilename, "a"); FILE *newfile = fopen(logfilename, "a");
if(!newfile) { 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; return;
} }
fclose(logfile); fclose(logfile);
logfile = newfile; 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) { void closelogger(void) {
switch(logmode) { 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__ #ifndef __TINC_LOGGER_H__
#define __TINC_LOGGER_H__ #define __TINC_LOGGER_H__
@ -46,11 +66,10 @@ enum {
#endif #endif
extern debug_t debug_level; extern debug_t debug_level;
extern bool logcontrol;
extern void openlogger(const char *, logmode_t); extern void openlogger(const char *, logmode_t);
extern void reopenlogger(void); 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); extern void closelogger(void);
#define ifdebug(l) if(debug_level >= DEBUG_##l)
#endif /* __TINC_LOGGER_H__ */ #endif /* __TINC_LOGGER_H__ */

View file

@ -1,6 +1,6 @@
/* /*
meta.c -- handle the meta communication 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 2000-2005 Ivo Timmermans
2006 Scott Lamb <slamb@slamb.org> 2006 Scott Lamb <slamb@slamb.org>
@ -21,7 +21,6 @@
#include "system.h" #include "system.h"
#include "splay_tree.h"
#include "cipher.h" #include "cipher.h"
#include "connection.h" #include "connection.h"
#include "logger.h" #include "logger.h"
@ -31,21 +30,38 @@
#include "utils.h" #include "utils.h"
#include "xalloc.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) { if(!c) {
logger(LOG_ERR, "send_meta() called with NULL pointer!"); logger(DEBUG_ALWAYS, LOG_ERR, "send_meta_sptps() called with NULL pointer!");
abort(); 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); c->name, c->hostname);
if(c->protocol_minor >= 2)
return sptps_send_record(&c->sptps, 0, buffer, length);
/* Add our data to buffer */ /* Add our data to buffer */
if(c->status.encryptout) { if(c->status.encryptout) {
size_t outlen = length; size_t outlen = length;
if(!cipher_encrypt(&c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || 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); c->name, c->hostname);
return false; 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) { void broadcast_meta(connection_t *from, const char *buffer, int length) {
splay_node_t *node; for list_each(connection_t, c, connection_list)
connection_t *c;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
if(c != from && c->status.active) if(c != from && c->status.active)
send_meta(c, buffer, length); 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) { bool receive_meta(connection_t *c) {
@ -88,7 +136,7 @@ bool receive_meta(connection_t *c) {
buffer_compact(&c->inbuf, MAXBUFSIZE); buffer_compact(&c->inbuf, MAXBUFSIZE);
if(sizeof inbuf <= c->inbuf.len) { 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; return false;
} }
@ -96,17 +144,20 @@ bool receive_meta(connection_t *c) {
if(inlen <= 0) { if(inlen <= 0) {
if(!inlen || !errno) { 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); c->name, c->hostname);
} else if(sockwouldblock(sockerrno)) } else if(sockwouldblock(sockerrno))
return true; return true;
else 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)); c->name, c->hostname, sockstrerror(sockerrno));
return false; return false;
} }
do { do {
if(c->protocol_minor >= 2)
return sptps_receive_data(&c->sptps, bufp, inlen);
if(!c->status.decryptin) { if(!c->status.decryptin) {
endp = memchr(bufp, '\n', inlen); endp = memchr(bufp, '\n', inlen);
if(endp) if(endp)
@ -120,10 +171,9 @@ bool receive_meta(connection_t *c) {
bufp = endp; bufp = endp;
} else { } else {
size_t outlen = inlen; 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) { 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); c->name, c->hostname);
return false; return false;
} }
@ -137,6 +187,14 @@ bool receive_meta(connection_t *c) {
if(c->tcplen) { if(c->tcplen) {
char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen); char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
if(tcpbuffer) { 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); receive_tcppacket(c, tcpbuffer, c->tcplen);
c->tcplen = 0; c->tcplen = 0;
continue; continue;

View file

@ -1,6 +1,6 @@
/* /*
meta.h -- header for meta.c 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 2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -24,6 +24,8 @@
#include "connection.h" #include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int); 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 void broadcast_meta(struct connection_t *, const char *, int);
extern bool receive_meta(struct connection_t *); extern bool receive_meta(struct connection_t *);

View file

@ -1,7 +1,7 @@
/* /*
device.c -- Interaction with Windows tap driver in a MinGW environment device.c -- Interaction with Windows tap driver in a MinGW environment
Copyright (C) 2002-2005 Ivo Timmermans, 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -50,7 +50,7 @@ static DWORD WINAPI tapreader(void *bla) {
OVERLAPPED overlapped; OVERLAPPED overlapped;
vpn_packet_t packet; 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 */ /* 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)) if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
continue; continue;
} else { } 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)); device, strerror(errno));
return -1; return -1;
} }
@ -83,7 +83,7 @@ static DWORD WINAPI tapreader(void *bla) {
} }
} }
bool setup_device(void) { static bool setup_device(void) {
HKEY key, key2; HKEY key, key2;
int i; int i;
@ -105,7 +105,7 @@ bool setup_device(void) {
/* Open registry and look for network adapters */ /* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError())); logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false; return false;
} }
@ -156,7 +156,7 @@ bool setup_device(void) {
RegCloseKey(key); RegCloseKey(key);
if(!found) { if(!found) {
logger(LOG_ERR, "No Windows tap device found!"); logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
return false; return false;
} }
@ -174,14 +174,14 @@ bool setup_device(void) {
} }
if(device_handle == INVALID_HANDLE_VALUE) { 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; return false;
} }
/* Get MAC address from tap device */ /* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) { if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
logger(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; return false;
} }
@ -194,7 +194,7 @@ bool setup_device(void) {
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL); thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
if(!thread) { 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; return false;
} }
@ -205,31 +205,31 @@ bool setup_device(void) {
device_info = "Windows tap device"; 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; return true;
} }
void close_device(void) { static void close_device(void) {
CloseHandle(device_handle); CloseHandle(device_handle);
free(device); free(device);
free(iface); free(iface);
} }
bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
return false; return false;
} }
bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
long outlen; long outlen;
OVERLAPPED overlapped = {0}; 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); packet->len, device_info);
if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) { 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; return false;
} }
@ -238,8 +238,16 @@ bool write_packet(vpn_packet_t *packet) {
return true; return true;
} }
void dump_device_stats(void) { static void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in); logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out); 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 net.c -- most of the network code
Copyright (C) 1998-2005 Ivo Timmermans, 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> 2006 Scott Lamb <slamb@slamb.org>
2011 Loïc Grenié <loic.grenie@gmail.com> 2011 Loïc Grenié <loic.grenie@gmail.com>
@ -23,7 +23,6 @@
#include "system.h" #include "system.h"
#include "utils.h" #include "utils.h"
#include "splay_tree.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
#include "device.h" #include "device.h"
@ -40,40 +39,28 @@
int contradicting_add_edge = 0; int contradicting_add_edge = 0;
int contradicting_del_edge = 0; int contradicting_del_edge = 0;
static int sleeptime = 10; static int sleeptime = 10;
time_t last_config_check = 0;
/* Purge edges and subnets of unreachable nodes. Use carefully. */ /* Purge edges and subnets of unreachable nodes. Use carefully. */
void purge(void) { void purge(void) {
splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext; logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes");
node_t *n;
edge_t *e;
subnet_t *s;
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
/* Remove all edges and subnets owned by unreachable nodes. */ /* Remove all edges and subnets owned by unreachable nodes. */
for(nnode = node_tree->head; nnode; nnode = nnext) { for splay_each(node_t, n, node_tree) {
nnext = nnode->next;
n = nnode->data;
if(!n->status.reachable) { if(!n->status.reachable) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name, logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname);
n->hostname);
for(snode = n->subnet_tree->head; snode; snode = snext) { for splay_each(subnet_t, s, n->subnet_tree) {
snext = snode->next; send_del_subnet(everyone, s);
s = snode->data;
send_del_subnet(broadcast, s);
if(!strictsubnets) if(!strictsubnets)
subnet_del(n, s); subnet_del(n, s);
} }
for(enode = n->edge_tree->head; enode; enode = enext) { for splay_each(edge_t, e, n->edge_tree) {
enext = enode->next;
e = enode->data;
if(!tunnelserver) if(!tunnelserver)
send_del_edge(broadcast, e); send_del_edge(everyone, e);
edge_del(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. */ /* 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) { for splay_each(node_t, n, node_tree) {
nnext = nnode->next;
n = nnode->data;
if(!n->status.reachable) { if(!n->status.reachable) {
for(enode = edge_weight_tree->head; enode; enode = enext) { for splay_each(edge_t, e, edge_weight_tree)
enext = enode->next;
e = enode->data;
if(e->to == n) 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 */ /* in strictsubnets mode do not delete nodes with subnets */
node_del(n); node_del(n);
} }
@ -103,25 +83,25 @@ void purge(void) {
/* /*
Terminate a connection: Terminate a connection:
- Close the socket - Mark it as inactive
- Remove associated edge and tell other connections about it if report = true - Remove the edge representing this connection
- Kill it with fire
- Check if we need to retry making an outgoing connection - Check if we need to retry making an outgoing connection
- Deactivate the host
*/ */
void terminate_connection(connection_t *c, bool report) { void terminate_connection(connection_t *c, bool report) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)", logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname);
c->name, c->hostname);
c->status.active = false; c->status.active = false;
if(c->node) if(c->node && c->node->connection == c)
c->node->connection = NULL; c->node->connection = NULL;
if(c->edge) { if(c->edge) {
if(report && !tunnelserver) if(report && !tunnelserver)
send_del_edge(broadcast, c->edge); send_del_edge(everyone, c->edge);
edge_del(c->edge); edge_del(c->edge);
c->edge = NULL;
/* Run MST and SSSP algorithms */ /* Run MST and SSSP algorithms */
@ -134,18 +114,19 @@ void terminate_connection(connection_t *c, bool report) {
e = lookup_edge(c->node, myself); e = lookup_edge(c->node, myself);
if(e) { if(e) {
if(!tunnelserver) if(!tunnelserver)
send_del_edge(broadcast, e); send_del_edge(everyone, e);
edge_del(e); edge_del(e);
} }
} }
} }
outgoing_t *outgoing = c->outgoing;
connection_del(c);
/* Check if this was our outgoing connection */ /* Check if this was our outgoing connection */
if(c->outgoing) if(outgoing)
retry_outgoing(c->outgoing); do_outgoing_connection(outgoing);
connection_del(c);
} }
/* /*
@ -157,42 +138,34 @@ void terminate_connection(connection_t *c, bool report) {
and close the connection. and close the connection.
*/ */
static void timeout_handler(int fd, short events, void *event) { static void timeout_handler(int fd, short events, void *event) {
splay_node_t *node, *next;
connection_t *c;
time_t now = time(NULL); time_t now = time(NULL);
for(node = connection_tree->head; node; node = next) { for list_each(connection_t, c, connection_list) {
next = node->next; if(c->status.control)
c = node->data; continue;
if(c->last_ping_time + pingtimeout <= now) { if(c->last_ping_time + pingtimeout <= now) {
if(c->status.active) { if(c->status.active) {
if(c->status.pinged) { if(c->status.pinged) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", 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);
c->name, c->hostname, now - c->last_ping_time);
terminate_connection(c, true);
continue;
} else if(c->last_ping_time + pinginterval <= now) { } else if(c->last_ping_time + pinginterval <= now) {
send_ping(c); send_ping(c);
} continue;
} else { } 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; 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) { 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); usleep(sleeptime * 1000000LL);
sleeptime *= 2; sleeptime *= 2;
if(sleeptime < 0) if(sleeptime < 0)
@ -222,11 +195,8 @@ void handle_meta_connection_data(int fd, short events, void *data) {
if(!result) if(!result)
finish_connecting(c); finish_connecting(c);
else { else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG, logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result));
"Error while connecting to %s (%s): %s", terminate_connection(c, false);
c->name, c->hostname, sockstrerror(result));
closesocket(c->socket);
do_outgoing_connection(c);
return; 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) { 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); event_loopexit(NULL);
} }
static void sighup_handler(int signal, short events, void *data) { 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(); reopenlogger();
reload_configuration(); reload_configuration();
} }
static void sigalrm_handler(int signal, short events, void *data) { 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(); retry();
} }
int reload_configuration(void) { int reload_configuration(void) {
connection_t *c;
splay_node_t *node, *next;
char *fname; char *fname;
struct stat s;
static time_t last_config_check = 0;
/* Reread our own configuration file */ /* Reread our own configuration file */
@ -266,85 +232,112 @@ int reload_configuration(void) {
init_configuration(&config_tree); init_configuration(&config_tree);
if(!read_server_config()) { 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); event_loopexit(NULL);
return EINVAL; 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) { xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
c = node->data; read_config_file(config_tree, fname);
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);
free(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 StrictSubnet is set, expire deleted Subnets and read new ones in */
if(strictsubnets) { if(strictsubnets) {
subnet_t *subnet; for splay_each(subnet_t, subnet, subnet_tree)
for(node = subnet_tree->head; node; node = node->next) {
subnet = node->data;
subnet->expires = 1; subnet->expires = 1;
}
load_all_subnets(); load_all_subnets();
for(node = subnet_tree->head; node; node = next) { for splay_each(subnet_t, subnet, subnet_tree) {
next = node->next;
subnet = node->data;
if(subnet->expires == 1) { if(subnet->expires == 1) {
send_del_subnet(broadcast, subnet); send_del_subnet(everyone, subnet);
if(subnet->owner->status.reachable) if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, false); subnet_update(subnet->owner, subnet, false);
subnet_del(subnet->owner, subnet); subnet_del(subnet->owner, subnet);
} else if(subnet->expires == -1) { } else if(subnet->expires == -1) {
subnet->expires = 0; subnet->expires = 0;
} else { } else {
send_add_subnet(broadcast, subnet); send_add_subnet(everyone, subnet);
if(subnet->owner->status.reachable) if(subnet->owner->status.reachable)
subnet_update(subnet->owner, subnet, true); 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 to make outgoing connections */
try_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; return 0;
} }
void retry(void) { void retry(void) {
connection_t *c; for list_each(connection_t, c, connection_list) {
splay_node_t *node;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
if(c->outgoing && !c->node) { if(c->outgoing && !c->node) {
if(timeout_initialized(&c->outgoing->ev)) if(timeout_initialized(&c->outgoing->ev))
event_del(&c->outgoing->ev); event_del(&c->outgoing->ev);
if(c->status.connecting) if(c->status.connecting)
close(c->socket); close(c->socket);
c->outgoing->timeout = 0; c->outgoing->timeout = 0;
do_outgoing_connection(c); terminate_connection(c, c->status.active);
} }
} }
} }
@ -375,7 +368,7 @@ int main_loop(void) {
#endif #endif
if(event_loop(0) < 0) { 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; return 1;
} }

View file

@ -1,7 +1,7 @@
/* /*
net.h -- header for net.c net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,8 +31,11 @@
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#endif #endif
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ /* MAXSIZE is the maximum size of an encapsulated packet: 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 */ #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... */ #define MAXSOCKETS 8 /* Probably overkill... */
@ -83,6 +86,18 @@ typedef struct vpn_packet_t {
uint8_t data[MAXSIZE]; uint8_t data[MAXSIZE];
} vpn_packet_t; } 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 { typedef struct listen_socket_t {
struct event ev_tcp; struct event ev_tcp;
struct event ev_udp; struct event ev_udp;
@ -97,6 +112,7 @@ typedef struct listen_socket_t {
typedef struct outgoing_t { typedef struct outgoing_t {
char *name; char *name;
int timeout; int timeout;
splay_tree_t *config_tree;
struct config_t *cfg; struct config_t *cfg;
struct addrinfo *ai; struct addrinfo *ai;
struct addrinfo *aip; struct addrinfo *aip;
@ -109,6 +125,7 @@ extern int maxoutbufsize;
extern int seconds_till_retry; extern int seconds_till_retry;
extern int addressfamily; extern int addressfamily;
extern unsigned replaywin; extern unsigned replaywin;
extern bool localdiscovery;
extern listen_socket_t listen_socket[MAXSOCKETS]; extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets; extern int listen_sockets;
@ -119,6 +136,24 @@ extern bool do_prune;
extern char *myport; extern char *myport;
extern int contradicting_add_edge; extern int contradicting_add_edge;
extern int contradicting_del_edge; extern int contradicting_del_edge;
extern time_t last_config_check;
extern 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 */ /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
#include "connection.h" #include "connection.h"
@ -127,20 +162,23 @@ extern int contradicting_del_edge;
extern void retry_outgoing(outgoing_t *); extern void retry_outgoing(outgoing_t *);
extern void handle_incoming_vpn_data(int, short, void *); extern void handle_incoming_vpn_data(int, short, void *);
extern void finish_connecting(struct connection_t *); 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 void handle_new_meta_connection(int, short, void *);
extern int setup_listen_socket(const sockaddr_t *); extern int setup_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_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 send_packet(struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, const char *, int); extern void receive_tcppacket(struct connection_t *, const char *, int);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *); 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 bool setup_network(void);
extern void setup_outgoing_connection(struct outgoing_t *); extern void setup_outgoing_connection(struct outgoing_t *);
extern void try_outgoing_connections(void); extern void try_outgoing_connections(void);
extern void close_network_connections(void); extern void close_network_connections(void);
extern int main_loop(void); extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool); 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 node_read_ecdsa_public_key(struct node_t *);
extern bool read_ecdsa_public_key(struct connection_t *); extern bool read_ecdsa_public_key(struct connection_t *);
extern bool read_rsa_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 net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans, 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 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com> 2010 Brandon Black <blblack@gmail.com>
@ -36,7 +36,6 @@
#include LZO1X_H #include LZO1X_H
#endif #endif
#include "splay_tree.h"
#include "cipher.h" #include "cipher.h"
#include "conf.h" #include "conf.h"
#include "connection.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 *); static void send_udppacket(node_t *, vpn_packet_t *);
unsigned replaywin = 16; unsigned replaywin = 16;
bool localdiscovery = false;
#define MAX_SEQNO 1073741824 #define MAX_SEQNO 1073741824
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval /* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
// mtuprobes == 31: sleep pinginterval seconds mtuprobes == 31: sleep pinginterval seconds
// mtuprobes == 32: send 1 burst, sleep pingtimeout second mtuprobes == 32: send 1 burst, sleep pingtimeout second
// mtuprobes == 33: no response from other side, restart PMTU discovery process 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) { static void send_mtu_probe_handler(int fd, short events, void *data) {
node_t *n = data; node_t *n = data;
vpn_packet_t packet;
int len, i;
int timeout = 1; int timeout = 1;
n->mtuprobes++; n->mtuprobes++;
if(!n->status.reachable || !n->status.validkey) { 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; n->mtuprobes = 0;
return; return;
} }
@ -91,14 +96,15 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
goto end; 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->mtuprobes = 1;
n->minmtu = 0; n->minmtu = 0;
n->maxmtu = MTU; n->maxmtu = MTU;
} }
if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) { 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; n->mtuprobes = 31;
} }
@ -108,7 +114,7 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
else else
n->maxmtu = n->minmtu; n->maxmtu = n->minmtu;
n->mtu = 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; n->mtuprobes = 31;
} }
@ -119,7 +125,9 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
timeout = pingtimeout; timeout = pingtimeout;
} }
for(i = 0; i < 3; i++) { for(int i = 0; i < 3 + localdiscovery; i++) {
int len;
if(n->maxmtu <= n->minmtu) if(n->maxmtu <= n->minmtu)
len = n->maxmtu; len = n->maxmtu;
else else
@ -128,12 +136,16 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
if(len < 64) if(len < 64)
len = 64; len = 64;
vpn_packet_t packet;
memset(packet.data, 0, 14); memset(packet.data, 0, 14);
randomize(packet.data + 14, len - 14); randomize(packet.data + 14, len - 14);
packet.len = len; packet.len = len;
if(i >= 3 && n->mtuprobes <= 10)
packet.priority = -1;
else
packet.priority = 0; 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); 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) { 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]) { if(!packet->data[0]) {
packet->data[0] = 1; packet->data[0] = 1;
send_udppacket(n, packet); send_udppacket(n, packet);
} else { } else {
n->status.udp_confirmed = true;
if(n->mtuprobes > 30) { if(n->mtuprobes > 30) {
if(n->minmtu) if(n->minmtu)
n->mtuprobes = 30; 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 */ /* VPN packet I/O */
static void receive_packet(node_t *n, vpn_packet_t *packet) { 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); packet->len, n->name, n->hostname);
n->in_packets++; 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) { 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)) if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
return false; return false;
@ -254,8 +271,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t *outpkt = pkt[0]; vpn_packet_t *outpkt = pkt[0];
size_t outlen; size_t outlen;
if(n->status.sptps) {
sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
return;
}
if(!cipher_active(&n->incipher)) { 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); n->name, n->hostname);
return; return;
} }
@ -263,7 +285,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
/* Check packet length */ /* Check packet length */
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) { 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); n->name, n->hostname);
return; return;
} }
@ -273,7 +295,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(digest_active(&n->indigest)) { if(digest_active(&n->indigest)) {
inpkt->len -= n->indigest.maclength; inpkt->len -= n->indigest.maclength;
if(!digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) { 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; return;
} }
} }
@ -284,7 +306,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
outlen = MAXSIZE; outlen = MAXSIZE;
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { 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; 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 + 1) {
if(inpkt->seqno >= n->received_seqno + replaywin * 8) { if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) { 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); n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
return; 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); inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin); memset(n->late, 0, replaywin);
} else if (inpkt->seqno <= n->received_seqno) { } 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))) { 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); n->name, n->hostname, inpkt->seqno, n->received_seqno);
return; return;
} }
@ -338,7 +360,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) { 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); n->name, n->hostname);
return; return;
} }
@ -369,6 +391,53 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
receive_packet(c->node, &outpkt); 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) { static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
vpn_packet_t pkt1, pkt2; vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &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; size_t outlen;
#if defined(SOL_IP) && defined(IP_TOS) #if defined(SOL_IP) && defined(IP_TOS)
static int priority = 0; static int priority = 0;
int origpriority = origpkt->priority;
#endif #endif
int sock; int origpriority = origpkt->priority;
if(!n->status.reachable) { 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; return;
} }
if(n->status.sptps)
return send_sptps_packet(n, origpkt);
/* Make sure we have a valid key */ /* Make sure we have a valid key */
if(!n->status.validkey) { if(!n->status.validkey) {
time_t now = time(NULL); 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", "No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname); 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])) { 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", "Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP"); 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++]; outpkt = pkt[nextpkt++];
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) { 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); n->name, n->hostname);
return; return;
} }
@ -446,7 +517,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
outlen = MAXSIZE; outlen = MAXSIZE;
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) { 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; goto end;
} }
@ -461,41 +532,221 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
inpkt->len += digest_length(&n->outdigest); 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 */ /* 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++) 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; break;
if(sock >= listen_sockets) 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 defined(SOL_IP) && defined(IP_TOS)
if(priorityinheritance && origpriority != priority 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; priority = origpriority;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority); logger(DEBUG_TRAFFIC, 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 */ if(setsockopt(listen_socket[n->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_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
} }
#endif #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(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen) if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1; n->maxmtu = origlen - 1;
if(n->mtu >= origlen) if(n->mtu >= origlen)
n->mtu = origlen - 1; n->mtu = origlen - 1;
} else } 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: end:
origpkt->len = origlen; 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. 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); memcpy(packet->data, mymac.x, ETH_ALEN);
n->out_packets++; n->out_packets++;
n->out_bytes += packet->len; n->out_bytes += packet->len;
write_packet(packet); devops.write(packet);
return; 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); packet->len, n->name, n->hostname);
if(!n->status.reachable) { 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); n->name, n->hostname);
return; return;
} }
@ -523,10 +774,15 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
n->out_packets++; n->out_packets++;
n->out_bytes += packet->len; 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; via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
if(via != n) 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); n->name, via->name, n->via->hostname);
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) { 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 */ /* Broadcast a packet using the minimum spanning tree */
void broadcast_packet(const node_t *from, vpn_packet_t *packet) { void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
splay_node_t *node; // Always give ourself a copy of the packet.
connection_t *c; if(from != myself)
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
if(from != myself) {
send_packet(myself, packet); send_packet(myself, packet);
// In TunnelServer mode, do not forward broadcast packets. // In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops. // The MST might not be valid and create loops.
if(tunnelserver) if(tunnelserver || broadcast_mode == BMODE_NONE)
return; return;
}
for(node = connection_tree->head; node; node = node->next) { logger(DEBUG_TRAFFIC, LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
c = node->data; 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) if(c->status.active && c->status.mst && c != from->nexthop->connection)
send_packet(c->node, packet); 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) { 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; node_t *n = NULL;
bool hard = false; bool hard = false;
static time_t last_hard_try = 0; static time_t last_hard_try = 0;
time_t now = time(NULL); time_t now = time(NULL);
if(last_hard_try == now) for splay_each(edge_t, e, edge_weight_tree) {
return NULL; if(!e->to->status.reachable || e->to == myself)
else
last_hard_try = now;
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
if(e->to == myself)
continue; continue;
if(sockaddrcmp_noport(from, &e->address)) { 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) if(hard)
last_hard_try = now; last_hard_try = now;
last_hard_try = now;
return n; return n;
} }
void handle_incoming_vpn_data(int sock, short events, void *data) { void handle_incoming_vpn_data(int sock, short events, void *data) {
vpn_packet_t pkt; vpn_packet_t pkt;
char *hostname; char *hostname;
sockaddr_t from; sockaddr_t from = {{0}};
socklen_t fromlen = sizeof from; socklen_t fromlen = sizeof from;
node_t *n; node_t *n;
int len; int len;
@ -612,7 +876,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
if(len <= 0 || len > MAXSIZE) { if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno)) if(!sockwouldblock(sockerrno))
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
return; return;
} }
@ -626,9 +890,9 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
n = try_harder(&from, &pkt); n = try_harder(&from, &pkt);
if(n) if(n)
update_node_udp(n, &from); update_node_udp(n, &from);
else ifdebug(PROTOCOL) { else if(debug_level >= DEBUG_PROTOCOL) {
hostname = sockaddr2hostname(&from); 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); free(hostname);
return; return;
} }
@ -636,6 +900,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
return; return;
} }
n->sock = (intptr_t)data;
receive_udppacket(n, &pkt); receive_udppacket(n, &pkt);
} }
@ -644,7 +910,7 @@ void handle_device_data(int sock, short events, void *data) {
packet.priority = 0; packet.priority = 0;
if(read_packet(&packet)) { if(devops.read(&packet)) {
myself->in_packets++; myself->in_packets++;
myself->in_bytes += packet.len; myself->in_bytes += packet.len;
route(myself, &packet); route(myself, &packet);

View file

@ -1,7 +1,7 @@
/* /*
net_setup.c -- Setup. net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans, 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> 2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com> 2010 Brandon Black <blblack@gmail.com>
@ -22,7 +22,6 @@
#include "system.h" #include "system.h"
#include "splay_tree.h"
#include "cipher.h" #include "cipher.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
@ -44,6 +43,16 @@
char *myport; char *myport;
static struct event device_ev; 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) { bool node_read_ecdsa_public_key(node_t *n) {
if(ecdsa_active(&n->ecdsa)) if(ecdsa_active(&n->ecdsa))
@ -51,14 +60,14 @@ bool node_read_ecdsa_public_key(node_t *n) {
splay_tree_t *config_tree; splay_tree_t *config_tree;
FILE *fp; FILE *fp;
char *fname; char *pubname = NULL, *hcfname = NULL;
char *p; char *p;
bool result = false; 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); init_configuration(&config_tree);
if(!read_config_file(config_tree, fname)) if(!read_config_file(config_tree, hcfname))
goto exit; goto exit;
/* First, check for simple ECDSAPublicKey statement */ /* 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 */ /* 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)) fp = fopen(pubname, "r");
xasprintf(&fname, "%s/hosts/%s", confbase, n->name);
fp = fopen(fname, "r");
if(!fp) { 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; goto exit;
} }
@ -88,7 +95,8 @@ bool node_read_ecdsa_public_key(node_t *n) {
exit: exit:
exit_configuration(&config_tree); exit_configuration(&config_tree);
free(fname); free(hcfname);
free(pubname);
return result; return result;
} }
@ -109,12 +117,12 @@ bool read_ecdsa_public_key(connection_t *c) {
/* Else, check for ECDSAPublicKeyFile statement and read it */ /* Else, check for ECDSAPublicKeyFile statement and read it */
if(!get_config_string(lookup_config(c->config_tree, "ECDSAPublicKeyFile"), &fname)) 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"); fp = fopen(fname, "r");
if(!fp) { 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)); fname, strerror(errno));
free(fname); free(fname);
return false; return false;
@ -124,7 +132,7 @@ bool read_ecdsa_public_key(connection_t *c) {
fclose(fp); fclose(fp);
if(!result) 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); free(fname);
return result; return result;
} }
@ -146,13 +154,12 @@ bool read_rsa_public_key(connection_t *c) {
/* Else, check for PublicKeyFile statement and read it */ /* Else, check for PublicKeyFile statement and read it */
if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) 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"); fp = fopen(fname, "r");
if(!fp) { if(!fp) {
logger(LOG_ERR, "Error reading RSA public key file `%s': %s", logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
fname, strerror(errno));
free(fname); free(fname);
return false; return false;
} }
@ -161,7 +168,7 @@ bool read_rsa_public_key(connection_t *c) {
fclose(fp); fclose(fp);
if(!result) 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); free(fname);
return result; return result;
} }
@ -174,13 +181,12 @@ static bool read_ecdsa_private_key(void) {
/* Check for PrivateKeyFile statement and read it */ /* Check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "ECDSAPrivateKeyFile"), &fname)) 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"); fp = fopen(fname, "r");
if(!fp) { if(!fp) {
logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s", logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
fname, strerror(errno));
free(fname); free(fname);
return false; return false;
} }
@ -189,20 +195,20 @@ static bool read_ecdsa_private_key(void) {
struct stat s; struct stat s;
if(fstat(fileno(fp), &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); free(fname);
return false; return false;
} }
if(s.st_mode & ~0100700) 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 #endif
result = ecdsa_read_pem_private_key(&myself->connection->ecdsa, fp); result = ecdsa_read_pem_private_key(&myself->connection->ecdsa, fp);
fclose(fp); fclose(fp);
if(!result) 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); free(fname);
return result; 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, "PrivateKey"), &d)) {
if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) { 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); free(d);
return false; return false;
} }
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d); result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
free(n); free(n);
free(d); free(d);
return true; return result;
} }
/* Else, check for PrivateKeyFile statement and read it */ /* Else, check for PrivateKeyFile statement and read it */
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) 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"); fp = fopen(fname, "r");
if(!fp) { 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)); fname, strerror(errno));
free(fname); free(fname);
return false; return false;
@ -245,20 +251,20 @@ static bool read_rsa_private_key(void) {
struct stat s; struct stat s;
if(fstat(fileno(fp), &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); free(fname);
return false; return false;
} }
if(s.st_mode & ~0100700) 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 #endif
result = rsa_read_pem_private_key(&myself->connection->rsa, fp); result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
fclose(fp); fclose(fp);
if(!result) 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); free(fname);
return result; return result;
} }
@ -271,7 +277,7 @@ static void keyexpire_handler(int fd, short events, void *data) {
void regenerate_key(void) { void regenerate_key(void) {
if(timeout_initialized(&keyexpire_event)) { 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); event_del(&keyexpire_event);
send_key_changed(); send_key_changed();
} else { } else {
@ -288,17 +294,11 @@ void load_all_subnets(void) {
DIR *dir; DIR *dir;
struct dirent *ent; struct dirent *ent;
char *dname; 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); dir = opendir(dname);
if(!dir) { 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); free(dname);
return; return;
} }
@ -307,18 +307,20 @@ void load_all_subnets(void) {
if(!check_id(ent->d_name)) if(!check_id(ent->d_name))
continue; continue;
n = lookup_node(ent->d_name); node_t *n = lookup_node(ent->d_name);
#ifdef _DIRENT_HAVE_D_TYPE #ifdef _DIRENT_HAVE_D_TYPE
//if(ent->d_type != DT_REG) //if(ent->d_type != DT_REG)
// continue; // continue;
#endif #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); 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); free(fname);
if(!result)
continue;
if(!n) { if(!n) {
n = new_node(); n = new_node();
@ -326,7 +328,9 @@ void load_all_subnets(void) {
node_add(n); 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)) if(!get_config_subnet(cfg, &s))
continue; continue;
@ -343,84 +347,127 @@ void load_all_subnets(void) {
closedir(dir); closedir(dir);
} }
/* char *get_name(void) {
Configure node_t myself and set up the local sockets (listen only) char *name = NULL;
*/
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;
myself = new_node(); get_config_string(lookup_config(config_tree, "Name"), &name);
myself->connection = new_connection();
myself->hostname = xstrdup("MYSELF"); if(!name)
myself->connection->hostname = xstrdup("MYSELF"); return NULL;
myself->connection->options = 0; if(*name == '$') {
myself->connection->protocol_major = PROT_MAJOR; char *envname = getenv(name + 1);
myself->connection->protocol_minor = PROT_MINOR; if(!envname) {
if(strcmp(name + 1, "HOST")) {
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */ logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
logger(LOG_ERR, "Name for tinc daemon required!");
return false; 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)) { if(!check_id(name)) {
logger(LOG_ERR, "Invalid name for myself!"); logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
free(name); free(name);
return false; return false;
} }
myself->name = name; return 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);
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; 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"); case PROXY_EXEC:
if(!space || !*space) {
while(cfg) { logger(DEBUG_ALWAYS, LOG_ERR, "Argument expected for proxy type exec!");
if(!get_config_subnet(cfg, &subnet))
return false; return false;
}
proxyhost = xstrdup(space);
break;
subnet_add(myself, subnet); case PROXY_SOCKS4:
case PROXY_SOCKS4A:
cfg = lookup_config_next(config_tree, cfg); 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) if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
myself->options |= OPTION_INDIRECT; myself->options |= OPTION_INDIRECT;
@ -432,36 +479,34 @@ static bool setup_myself(void) {
myself->options |= OPTION_INDIRECT; myself->options |= OPTION_INDIRECT;
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); 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, "LocalDiscovery"), &localdiscovery);
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
strictsubnets |= tunnelserver;
if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) { if(get_config_string(lookup_config(config_tree, "Mode"), &rmode)) {
if(!strcasecmp(mode, "router")) if(!strcasecmp(rmode, "router"))
routing_mode = RMODE_ROUTER; routing_mode = RMODE_ROUTER;
else if(!strcasecmp(mode, "switch")) else if(!strcasecmp(rmode, "switch"))
routing_mode = RMODE_SWITCH; routing_mode = RMODE_SWITCH;
else if(!strcasecmp(mode, "hub")) else if(!strcasecmp(rmode, "hub"))
routing_mode = RMODE_HUB; routing_mode = RMODE_HUB;
else { else {
logger(LOG_ERR, "Invalid routing mode!"); logger(DEBUG_ALWAYS, LOG_ERR, "Invalid routing mode!");
return false; return false;
} }
free(mode); free(rmode);
} }
if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { if(get_config_string(lookup_config(config_tree, "Forwarding"), &fmode)) {
if(!strcasecmp(mode, "off")) if(!strcasecmp(fmode, "off"))
forwarding_mode = FMODE_OFF; forwarding_mode = FMODE_OFF;
else if(!strcasecmp(mode, "internal")) else if(!strcasecmp(fmode, "internal"))
forwarding_mode = FMODE_INTERNAL; forwarding_mode = FMODE_INTERNAL;
else if(!strcasecmp(mode, "kernel")) else if(!strcasecmp(fmode, "kernel"))
forwarding_mode = FMODE_KERNEL; forwarding_mode = FMODE_KERNEL;
else { else {
logger(LOG_ERR, "Invalid forwarding mode!"); logger(DEBUG_ALWAYS, LOG_ERR, "Invalid forwarding mode!");
return false; return false;
} }
free(mode); free(fmode);
} }
choice = true; choice = true;
@ -475,10 +520,24 @@ static bool setup_myself(void) {
myself->options |= OPTION_CLAMP_MSS; myself->options |= OPTION_CLAMP_MSS;
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); 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 !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance) 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 #endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) 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(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
if(maxtimeout <= 0) { if(maxtimeout <= 0) {
logger(LOG_ERR, "Bogus maximum timeout!"); logger(DEBUG_ALWAYS, LOG_ERR, "Bogus maximum timeout!");
return false; return false;
} }
} else } else
maxtimeout = 900; 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(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
if(!strcasecmp(afname, "IPv4")) if(!strcasecmp(afname, "IPv4"))
addressfamily = AF_INET; addressfamily = AF_INET;
@ -522,7 +559,7 @@ static bool setup_myself(void) {
else if(!strcasecmp(afname, "any")) else if(!strcasecmp(afname, "any"))
addressfamily = AF_UNSPEC; addressfamily = AF_UNSPEC;
else { else {
logger(LOG_ERR, "Invalid address family!"); logger(DEBUG_ALWAYS, LOG_ERR, "Invalid address family!");
return false; return false;
} }
free(afname); free(afname);
@ -530,44 +567,149 @@ static bool setup_myself(void) {
get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames); 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 */ /* Generate packet encryption key */
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
cipher = xstrdup("blowfish"); cipher = xstrdup("blowfish");
if(!cipher_open_by_name(&myself->incipher, cipher)) { if(!cipher_open_by_name(&myself->incipher, cipher)) {
logger(LOG_ERR, "Unrecognized cipher type!"); logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
return false; return false;
} }
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) free(cipher);
keylifetime = 3600;
regenerate_key(); regenerate_key();
/* Check if we want to use message authentication codes... */ /* 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; int maclength = 4;
get_config_int(lookup_config(config_tree, "MACLength"), &maclength); get_config_int(lookup_config(config_tree, "MACLength"), &maclength);
if(maclength < 0) { if(maclength < 0) {
logger(LOG_ERR, "Bogus MAC length!"); logger(DEBUG_ALWAYS, LOG_ERR, "Bogus MAC length!");
return false; return false;
} }
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
digest = xstrdup("sha1");
if(!digest_open_by_name(&myself->indigest, digest, maclength)) { 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; return false;
} }
free(digest);
/* Compression */ /* Compression */
if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) { if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
if(myself->incompression < 0 || myself->incompression > 11) { if(myself->incompression < 0 || myself->incompression > 11) {
logger(LOG_ERR, "Bogus compression level!"); logger(DEBUG_ALWAYS, LOG_ERR, "Bogus compression level!");
return false; return false;
} }
} else } else
@ -580,6 +722,8 @@ static bool setup_myself(void) {
myself->nexthop = myself; myself->nexthop = myself;
myself->via = myself; myself->via = myself;
myself->status.reachable = true; myself->status.reachable = true;
myself->last_state_change = time(NULL);
myself->status.sptps = experimental;
node_add(myself); node_add(myself);
graph(); graph();
@ -589,20 +733,40 @@ static bool setup_myself(void) {
/* Open device */ /* 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; return false;
if(device_fd >= 0) { if(device_fd >= 0) {
event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL); event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
if (event_add(&device_ev, NULL) < 0) { if (event_add(&device_ev, NULL) < 0) {
logger(LOG_ERR, "event_add failed: %s", strerror(errno)); logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
close_device(); devops.close();
return false; return false;
} }
} }
/* Run tinc-up script to further initialize the tap interface */ /* Run tinc-up script to further initialize the tap interface */
char *envp[5];
xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
@ -611,7 +775,7 @@ static bool setup_myself(void) {
execute_script("tinc-up", envp); execute_script("tinc-up", envp);
for(i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
free(envp[i]); free(envp[i]);
/* Run subnet-up scripts for our own subnets */ /* Run subnet-up scripts for our own subnets */
@ -620,24 +784,100 @@ static bool setup_myself(void) {
/* Open sockets */ /* 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_family = addressfamily;
hint.ai_socktype = SOCK_STREAM; hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP; hint.ai_protocol = IPPROTO_TCP;
hint.ai_flags = AI_PASSIVE; 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) { 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)); gai_strerror(err));
return false; 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 = listen_socket[listen_sockets].tcp =
setup_listen_socket((sockaddr_t *) aip->ai_addr); setup_listen_socket((sockaddr_t *) aip->ai_addr);
@ -657,43 +897,42 @@ static bool setup_myself(void) {
EV_READ|EV_PERSIST, EV_READ|EV_PERSIST,
handle_new_meta_connection, NULL); handle_new_meta_connection, NULL);
if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) { 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(); abort();
} }
event_set(&listen_socket[listen_sockets].ev_udp, event_set(&listen_socket[listen_sockets].ev_udp,
listen_socket[listen_sockets].udp, listen_socket[listen_sockets].udp,
EV_READ|EV_PERSIST, 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) { 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(); abort();
} }
ifdebug(CONNECTIONS) { if(debug_level >= DEBUG_CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); 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); free(hostname);
} }
memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
listen_sockets++; listen_sockets++;
if(listen_sockets >= MAXSOCKETS) {
logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
break;
}
} }
freeaddrinfo(ai); freeaddrinfo(ai);
} while(cfg);
}
if(listen_sockets) if(listen_sockets)
logger(LOG_NOTICE, "Ready"); logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
else { else {
logger(LOG_ERR, "Unable to create any listening socket!"); logger(DEBUG_ALWAYS, LOG_ERR, "Unable to create any listening socket!");
return false; return false;
} }
last_config_check = time(NULL);
return true; return true;
} }
@ -732,14 +971,12 @@ bool setup_network(void) {
close all open network connections close all open network connections
*/ */
void close_network_connections(void) { void close_network_connections(void) {
splay_node_t *node, *next; for(list_node_t *node = connection_list->head, *next; node; node = next) {
connection_t *c;
char *envp[5];
int i;
for(node = connection_tree->head; node; node = next) {
next = 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; c->outgoing = NULL;
terminate_connection(c, false); terminate_connection(c, false);
} }
@ -752,13 +989,14 @@ void close_network_connections(void) {
free_connection(myself->connection); 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_tcp);
event_del(&listen_socket[i].ev_udp); event_del(&listen_socket[i].ev_udp);
close(listen_socket[i].tcp); close(listen_socket[i].tcp);
close(listen_socket[i].udp); close(listen_socket[i].udp);
} }
char *envp[5];
xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
@ -775,10 +1013,10 @@ void close_network_connections(void) {
if(myport) free(myport); if(myport) free(myport);
for(i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
free(envp[i]); free(envp[i]);
close_device(); devops.close();
return; return;
} }

View file

@ -1,7 +1,7 @@
/* /*
net_socket.c -- Handle various kinds of sockets. net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans, 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> 2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org> 2009 Florian Forster <octo@verplant.org>
@ -22,9 +22,9 @@
#include "system.h" #include "system.h"
#include "splay_tree.h"
#include "conf.h" #include "conf.h"
#include "connection.h" #include "connection.h"
#include "list.h"
#include "logger.h" #include "logger.h"
#include "meta.h" #include "meta.h"
#include "net.h" #include "net.h"
@ -33,8 +33,6 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
#include <assert.h>
/* Needed on Mac OS/X */ /* Needed on Mac OS/X */
#ifndef SOL_TCP #ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP #define SOL_TCP IPPROTO_TCP
@ -59,13 +57,13 @@ static void configure_tcp(connection_t *c) {
int flags = fcntl(c->socket, F_GETFL); int flags = fcntl(c->socket, F_GETFL);
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) { 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) #elif defined(WIN32)
unsigned long arg = 1; unsigned long arg = 1;
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) { 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 #endif
@ -98,74 +96,17 @@ static bool bind_to_interface(int sd) {
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)); status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
if(status) { 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)); strerror(errno));
return false; return false;
} }
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */ #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 #endif
return true; 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 setup_listen_socket(const sockaddr_t *sa) {
int nfd; int nfd;
char *addrstr; char *addrstr;
@ -175,10 +116,14 @@ int setup_listen_socket(const sockaddr_t *sa) {
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP); nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(nfd < 0) { 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; return -1;
} }
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
/* Optimize TCP settings */ /* Optimize TCP settings */
option = 1; 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)) { if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) {
closesocket(nfd); 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)); strerror(sockerrno));
return -1; return -1;
} }
#else #else
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface"); logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "BindToInterface");
#endif #endif
} }
if(bind(nfd, &sa->sa, SALEN(sa->sa))) { if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd); closesocket(nfd);
addrstr = sockaddr2hostname(sa); 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); free(addrstr);
return -1; return -1;
} }
if(listen(nfd, 3)) { if(listen(nfd, 3)) {
closesocket(nfd); 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; 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); nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
if(nfd < 0) { 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; return -1;
} }
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK #ifdef O_NONBLOCK
{ {
int flags = fcntl(nfd, F_GETFL); int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd); closesocket(nfd);
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno)); strerror(errno));
return -1; return -1;
} }
@ -253,7 +202,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
unsigned long arg = 1; unsigned long arg = 1;
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
closesocket(nfd); 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; return -1;
} }
} }
@ -261,12 +210,13 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
option = 1; option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); 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))) 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))) 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 defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6) 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))) { if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd); closesocket(nfd);
addrstr = sockaddr2hostname(sa); 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); free(addrstr);
return -1; return -1;
} }
@ -334,14 +284,15 @@ void retry_outgoing(outgoing_t *outgoing) {
timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing); timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0}); 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", "Trying to re-establish outgoing connection in %d seconds",
outgoing->timeout); outgoing->timeout);
} }
void finish_connecting(connection_t *c) { 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); configure_tcp(c);
c->last_ping_time = time(NULL); c->last_ping_time = time(NULL);
@ -350,113 +301,68 @@ void finish_connecting(connection_t *c) {
send_id(c); send_id(c);
} }
bool do_outgoing_connection(connection_t *c) { static void do_outgoing_pipe(connection_t *c, char *command) {
char *address, *port, *space; #ifndef HAVE_MINGW
int result; int fd[2];
if(!c->outgoing) { if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name); logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s", strerror(errno));
abort(); return;
} }
begin: if(fork()) {
if(!c->outgoing->ai) { c->socket = fd[0];
if(!c->outgoing->cfg) { close(fd[1]);
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s", logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Using proxy %s", command);
c->name); return;
retry_outgoing(c->outgoing);
c->outgoing = NULL;
connection_del(c);
return false;
} }
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, ' '); // Other filedescriptors should be closed automatically by CLOEXEC
if(space) {
port = xstrdup(space + 1);
*space = 0;
} else {
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
port = xstrdup("655");
}
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM); char *host = NULL;
free(address); char *port = NULL;
free(port);
c->outgoing->aip = c->outgoing->ai; sockaddr2str(&c->address, &host, &port);
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg); 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) { int result = system(command);
if(c->outgoing->ai) if(result < 0)
freeaddrinfo(c->outgoing->ai); logger(DEBUG_ALWAYS, LOG_ERR, "Could not execute %s: %s", command, strerror(errno));
c->outgoing->ai = NULL; else if(result)
goto begin; logger(DEBUG_ALWAYS, LOG_ERR, "%s exited with non-zero status %d", command, result);
} exit(result);
#else
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen); logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type exec not supported on this platform!");
c->outgoing->aip = c->outgoing->aip->ai_next; return;
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);
#endif #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) { static void handle_meta_write(int sock, short events, void *data) {
ifdebug(META) logger(LOG_DEBUG, "handle_meta_write() called");
connection_t *c = data; connection_t *c = data;
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0); ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
if(outlen <= 0) { if(outlen <= 0) {
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); terminate_connection(c, c->status.active);
return; return;
} }
@ -466,51 +372,151 @@ static void handle_meta_write(int sock, short events, void *data) {
event_del(&c->outevent); event_del(&c->outevent);
} }
void setup_outgoing_connection(outgoing_t *outgoing) {
connection_t *c;
node_t *n;
if(event_initialized(&outgoing->ev)) bool do_outgoing_connection(outgoing_t *outgoing) {
event_del(&outgoing->ev); char *address, *port, *space;
struct addrinfo *proxyai = NULL;
int result;
n = lookup_node(outgoing->name); begin:
if(!outgoing->ai) {
if(n) if(!outgoing->cfg) {
if(n->connection) { logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name); retry_outgoing(outgoing);
return false;
n->connection->outgoing = outgoing;
return;
} }
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->name = xstrdup(outgoing->name);
c->outcipher = myself->connection->outcipher; c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest; c->outdigest = myself->connection->outdigest;
c->outmaclength = myself->connection->outmaclength; c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression; c->outcompression = myself->connection->outcompression;
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); c->last_ping_time = time(NULL);
connection_add(c); 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->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_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
event_add(&c->inevent, NULL); 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); fd = accept(sock, &sa.sa, &len);
if(fd < 0) { 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; return;
} }
@ -544,7 +550,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
c->socket = fd; c->socket = fd;
c->last_ping_time = time(NULL); 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->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_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) { static void free_outgoing(outgoing_t *outgoing) {
if(event_initialized(&outgoing->ev))
event_del(&outgoing->ev);
if(outgoing->ai) if(outgoing->ai)
freeaddrinfo(outgoing->ai); freeaddrinfo(outgoing->ai);
if(outgoing->config_tree)
exit_configuration(&outgoing->config_tree);
if(outgoing->name) if(outgoing->name)
free(outgoing->name); free(outgoing->name);
@ -569,26 +581,60 @@ static void free_outgoing(outgoing_t *outgoing) {
} }
void try_outgoing_connections(void) { void try_outgoing_connections(void) {
static config_t *cfg = NULL; /* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
char *name;
outgoing_t *outgoing;
if(!outgoing_list) {
outgoing_list = list_alloc((list_action_t)free_outgoing); 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); get_config_string(cfg, &name);
if(!check_id(name)) { if(!check_id(name)) {
logger(LOG_ERR, logger(DEBUG_ALWAYS, LOG_ERR,
"Invalid name for outgoing connection in %s line %d", "Invalid name for outgoing connection in %s line %d",
cfg->file, cfg->line); cfg->file, cfg->line);
free(name); free(name);
continue; 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; outgoing->name = name;
list_insert_tail(outgoing_list, outgoing); list_insert_tail(outgoing_list, outgoing);
setup_outgoing_connection(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 netutl.c -- some supporting network utility code
Copyright (C) 1998-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -42,7 +42,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
err = getaddrinfo(address, service, &hint, &ai); err = getaddrinfo(address, service, &hint, &ai);
if(err) { 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)); service, gai_strerror(err));
return NULL; return NULL;
} }
@ -62,8 +62,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port) {
err = getaddrinfo(address, port, &hint, &ai); err = getaddrinfo(address, port, &hint, &ai);
if(err || !ai) { if(err || !ai) {
ifdebug(SCARY_THINGS) logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Unknown type address %s port %s", address, port);
logger(LOG_DEBUG, "Unknown type address %s port %s", address, port);
result.sa.sa_family = AF_UNKNOWN; result.sa.sa_family = AF_UNKNOWN;
result.unknown.address = xstrdup(address); result.unknown.address = xstrdup(address);
result.unknown.port = xstrdup(port); result.unknown.port = xstrdup(port);
@ -83,7 +82,9 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
int err; int err;
if(sa->sa.sa_family == AF_UNKNOWN) { if(sa->sa.sa_family == AF_UNKNOWN) {
if(addrstr)
*addrstr = xstrdup(sa->unknown.address); *addrstr = xstrdup(sa->unknown.address);
if(portstr)
*portstr = xstrdup(sa->unknown.port); *portstr = xstrdup(sa->unknown.port);
return; 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); err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
if(err) { if(err) {
logger(LOG_ERR, "Error while translating addresses: %s", logger(DEBUG_ALWAYS, LOG_ERR, "Error while translating addresses: %s",
gai_strerror(err)); gai_strerror(err));
abort(); abort();
} }
@ -121,7 +122,7 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
if(err) { 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)); 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)); return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
default: 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); a->sa.sa_family);
abort(); 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); return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
default: 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); a->sa.sa_family);
abort(); abort();
} }
@ -224,71 +225,3 @@ void sockaddrunmap(sockaddr_t *sa) {
sa->in.sin_family = AF_INET; 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 netutl.h -- header file for netutl.c
Copyright (C) 1998-2005 Ivo Timmermans 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -34,9 +34,5 @@ extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
extern void sockaddrunmap(sockaddr_t *); extern void sockaddrunmap(sockaddr_t *);
extern void sockaddrfree(sockaddr_t *); extern void sockaddrfree(sockaddr_t *);
extern void sockaddrcpy(sockaddr_t *, const 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__ */ #endif /* __TINC_NETUTL_H__ */

View file

@ -1,6 +1,6 @@
/* /*
node.c -- node tree management 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 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -21,16 +21,17 @@
#include "system.h" #include "system.h"
#include "control_common.h" #include "control_common.h"
#include "splay_tree.h" #include "hash.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
#include "netutl.h" #include "netutl.h"
#include "node.h" #include "node.h"
#include "splay_tree.h"
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
splay_tree_t *node_tree; /* Known nodes, sorted by name */ splay_tree_t *node_tree;
splay_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ static hash_t *node_udp_cache;
node_t *myself; 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); 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) { void init_nodes(void) {
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node); 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) { void exit_nodes(void) {
splay_delete_tree(node_udp_tree); hash_free(node_udp_cache);
splay_delete_tree(node_tree); splay_delete_tree(node_tree);
} }
@ -85,8 +75,8 @@ void free_node(node_t *n) {
cipher_close(&n->outcipher); cipher_close(&n->outcipher);
digest_close(&n->outdigest); digest_close(&n->outdigest);
ecdh_free(&n->ecdh);
ecdsa_free(&n->ecdsa); ecdsa_free(&n->ecdsa);
sptps_stop(&n->sptps);
if(timeout_initialized(&n->mtuevent)) if(timeout_initialized(&n->mtuevent))
event_del(&n->mtuevent); event_del(&n->mtuevent);
@ -108,23 +98,12 @@ void node_add(node_t *n) {
} }
void node_del(node_t *n) { void node_del(node_t *n) {
splay_node_t *node, *next; for splay_each(subnet_t, s, n->subnet_tree)
edge_t *e;
subnet_t *s;
for(node = n->subnet_tree->head; node; node = next) {
next = node->next;
s = node->data;
subnet_del(n, s); subnet_del(n, s);
}
for(node = n->edge_tree->head; node; node = next) { for splay_each(edge_t, e, n->edge_tree)
next = node->next;
e = node->data;
edge_del(e); edge_del(e);
}
splay_delete(node_udp_tree, n);
splay_delete(node_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 *lookup_node_udp(const sockaddr_t *sa) {
node_t n = {NULL}; return hash_search(node_udp_cache, sa);
n.address = *sa;
n.name = NULL;
return splay_search(node_udp_tree, &n);
} }
void update_node_udp(node_t *n, const sockaddr_t *sa) { void update_node_udp(node_t *n, const sockaddr_t *sa) {
if(n == myself) { 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; return;
} }
splay_delete(node_udp_tree, n); hash_insert(node_udp_cache, &n->address, NULL);
if(n->hostname)
free(n->hostname);
if(sa) { if(sa) {
n->address = *sa; n->address = *sa;
hash_insert(node_udp_cache, sa, n);
free(n->hostname);
n->hostname = sockaddr2hostname(&n->address); n->hostname = sockaddr2hostname(&n->address);
splay_insert(node_udp_tree, n); logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
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);
} }
} }
bool dump_nodes(connection_t *c) { bool dump_nodes(connection_t *c) {
splay_node_t *node; for splay_each(node_t, n, node_tree)
node_t *n; 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),
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),
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression, 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->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); return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
} }
bool dump_traffic(connection_t *c) { bool dump_traffic(connection_t *c) {
splay_node_t *node; for splay_each(node_t, n, node_tree)
node_t *n;
for(node = node_tree->head; node; node = node->next) {
n = node->data;
send_request(c, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_TRAFFIC, 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); n->name, n->in_packets, n->in_bytes, n->out_packets, n->out_bytes);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC); return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
} }

View file

@ -1,6 +1,6 @@
/* /*
node.h -- header for node.c 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 2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -25,32 +25,34 @@
#include "cipher.h" #include "cipher.h"
#include "connection.h" #include "connection.h"
#include "digest.h" #include "digest.h"
#include "ecdh.h"
#include "subnet.h" #include "subnet.h"
typedef struct node_status_t { typedef struct node_status_t {
unsigned int unused_active:1; /* 1 if active (not used for nodes) */ 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 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 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 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 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 sptps:1; /* 1 if this node supports SPTPS */
unsigned int unused:25; unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */
unsigned int unused:24;
} node_status_t; } node_status_t;
typedef struct node_t { typedef struct node_t {
char *name; /* name of this node */ char *name; /* name of this node */
uint32_t options; /* options turned on for 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 */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */ char *hostname; /* the hostname of its real ip */
node_status_t status; node_status_t status;
time_t last_state_change;
time_t last_req_key; time_t last_req_key;
ecdsa_t ecdsa; /* His public ECDSA 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 */ cipher_t incipher; /* Cipher for UDP packets */
digest_t indigest; /* Digest for UDP packets */ digest_t indigest; /* Digest for UDP packets */
@ -63,6 +65,7 @@ typedef struct node_t {
int distance; int distance;
struct node_t *nexthop; /* nearest node from us to him */ 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 */ struct node_t *via; /* next hop for UDP packets */
splay_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ 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 struct node_t *myself;
extern splay_tree_t *node_tree; extern splay_tree_t *node_tree;
extern splay_tree_t *node_udp_tree;
extern void init_nodes(void); extern void init_nodes(void);
extern void exit_nodes(void); extern void exit_nodes(void);

View file

@ -1,6 +1,6 @@
/* /*
cipher.c -- Symmetric block cipher handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -26,6 +26,12 @@
#include "logger.h" #include "logger.h"
#include "xalloc.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) { static bool cipher_open(cipher_t *cipher) {
EVP_CIPHER_CTX_init(&cipher->ctx); EVP_CIPHER_CTX_init(&cipher->ctx);
@ -38,7 +44,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
if(cipher->cipher) if(cipher->cipher)
return cipher_open(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; return false;
} }
@ -48,7 +54,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
if(cipher->cipher) if(cipher->cipher)
return cipher_open(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; return false;
} }
@ -59,10 +65,12 @@ bool cipher_open_blowfish_ofb(cipher_t *cipher) {
void cipher_close(cipher_t *cipher) { void cipher_close(cipher_t *cipher) {
EVP_CIPHER_CTX_cleanup(&cipher->ctx); EVP_CIPHER_CTX_cleanup(&cipher->ctx);
free(cipher->counter);
cipher->counter = NULL;
} }
size_t cipher_keylength(const cipher_t *cipher) { 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) { 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) if(result)
return true; 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; return false;
} }
@ -91,28 +99,92 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
if(result) if(result)
return true; 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; 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) { bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
if(oneshot) { if(oneshot) {
int len, pad; int len, pad;
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL) if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) && EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) { && EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
*outlen = len + pad; if(outlen) *outlen = len + pad;
return true; return true;
} }
} else { } else {
int len; int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) { if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
*outlen = len; if(outlen) *outlen = len;
return true; 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; 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) if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen) && EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) { && EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
*outlen = len + pad; if(outlen) *outlen = len + pad;
return true; return true;
} }
} else { } else {
int len; int len;
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) { if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
*outlen = len; if(outlen) *outlen = len;
return true; 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; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
cipher.h -- header file cipher.c 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -29,6 +29,7 @@
typedef struct cipher { typedef struct cipher {
EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX ctx;
const EVP_CIPHER *cipher; const EVP_CIPHER *cipher;
struct cipher_counter *counter;
} cipher_t; } cipher_t;
extern bool cipher_open_by_name(cipher_t *, const char *); 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 size_t cipher_keylength(const cipher_t *);
extern bool cipher_set_key(cipher_t *, void *, bool); 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_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_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_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 int cipher_get_nid(const cipher_t *);
extern bool cipher_active(const cipher_t *); extern bool cipher_active(const cipher_t *);

View file

@ -1,6 +1,6 @@
/* /*
digest.c -- Digest handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -41,7 +41,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
digest->key = NULL; digest->key = NULL;
if(!digest->digest) { if(!digest->digest) {
logger(LOG_DEBUG, "Unknown digest name '%s'!", name); logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
return false; return false;
} }
@ -54,7 +54,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
digest->key = NULL; digest->key = NULL;
if(!digest->digest) { if(!digest->digest) {
logger(LOG_DEBUG, "Unknown digest nid %d!", nid); logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
return false; 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) { void digest_close(digest_t *digest) {
if(digest->key)
free(digest->key); free(digest->key);
digest->key = NULL; 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) if(!EVP_DigestInit(&ctx, digest->digest)
|| !EVP_DigestUpdate(&ctx, indata, inlen) || !EVP_DigestUpdate(&ctx, indata, inlen)
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) { || !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; return false;
} }
} }
@ -115,6 +114,10 @@ int digest_get_nid(const digest_t *digest) {
return digest->digest ? digest->digest->type : 0; 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) { size_t digest_length(const digest_t *digest) {
return digest->maclength; return digest->maclength;
} }

View file

@ -1,6 +1,6 @@
/* /*
digest.h -- header file digest.c 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -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_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 bool digest_set_key(struct digest *, const void *key, size_t len);
extern int digest_get_nid(const struct digest *); 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 size_t digest_length(const struct digest *);
extern bool digest_active(const struct digest *); extern bool digest_active(const struct digest *);

View file

@ -1,6 +1,6 @@
/* /*
ecdh.c -- Diffie-Hellman key exchange handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -30,21 +30,32 @@
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) { bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1); *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)) { if(!EC_KEY_generate_key(*ecdh)) {
logger(LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL)); EC_KEY_free(*ecdh);
abort(); *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); const EC_POINT *point = EC_KEY_get0_public_key(*ecdh);
if(!point) { if(!point) {
logger(LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL)); EC_KEY_free(*ecdh);
abort(); *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); size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
if(!result) { if(!result) {
logger(LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL)); EC_KEY_free(*ecdh);
abort(); *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; 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) { bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh)); EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh));
if(!point) { if(!point) {
logger(LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort(); return false;
} }
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL); int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL);
if(!result) { if(!result) {
logger(LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL)); EC_POINT_free(point);
abort(); 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); 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; *ecdh = NULL;
if(!result) { 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; return false;
} }

View file

@ -1,6 +1,6 @@
/* /*
ecdsa.c -- ECDSA key handling 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -30,15 +30,19 @@
// //
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) { bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1); *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); int len = strlen(p);
unsigned char pubkey[len / 4 * 3 + 3]; unsigned char pubkey[len / 4 * 3 + 3];
const unsigned char *ppubkey = pubkey; const unsigned char *ppubkey = pubkey;
len = b64decode(p, pubkey, len); len = b64decode(p, (char *)pubkey, len);
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) { if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) {
logger(LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL)); logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
abort(); return false;
} }
return true; return true;
@ -49,7 +53,7 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
int len = i2o_ECPublicKey(*ecdsa, &pubkey); int len = i2o_ECPublicKey(*ecdsa, &pubkey);
char *base64 = malloc(len * 4 / 3 + 5); char *base64 = malloc(len * 4 / 3 + 5);
b64encode(pubkey, base64, len); b64encode((char *)pubkey, base64, len);
free(pubkey); free(pubkey);
@ -64,7 +68,7 @@ bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
if(*ecdsa) if(*ecdsa)
return true; 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; return false;
} }
@ -74,7 +78,7 @@ bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
if(*ecdsa) if(*ecdsa)
return true; 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; 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) { bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa); unsigned int siglen = ECDSA_size(*ecdsa);
char hash[SHA512_DIGEST_LENGTH]; unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash); SHA512(in, len, hash);
memset(sig, 0, siglen); memset(sig, 0, siglen);
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) { 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; return false;
} }
if(siglen != ECDSA_size(*ecdsa)) {
logger(LOG_ERR, "Signature length %d != %d", siglen, ECDSA_size(*ecdsa));
}
return true; return true;
} }
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) { bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
unsigned int siglen = ECDSA_size(*ecdsa); unsigned int siglen = ECDSA_size(*ecdsa);
char hash[SHA512_DIGEST_LENGTH]; unsigned char hash[SHA512_DIGEST_LENGTH];
SHA512(in, len, hash); SHA512(in, len, hash);
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) { 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; return false;
} }

View file

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

View file

@ -1,6 +1,6 @@
/* /*
prf.c -- Pseudo-Random Function for key material generation 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,14 +19,16 @@
#include "system.h" #include "system.h"
#include <openssl/obj_mac.h>
#include "digest.h" #include "digest.h"
#include "prf.h" #include "prf.h"
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5. /* 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; digest_t digest;
if(!digest_open_by_nid(&digest, nid, -1)) 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; return true;
} }
bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) { bool prf(const 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, /* This construction allows us to easily switch back to a scheme where the PRF is calculated using two different digest algorithms. */
and XOR the results. */
memset(out, 0, outlen); memset(out, 0, outlen);
return prf_xor(NID_sha512, secret, (secretlen + 1) / 2, seed, seedlen, out, outlen) return prf_xor(NID_sha512, secret, secretlen, seed, seedlen, out, outlen);
&& prf_xor(NID_whirlpool, secret + secretlen / 2, (secretlen + 1) / 2, seed, seedlen, out, outlen);
} }

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