diff --git a/COPYING b/COPYING index c3d1ceb..513da31 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others. +Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others. See the AUTHORS file for a complete list. This program is free software; you can redistribute it and/or modify it under diff --git a/COPYING.README b/COPYING.README index 2eb9c1f..166102b 100644 --- a/COPYING.README +++ b/COPYING.README @@ -1,19 +1,17 @@ The following applies to tinc: -This program is released under the GPL with the additional exemption that -compiling, linking, and/or using OpenSSL is allowed. You may provide binary -packages linked to the OpenSSL libraries, provided that all other requirements -of the GPL are met. +> This program is released under the GPL with the additional exemption that +> compiling, linking, and/or using OpenSSL is allowed. You may provide binary +> packages linked to the OpenSSL libraries, provided that all other requirements +> of the GPL are met. The following applies to the LZO library: - Hereby I grant a special exception to the tinc VPN project - (http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library - (http://www.openssl.org). - - Markus F.X.J. Oberhumer +> Hereby I grant a special exception to the tinc VPN project +> (https://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library +> (https://openssl.org). +> +> Markus F.X.J. Oberhumer When tinc is compiled with the --enable-tunemu option, the resulting binary falls under the GPL version 3 or later. - - diff --git a/ChangeLog b/ChangeLog index b2faf52..40b3bfb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,304 @@ +Version 1.1pre12 April 24 2016 +------------------------------------------------------------------------ + +Guus Sliepen (166): + Allow tinc to be compiled without OpenSSL. + Add missing nolegacy/crypto.c and prf.c. + Fixes for bugs in src/Makefile.am and tincctl.c introduced by cfe9285adf391ab66faeb5def811fe08e47a221a. + Fix indentation and some whitespace issues. + Use void pointers for opaque data blobs in the SHA512 code. + Use global "now" in try_udp() and try_mtu(). + Remember whether we sent our key to another node. + Try to clarify the new code in net_packet.c a bit. + Correctly estimate the initial MTU for legacy packets. + Fix size of type 2 probe replies. + Proactively send our own key when we request another node's key. + Don't send probe replies if we don't have the other's key. + Fix segfault when sptps_test cannot open the key files. + Always keep UDP mappings alive for nodes that also have a meta-connection. + Immediately send our key when a meta-connection is established. + Only send small packets during UDP probes. + Remove RTT and packet loss estimation code. + Send MTU probes only once every PingInterval. + Move detection of PMTU decrease to try_mtu(). + Keep track of the largest UDP packet size received from a node. + Move UDP probe reply code into its own function. + Send the size of the largest recently received packets in type 2 probe replies. + Send gratuitous type 2 probe replies. + Improve packet source detection. + Add the "fsck" command to the CLI. + Always call res_init() before getaddrinfo(). + Make "tinc add" idempotent. + Document that --force should precede commands. + Suppress warnings about parsing Ed25519 keys when they are not present. + Merge remote-tracking branch 'dechamps/sptpsabort' into 1.1 + Merge remote-tracking branch 'seehuhn/1.1' into 1.1 + Fix the case where we detach and use --logfile. + --syslog and --logfile are mutually exclusive. + Merge remote-tracking branch 'dechamps/staticfix' into 1.1 + Merge remote-tracking branch 'dechamps/fsckwin' into 1.1 + Merge remote-tracking branch 'dechamps/winmtu' into 1.1 + Merge remote-tracking branch 'dechamps/windevice' into 1.1 + Always call res_init() before getaddrinfo(). + Merge remote-tracking branch 'dechamps/wintapver' into 1.1 + Allow one-sided upgrades to Ed25519. + Fix a possible segmentation fault during key upgrades. + Don't log an error message when receiving a TERMREQ. + Fix typo 0fda572c88d02b0b200ef81d72cc4da594fa0e38 that prevented some errors from being logged. + Remove "release-" from displayed git version. + Don't include build-time generated version_git.h in the tarball. + Really remove "release-" from the git-derived version string. + Fix invitations. + Fix receiving UDP packets from tinc 1.0.x nodes. + Use AF_UNSPEC instead of AF_UNKNOWN for unspecified local address in add_edge_h(). + Be more liberal accepting ADD_EDGE messages with conflicting local address information. + Try all addresses for the hostname in an invitation URL. + Let sockaddr2str() handle AF_UNSPEC addresses. + Don't send local_address in ADD_EDGE messages if it's AF_UNSPEC. + Merge remote-tracking branches 'dechamps/sptpsrestart' and 'dechamps/keychanged' into 1.1 + Remove info-in-builddir option from AM_INIT_AUTOMAKE(). + Fix src/Makefile.am for *BSD. + Add newline at end of precomp_data.h and sc.h. + Add source of SPTPS errors to log messages. + Don't log seqno failures in sptps_verify_datagram(). + If LOCALSTATEDIR is inaccessible, store the pid and socket files in the configuration directory. + Quit with an error message if ioctl(TUNSETIFF) fails. + Add "list" as an alias for "dump" in the CLI. + Allow dumping a list of outstanding invitations. + Allocate temporary filenames on the stack. + Fix check for LOCALSTATEDIR accessibility for the CLI. + Ensure "tinc start" knows if the daemon really started succesfully. + Don't write log messages to the umbilical pipe if we don't detach. + Use socketpair() instead of pipe() for the umbilical. + Set the CLOEXEC flag on the umbilical socket. + Update copyright notices. + Fix missing return value caused by the previous commit. + Fix autoconf check for function attributes. + Fix warnings about missing return value checks. + Fix receiving SPTPS data in sptps_speed and sptps_test. + Fix alignment of output of sptps_speed. + Fix crash is sptps_logger(). + Don't #include OpenSSL headers when compiling without OpenSSL. + Coalesce two if statements that check for the same thing. + Call sockaddrfree(&e->local_address) in free_edge() instead of exit_edges(). + Fix undefined behaviour when left-shifting signed integers. + Remove unused code that caused warnings about an uninitialized variable. + Use AC_CONFIG_MACRO_DIRS([m4]). + Make subnet caches static. + Fix the PRF function when compiling without OpenSSL. + Use AC_CONFIG_MACRO_DIR() instead of _DIRS(). + In sssp_bfs(), never try to update myself. + Add -I m4 back to ACLOCAL_AMFLAGS. + Optionally install systemd service files. + Replace bare if statements with AS_IF in configure.ac. + Fix struct node_status_t. + Fix a few memory leaks in the CLI found by AddressSanitizer. + Avoid undefined behavior. + Update THANKS file. + Don't leave dead outgoing_t's in the outgoing_list. + list_delete() already free()s the deleted element. + Add support for recvmmsg(). + Use static buffers for recvmmsg(), initialize them only as needed. + Only add a reflexive address when we're sure it's working. + Merge remote-tracking branch 'mweinelt/tinc-gui' into 1.1 + Add the ability to sign and verify files. + Update .gitignore. + Only check for -fno-strict-overflow if -fwrapv does not work. + Use nostdinc instead of overriding DEFAULT_INCLUDES. + Improve performance of edge updates. + Fix forwarding of edge updates. + Clarify that scripts are called synchronously. + Small fixes for the documentation. + Add warnings for bad combinations of Device and Interface. + Fix for botched cherry-pick commit 60fb230. + Fix typo. + Don't compile getopt*.c if the system provides getopt_long(). + Update .gitignore. + Update THANKS. + Use iface instead of interface. + Support ToS/DiffServ for IPv6 meta and UDP connections. + Fix --logfile without a filename on Windows. + Never call putenv() with data on the stack. + Update "now" after connect() when making outgoing connections. + Update support for BSD tun/tap devices, add support for OS X utun interfaces. + Explicitly mention that LibreSSL can be used as well. + Update links in the documentation. + Enable silent builds by default. + Really don't compile getopt*.c if the system provides getopt_long(). + Remove elliptic curve stubs from gcrypt/, add PRF implementation. + Update .gitignore. + Make text files Markdown-compatible. + Remove checks for headers and functions that are in C99. + Fix compiling under MinGW. + Replace usleep() with nanosleep(). + Use getcwd() instead of get_current_dir_name(). + Fix typo in Makefile.am. + Fix version_get.h generation on BSD. + Remove checks for non-C99 compliant compilers. + Remove support for Windows 2000 and anything that doesn't support getaddrinfo(). + Make some platform-specific header checks conditional. + Add version_git.h and sample-config.tar.gz to CLEANFILES. + Don't assume sa.sa_family is a short int. + Remove use of strcpy() and sprintf(). + Don't use HAVE_SYSTEM, the autoconf check was removed. + Fix a non-working cast to get rid of a compiler warning. + Fix generation of version_git.h for some versions of BSD make. + Fix some compiler warnings from MinGW. + Fix conditional checking of tun/tap headers on DragonFly BSD. + Fix crash at startup when Device is not specified on OS X. + Stop using SOL_TCP, SOL_IP and SOL_IPV6. + Document how invitation files work. + Generate a tinc-up script from an invitation. + Move some stray #includes. + Allow gateways to be specified for routes. + Fix gateway parsing in invitation files. + Fix compiler warnings. + Add a test for tinc-up creation from invitations. + Chdir() to the configuration directory instead of /. + Use ifconfig_header(). + Add stricter checks for netnames. + Handle special characters in sptps_test only if the --special option is given. + Don't call terminate_connection(myself->connection). + Speed up AutoConnect at startup. + Fix the "network" command in tinc shell. + Move documentation of invitations to the manual. + Have "tinc fsck" recognize Ed25519PublicKey statements. + Fix possible read of freed memory when verifying the signature of a file. + Fix a compiler warning on Windows. + Fix starting tinc as a service on Windows. + Don't check file permissions on Windows during fsck. + Releasing 1.1pre12. + +Etienne Dechamps (72): + Clarify the send_mtu_probe() function. + Add the try_tx() function. + Move try_sptps() closer to try_tx(). + Add UDP discovery mechanism. + Move responsibility for local discovery to UDP discovery. + Remove PMTU discovery code redundant with UDP discovery. + Move PMTU discovery code into the TX path. + Move try_mtu() closer to try_tx(). + Fix MTU as soon as possible. + Use -1 to identify the post-initial MTU discovery state. + Send one MTU probe at a time. + Remove bandwidth estimation code. + Use a smarter algorithm for choosing MTU discovery probe sizes. + Adjust MTU probe counts. + Don't send MTU probes smaller than 512 bytes. + Add IP_MTU-based maxmtu estimation. + Fine-tune the MTU discovery multiplier for the maxmtu < MTU case. + Recalculate and resend MTU probes if they are too large for the system. + Use a different UDP discovery interval if the tunnel is established. + Fix typo in logging statement. + Fix dynamic UDP SPTPS relaying. + Fix UDP/MTU discovery in intermediate SPTPS UDP relays. + Don't abort() willy-nilly in SPTPS code. + Add UDP_INFO protocol message. + Add MTU_INFO protocol message. + Throttle the rate of UDP_INFO messages. + Throttle the rate of MTU_INFO messages. + Don't send UDP probes past static relays. + Fix invalid getuid() call on Windows. + Fix HAVE_DECL_RES_INIT conditionals. + Make sure packet header structures are correctly packed on Windows. + When disabling the Windows device, wait for pending reads to complete. + Fix Windows device asynchronous write behavior. + Set the default for UDPRcvBuf and UDPSndBuf to 1M. + Increase the ReplayWindow default from 16 to 32. + Log TAP-Windows driver version on startup. + Warn about performance if using TAP-Windows >=9.21. + Use git description as the tinc version. + Use git describe to populate autoconf's VERSION. + Remove explicit distribution rules for m4 scripts. + Add support for out-of-tree ("VPATH") builds. + When relaying, send probes to the destination, not the source. + Use the correct originator node when relaying SPTPS UDP packets. + Expose the raw SPTPS send interface from net_packet. + Try to use UDP to relay SPTPS packets received over TCP. + Rename REQ_SPTPS to SPTPS_PACKET. + Only read one record at a time in sptps_receive_data(). + Introduce raw TCP SPTPS packet transport. + Prevent SPTPS key regeneration packets from entering an UDP relay path. + Trivial: make sptps_receive_data_datagram() a little more readable. + Proactively restart the SPTPS tunnel if we get receive errors. + Don't send KEY_CHANGED messages if we don't support the legacy protocol. + Make sure the MIN() macro is defined. + Don't pollute the system header directory namespace. + Fix SPTPS condition in try_harder(). + Don't parse node IDs if the sending node doesn't support them. + Fix direct UDP communciation with pre-relaying 1.1 nodes. + Fix crashes when trying unreachable nodes. + Don't set up an ongoing connection to myself. + Fix wrong format string type in send_sptps_tcppacket(). + Fix invalid pointer use in get_my_hostname(). + Don't try to relay packets to unreachable nodes. + Protect against callbacks removing items from the io tree. + Use a splay tree for node UDP addresses in order to avoid collisions. + Revert "Cache node IDs in a hash table for faster lookups." + Make sure the packet source MAC address is always set. + Add a new optional dependency on the miniupnpc library. + Add UPnP support to tincd. + Allow tinc to be built with miniupnpc on Windows. + Try to ensure we build correctly against various libminiupnpc versions. + Don't unset validkey when receiving SPTPS handshakes over ANS_KEY. + Add upnp.h to tincd SOURCES. + +thorkill (8): + Fixed 2 leaks in setup_myself() + Cleanup edges stored in edge_weight_tree on exit + Cleanup local_address in protocol_edge.c + Removed double break; + Included missing names.h + Make sure we do not allocate new edge when talking to old nodes and the same edge already exists + Prevent tinc from forgeting e->local_address + Do not access e->to->prevedge if not defined + +Vittorio Gambaletta (VittGam) (6): + Fix DecrementTTL option. + Fix source IP address for ICMP unreachable packets generated by tinc. + Try to reply with node address only when decrementing the TTL. + Fix DecrementTTL option for packets destined to the local node. + s/broadcast_packet_helper/route_broadcast/ + Remove forward declaration for do_decrement_ttl. + +Martin Weinelt (5): + tinc-gui: Reformat codebase according to PEP8 + tinc-gui: Update Node object to correctly parse responses + tinc-gui: Fix GetListCtrl method name in SuperListCtrl + tinc-gui: Use ArgumentParser, default to python2 + tinc-gui: Properly initialize class attributes for VPN in __init__ + +Sven-Haegar Koch (3): + Fixed variables.test testsuite after 'Make "tinc add" idempotent.' change. + Let sockaddr2hostname() handle AF_UNSPEC addresses. + Fix check for public key in invite-join.test. + +Florian Klink (2): + (read|append)_config_file: log open errors as LOG_DEBUG + setup_outgoing_connection: log to LOG_DEBUG on if no known address + +LunarShaddow (2): + fix typo + re-arrange include sequence to avoid a mingw introduced bug. + +Dato Simó (1): + Fix typo in tinc.texi. + +Jo-Philipp Wich (1): + fix musl compatibility + +Jochen Voss (1): + Add a new --syslog option for tincd. + +Nathan Stratton Treadway (1): + Fix invalid checksum generation. + +Pierre Emeriaud (1): + Fix typo in tincctl help. + +xentec (1): + Fix compile errors introduced in cfe9285adf391ab66faeb5def811fe08e47a221a + Version 1.1pre11 December 27 2014 ------------------------------------------------------------------------ diff --git a/Makefile.am b/Makefile.am index 0a4faef..177f549 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,14 +2,22 @@ AUTOMAKE_OPTIONS = gnu -SUBDIRS = m4 src doc gui test +SUBDIRS = src doc gui test systemd -ACLOCAL_AMFLAGS = -I m4 +ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = COPYING.README README.android +# If git describe works, force autoconf to run in order to make sure we have the +# current version number from git in the resulting configure script. +configure-version: + -cd $(srcdir) && git describe && autoconf --force + +# Triggering the README target means we are building a distribution (make dist). +README: configure-version + ChangeLog: - git log > ChangeLog + (cd $(srcdir) && git log) > ChangeLog deb: dpkg-buildpackage -rfakeroot @@ -23,5 +31,5 @@ release: rm -f ChangeLog $(MAKE) ChangeLog echo "Please edit the NEWS file now..." - /usr/bin/editor NEWS + /usr/bin/editor $(srcdir)/NEWS $(MAKE) dist diff --git a/Makefile.in b/Makefile.in index 797d7bf..f5f609a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -78,21 +88,18 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . -DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ - $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/configure $(am__configure_deps) \ - $(srcdir)/config.h.in COPYING THANKS compile config.guess \ - config.sub depcomp install-sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d @@ -156,6 +163,9 @@ ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \ + COPYING ChangeLog INSTALL NEWS README THANKS compile \ + config.guess config.sub depcomp install-sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -231,6 +241,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -288,17 +299,19 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = gnu -SUBDIRS = m4 src doc gui test -ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = src doc gui test systemd +ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = COPYING.README README.android all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -319,7 +332,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -461,12 +473,6 @@ distclean-tags: -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) - @case `sed 15q $(srcdir)/NEWS` in \ - *"$(VERSION)"*) : ;; \ - *) \ - echo "NEWS not updated; not releasing" 1>&2; \ - exit 1;; \ - esac $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ @@ -547,15 +553,15 @@ dist-xz: distdir $(am__post_remove_distdir) dist-tarZ: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) @@ -591,17 +597,17 @@ distcheck: dist esac chmod -R a-w $(distdir) chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_inst + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build \ - && ../configure \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=.. --prefix="$$dc_install_base" \ + --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ @@ -776,9 +782,19 @@ uninstall-am: mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am +.PRECIOUS: Makefile + + +# If git describe works, force autoconf to run in order to make sure we have the +# current version number from git in the resulting configure script. +configure-version: + -cd $(srcdir) && git describe && autoconf --force + +# Triggering the README target means we are building a distribution (make dist). +README: configure-version ChangeLog: - git log > ChangeLog + (cd $(srcdir) && git log) > ChangeLog deb: dpkg-buildpackage -rfakeroot @@ -792,7 +808,7 @@ release: rm -f ChangeLog $(MAKE) ChangeLog echo "Please edit the NEWS file now..." - /usr/bin/editor NEWS + /usr/bin/editor $(srcdir)/NEWS $(MAKE) dist # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/NEWS b/NEWS index abd6a6f..bedca1c 100644 --- a/NEWS +++ b/NEWS @@ -1,830 +1,667 @@ -Version 1.1pre11 December 27 2014 +# Version 1.1pre12 April 24 2016 - * Added a "network" command to list or switch networks. +* Added a "--syslog" option to force logging to syslog even if running in the + foreground. +* Fixes and improvements to the DecrementTTL function. +* Improved PMTU discovery and UDP keepalive probes. +* More efficient relaying of UDP packets through intermediate nodes. +* Improved compatibility with newer TAP-Win32 drivers. +* Added support for UPnP. +* Allow tinc to be compiled without LibreSSL or OpenSSL (this drops + compatibility with nodes running 1.0.x). +* Added a "fsck" command to check the configuration files for problems. +* Tinc "start" now checks whether the daemon really started succesfully, and + displays error messages otherwise. +* Added systemd service files. +* Use the recvmmsg() function if available. +* Support ToS/Diffserv on IPv6 connections. +* Updated support for BSD tun/tap devices. +* Added support for OS X utun interfaces. +* Dropped support for Windows 2000. +* Initial support for generating a tinc-up script from an invitation. +* Many small fixes, documentation updates. - * Switched to Ed25519 keys and the ChaCha-Poly1305 cipher for the new protocol. +Thanks to Etienne Dechamps, thorkill, Vittorio Gambaletta, Martin Weinelt, +Sven-Haegar Koch, Florian Klink, LunnarShadow, Dato Simó, Jo-Philipp Wich, +Jochen Voss, Nathan Stratton Treadway, Pierre Emeriaud, xentec, Samuel +Thibault and Michael Tokarev for their contributions to this version of tinc. - * AutoConnect is now a boolean option, when enabled tinc always tries to keep - at least three meta-connections open. +# Version 1.1pre11 December 27 2014 - * The new protocol now uses UDP much more often. - - * Tinc "del" and "get" commands now return a non-zero exit code when they - don't find the requested variable. - - * Updated documentation. - - * Added a "DeviceStandby" option to defer running tinc-up until a working - connection is made, and which on Windows will also change the network - interface link status accordingly. - - * Tinc now tells the resolver to reload /etc/resolv.conf when it receives - SIGALRM. - - * Improved error messages and event loop handling on Windows. - - * LocalDiscovery now uses local address learned from other nodes, and is - enabled by default. - - * Added a "BroadcastSubnet" option to change the behavior of broadcast packets - in router mode. - - * Added support for dotted quad notation in IPv6 (e.g. ::1.2.3.4). - - * Improved format of printed Subnets, MAC and IPv6 addresses. - - * Added a "--batch" option to force the tinc CLI to run in non-interactive - mode. - - * Improve default Device selection on *BSD and Mac OS X. - - * Allow running tinc without RSA keys. +* Added a "network" command to list or switch networks. +* Switched to Ed25519 keys and the ChaCha-Poly1305 cipher for the new protocol. +* AutoConnect is now a boolean option, when enabled tinc always tries to keep + at least three meta-connections open. +* The new protocol now uses UDP much more often. +* Tinc "del" and "get" commands now return a non-zero exit code when they + don't find the requested variable. +* Updated documentation. +* Added a "DeviceStandby" option to defer running tinc-up until a working + connection is made, and which on Windows will also change the network + interface link status accordingly. +* Tinc now tells the resolver to reload /etc/resolv.conf when it receives + SIGALRM. +* Improved error messages and event loop handling on Windows. +* LocalDiscovery now uses local address learned from other nodes, and is + enabled by default. +* Added a "BroadcastSubnet" option to change the behavior of broadcast packets + in router mode. +* Added support for dotted quad notation in IPv6 (e.g. ::1.2.3.4). +* Improved format of printed Subnets, MAC and IPv6 addresses. +* Added a "--batch" option to force the tinc CLI to run in non-interactive + mode. +* Improve default Device selection on *BSD and Mac OS X. +* Allow running tinc without RSA keys. Thanks to Etienne Dechamps, Sven-Haegar Koch, William A. Kennington III, Baptiste Jonglez, Alexis Hildebrandt, Armin Fisslthaler, Franz Pletz, Alexander Ried and Saverio Proto for their contributions to this version of tinc. -Version 1.1pre10 February 7 2014 +# Version 1.1pre10 February 7 2014 - * Added a benchmark tool (sptps_speed) for the new protocol. - - * Fixed a crash when using Name = $HOST while $HOST is not set. - - * Use AES-256-GCM for the new protocol. - - * Updated support for Solaris. - - * Allow running tincd without a private ECDSA key present when - ExperimentalProtocol is not explicitly set. - - * Enable various compiler hardening flags by default. - - * Added support for a "conf.d" configuration directory. - - * Fix tinc-gui on Windows, also allowing it to connect to a 32-bits tincd when - tinc-gui is run in a 64-bits Python environment. - - * Added a "ListenAddress" option, which like BindToAddress adds more listening - address/ports, but doesn't bind to them for outgoing sockets. - - * Make invitations work better when the "invite" and "join" commands are not - run interactively. - - * When creating meta-connections to a node for which no Address statement is - specified, try to use addresses learned from other nodes. +* Added a benchmark tool (sptps_speed) for the new protocol. +* Fixed a crash when using Name = $HOST while $HOST is not set. +* Use AES-256-GCM for the new protocol. +* Updated support for Solaris. +* Allow running tincd without a private ECDSA key present when + ExperimentalProtocol is not explicitly set. +* Enable various compiler hardening flags by default. +* Added support for a "conf.d" configuration directory. +* Fix tinc-gui on Windows, also allowing it to connect to a 32-bits tincd when + tinc-gui is run in a 64-bits Python environment. +* Added a "ListenAddress" option, which like BindToAddress adds more listening + address/ports, but doesn't bind to them for outgoing sockets. +* Make invitations work better when the "invite" and "join" commands are not + run interactively. +* When creating meta-connections to a node for which no Address statement is + specified, try to use addresses learned from other nodes. Thanks to Dennis Joachimsthaler and Florent Clairambault for their contribution to this version of tinc. -Version 1.1pre9 September 8 2013 +# Version 1.1pre9 September 8 2013 - * The UNIX socket is now created before tinc-up is called. - - * Windows users can now use any extension that is in %PATHEXT% for scripts, - not only .bat. - - * Outgoing sockets are bound to the address of the listening sockets again, - when there is no ambiguity. - - * Added invitation-created and invitation-accepted scripts. - - * Invited nodes now learn of the Mode and Broadcast settings of the VPN. - - * Joining a VPN with an invitation now also works on Windows. - - * The port number tincd is listening on is now always included in the - invitation URL. - - * A running tincd is now correctly informed when a new invitation has been - generated. - - * Several bug fixes for the new protocol. - - * Added a test suite. +* The UNIX socket is now created before tinc-up is called. +* Windows users can now use any extension that is in %PATHEXT% for scripts, + not only .bat. +* Outgoing sockets are bound to the address of the listening sockets again, + when there is no ambiguity. +* Added invitation-created and invitation-accepted scripts. +* Invited nodes now learn of the Mode and Broadcast settings of the VPN. +* Joining a VPN with an invitation now also works on Windows. +* The port number tincd is listening on is now always included in the + invitation URL. +* A running tincd is now correctly informed when a new invitation has been + generated. +* Several bug fixes for the new protocol. +* Added a test suite. Thanks to Etienne Dechamps for his contribution to this version of tinc. -Version 1.1pre8 August 13 2013 +# Version 1.1pre8 August 13 2013 - * ExperimentalProtocol is now enabled by default. - - * Added an invitation protocol that makes it easy to invite new nodes. - - * Added the LocalDiscoveryAddress option to change the broadcast address used - to find local nodes. - - * Limit the rate of incoming meta-connections. - - * Many small bug fixes and code cleanups. +* ExperimentalProtocol is now enabled by default. +* Added an invitation protocol that makes it easy to invite new nodes. +* Added the LocalDiscoveryAddress option to change the broadcast address used + to find local nodes. +* Limit the rate of incoming meta-connections. +* Many small bug fixes and code cleanups. Thanks to Etienne Dechamps and Sven-Haegar Koch for their contributions to this version of tinc. -Version 1.1pre7 April 22 2013 +# Version 1.1pre7 April 22 2013 - * Fixed large latencies on Windows. - - * Renamed the tincctl tool to tinc. - - * Simplified changing the configuration using the tinc tool. - - * Added a full description of the ExperimentalProtocol to the manual. - - * Drop packets forwarded via TCP if they are too big (CVE-2013-1428). +* Fixed large latencies on Windows. +* Renamed the tincctl tool to tinc. +* Simplified changing the configuration using the tinc tool. +* Added a full description of the ExperimentalProtocol to the manual. +* Drop packets forwarded via TCP if they are too big (CVE-2013-1428). Thanks to Martin Schobert for auditing tinc and reporting the vulnerability. -Version 1.1pre6 February 20 2013 +# Version 1.1pre6 February 20 2013 - * Fixed tincd exitting immediately on Windows. +* Fixed tincd exitting immediately on Windows. +* Detect PMTU increases. +* Fixed crashes when using a SOCKS5 proxy. +* Fixed control connection when using a proxy. - * Detect PMTU increases. +# Version 1.1pre5 January 20 2013 - * Fixed crashes when using a SOCKS5 proxy. +* Fixed long delays and possible hangs on Windows. +* Fixed support for the tunemu device on iOS, the UML and VDE devices. +* Small improvements to the documentation and error messages. +* Fixed broadcast packets not reaching the whole VPN. +* Tincctl now connects via a UNIX socket to the tincd on platforms that + support this. +* The PriorityInheritance option now also works in switch mode. - * Fixed control connection when using a proxy. +# Version 1.1pre4 December 5 2012 -Version 1.1pre5 January 20 2013 +* Added the "AutoConnect" option which will let tinc automatically select + which nodes to connect to. +* Improved performance of VLAN-tagged IP traffic inside the VPN. +* Ensured LocalDiscovery works with multiple BindToAddress statements and/or + IPv6-only LANs. +* Dropped dependency on libevent. +* Fixed Windows version not reading packets from the TAP adapter. - * Fixed long delays and possible hangs on Windows. +# Version 1.1pre3 October 14 2012 - * Fixed support for the tunemu device on iOS, the UML and VDE devices. +* 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. - * Small improvements to the documentation and error messages. +# Version 1.1pre2 July 17 2011 - * Fixed broadcast packets not reaching the whole VPN. +* .cookie files are renamed to .pid files, which are compatible with 1.0.x. +* Experimental protocol enhancements that can be enabled with the option + ExperimentalProtocol = yes: - * Tincctl now connects via a UNIX socket to the tincd on platforms that - support this. + * Ephemeral ECDH key exchange will be used for both the meta protocol and + UDP session keys. + * Key exchanges are signed with ECDSA. + * ECDSA public keys are automatically exchanged after RSA authentication if + nodes do not know each other's ECDSA public key yet. - * The PriorityInheritance option now also works in switch mode. +# Version 1.1pre1 June 25 2011 -Version 1.1pre4 December 5 2012 +* Control interface allows control of a running tinc daemon. Used by: + * tincctl, a commandline utility + * tinc-gui, a preliminary GUI implemented in Python/wxWidgets +* Code cleanups and reorganization. +* Repleacable cryptography backend, currently supports OpenSSL and libgcrypt. +* Use libevent to handle I/O events and timeouts. +* Use splay trees instead of AVL trees to manage internal datastructures. - * Added the "AutoConnect" option which will let tinc automatically select - which nodes to connect to. +Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this +version of tinc. - * Improved performance of VLAN-tagged IP traffic inside the VPN. +# Version 1.0.22 August 13 2013 - * Ensured LocalDiscovery works with multiple BindToAddress statements and/or - IPv6-only LANs. - - * Dropped dependency on libevent. - - * Fixed Windows version not reading packets from the TAP adapter. - -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. - - * Experimental protocol enhancements that can be enabled with the option - ExperimentalProtocol = yes: - - * Ephemeral ECDH key exchange will be used for both the meta protocol and - UDP session keys. - * Key exchanges are signed with ECDSA. - * ECDSA public keys are automatically exchanged after RSA authentication if - nodes do not know each other's ECDSA public key yet. - -Version 1.1pre1 June 25 2011 - - * Control interface allows control of a running tinc daemon. Used by: - * tincctl, a commandline utility - * tinc-gui, a preliminary GUI implemented in Python/wxWidgets - - * Code cleanups and reorganization. - - * Repleacable cryptography backend, currently supports OpenSSL and libgcrypt. - - * Use libevent to handle I/O events and timeouts. - - * Use splay trees instead of AVL trees to manage internal datastructures. - - Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this - version of tinc. - -Version 1.0.22 August 13 2013 - - * Fixed the combination of Mode = router and DeviceType = tap. - - * The $NAME variable is now set in subnet-up/down scripts. - - * Tinc now gives an error when unknown options are given on the command line. - - * Tinc now correctly handles a space between a short command line option and - an optional argument. +* Fixed the combination of Mode = router and DeviceType = tap. +* The $NAME variable is now set in subnet-up/down scripts. +* Tinc now gives an error when unknown options are given on the command line. +* Tinc now correctly handles a space between a short command line option and + an optional argument. Thanks to Etienne Dechamps for his contribution to this version of tinc. -Version 1.0.21 April 22 2013 +# Version 1.0.21 April 22 2013 - * Drop packets forwarded via TCP if they are too big (CVE-2013-1428). +* Drop packets forwarded via TCP if they are too big (CVE-2013-1428). Thanks to Martin Schobert for auditing tinc and reporting this vulnerability. -Version 1.0.20 March 03 2013 +# Version 1.0.20 March 03 2013 - * Use /dev/tap0 by default on FreeBSD and NetBSD when using switch mode. - - * Minor improvements and clarifications in the documentation. - - * Allow tinc to be cross-compiled with Android's NDK. - - * The discovered PMTU is now also applied to VLAN tagged traffic. - - * The LocalDiscovery option now makes use of all addresses tinc is bound to. - - * Fixed support for tunemu on iOS devices. - - * The PriorityInheritance option now also works with switch mode. - - * Fixed tinc crashing when using a SOCKS5 proxy. +* Use /dev/tap0 by default on FreeBSD and NetBSD when using switch mode. +* Minor improvements and clarifications in the documentation. +* Allow tinc to be cross-compiled with Android's NDK. +* The discovered PMTU is now also applied to VLAN tagged traffic. +* The LocalDiscovery option now makes use of all addresses tinc is bound to. +* Fixed support for tunemu on iOS devices. +* The PriorityInheritance option now also works with switch mode. +* Fixed tinc crashing when using a SOCKS5 proxy. Thanks to Mesar Hameed, Vilbrekin and Martin Schürrer for their contributions to this version of tinc. -Version 1.0.19 June 25 2012 +# Version 1.0.19 June 25 2012 + +* Allow :: notation in IPv6 Subnets. +* Add support for systemd style socket activation. +* Allow environment variables to be used for the Name option. +* Add basic support for SOCKS proxies, HTTP proxies, and proxying through an + external command. + +# Version 1.0.18 March 25 2012 + +* Fixed IPv6 in switch mode by turning off DecrementTTL by default. +* Allow a port number to be specified in BindToAddress, which also allows tinc + to listen on multiple ports. +* Add support for multicast communication with UML/QEMU/KVM. + +# Version 1.0.17 March 10 2012 + +* The DeviceType option can now be used to select dummy, raw socket, UML and + VDE devices without needing to recompile tinc. +* Allow multiple BindToAddress statements. +* Decrement TTL value of IPv4 and IPv6 packets. +* Add LocalDiscovery option allowing tinc to detect peers that are behind the + same NAT. +* Accept Subnets passed with the -o option when StrictSubnets = yes. +* Disabling old RSA keys when generating new ones now also works properly on + Windows. + +# Version 1.0.16 July 23 2011 + +* Fixed a performance issue with TCP communication under Windows. +* Fixed code that, during network outages, would cause tinc to exit when it + thought two nodes with identical Names were on the VPN. + +# Version 1.0.15 June 24 2011 + +* Improved logging to file. +* Reduced amount of process wakeups on platforms which support pselect(). +* Fixed ProcessPriority option under Windows. + + Thanks to Loïc Grenié for his contribution to this version of tinc. + +# Version 1.0.14 May 8 2011 + +* Fixed reading configuration files that do not end with a newline. Again. +* Allow arbitrary configuration options being specified on the command line. +* Allow all options in both tinc.conf and the local host config file. +* Configurable replay window, UDP send and receive buffers for performance tuning. +* Try harder to get UDP communication back after falling back to TCP. +* Initial support for attaching tinc to a VDE switch. +* DragonFly BSD support. +* Allow linking with OpenSSL 1.0.0. + +Thanks to Brandon Black, Julien Muchembled, Michael Tokarev, Rumko and Timothy +Redaelli for their contributions to this version of tinc. + +# Version 1.0.13 Apr 11 2010 + +* Allow building tinc without LZO and/or Zlib. +* Clamp MSS of TCP packets in both directions. +* Experimental StrictSubnets, Forwarding and DirectOnly options, + giving more control over information and packets received from/sent to other + nodes. +* Ensure tinc never sends symbolic names for ports over the wire. + +# Version 1.0.12 Feb 3 2010 + +* Really allow fast roaming of hosts to other nodes in a switched VPN. +* Fixes missing or incorrect environment variables when calling host-up/down + and subnet-up/down scripts in some cases. +* Allow port to be specified in Address statements. +* Clamp MSS of TCP packets to the discovered path MTU. +* Let two nodes behind NAT learn each others current UDP address and port via + a third node, potentially allowing direct communications in a similar way to + STUN. + +# Version 1.0.11 Nov 1 2009 + +* Fixed potential crash when the HUP signal is sent. +* Fixes handling of weighted Subnets in switch and hub modes, preventing + unnecessary broadcasts. +* Works around a MinGW bug that caused packets to Windows nodes to always be + sent via TCP. +* Improvements to the PMTU discovery code, especially on Windows. +* Use UDP again in certain cases where 1.0.10 was too conservative and fell + back to TCP unnecessarily. +* Allow fast roaming of hosts to other nodes in a switched VPN. + +# Version 1.0.10 Oct 18 2009 + +* Fixed potential crashes during shutdown and (in rare conditions) when other + nodes disconnected from the VPN. +* Improved NAT handling: tinc now copes with mangled port numbers, and will + automatically fall back to TCP if direct UDP connection between nodes is not + possible. The TCPOnly option should not have to be used anymore. +* Allow configuration files with CRLF line endings to be read on UNIX. +* Disable old RSA keys when generating new ones, and raise the default size of + new RSA keys to 2048 bits. +* Many fixes in the path MTU discovery code, especially when Compression is + being used. +* Tinc can now drop privileges and/or chroot itself. +* The TunnelServer code now just ignores information from clients instead of + disconnecting them. +* Improved performance on Windows by using the new ProcessPriority option and + by making the handling of packets received from the TAP-Win32 adapter more + efficient. +* Code cleanups: tinc now follows the C99 standard, copyright headers have + been updated to include patch authors, checkpoint tracing and localisation + features have been removed. +* Support for (jailbroken) iPhone and iPod Touch has been added. + +Thanks to Florian Forster, Grzegorz Dymarek and especially Michael Tokarev for +their contributions to this version of tinc. + +# Version 1.0.9 Dec 26 2008 + +* Fixed tinc as a service under Windows 2003. +* Fixed reading configuration files that do not end with a newline. +* Fixed crashes in situations where hostnames could not be resolved or hosts + would disconnect at the same time as session keys were exchanged. +* Improved default settings of tun and tap devices on BSD platforms. +* Make IPv6 sockets bind only to IPv6 on Linux. +* Enable path MTU discovery by default. +* Fixed a memory leak that occured when connections were closed. + +Thanks to Max Rijevski for his contributions to this version of tinc. + +# Version 1.0.8 May 16 2007 + +* Fixed some memory and resource leaks. +* Made network sockets non-blocking under Windows. + +Thanks to Scott Lamb and "dnk" for their contributions to this version of tinc. + +# Version 1.0.7 Jan 5 2007 + +* Fixed a bug that caused slow network speeds on Windows. +* Fixed a bug that caused tinc unable to write packets to the tun device on + OpenBSD. + +# Version 1.0.6 Dec 18 2006 + +* More flexible detection of the LZO libraries when compiling. +* Fixed a bug where broadcasts in switch and hub modes sometimes would not + work anymore when part of the VPN had become disconnected from the rest. + +# Version 1.0.5 Nov 14 2006 + +* Lots of small fixes. +* Broadcast packets no longer grow in size with each hop. This should + fix switch mode (again). +* Generic host-up and host-down scripts. +* Optionally dump graph in graphviz format to a file or a script. +* Support LZO 2.0 and later. + +Thanks to Scott Lamb for his contributions to this version of tinc. + +# Version 1.0.4 May 4 2005 + +* Fix switch and hub modes. +* Optionally start scripts when a Subnet becomes (un)reachable. + +# Version 1.0.3 Nov 11 2004 + +* Show error message when failing to write a PID file. +* Ignore spaces at end of lines in config files. +* Fix handling of late packets. +* Unify BSD tun/tap device handling. This allows IPv6 on tun devices and + anything on tap devices as long as the underlying OS supports it. +* Handle IPv6 on Solaris tun devices. +* Allow tinc to work properly under Windows XP SP2. +* Allow VLAN tagged Ethernet frames in switch and hub mode. +* Experimental PMTUDiscovery, TunnelServer and BlockingTCP options. + +# Version 1.0.2 Nov 8 2003 + +* Fix address and hostname resolving under Windows. +* Remove warnings about non-existing scripts and unsupported address families. +* Use the event logger under Windows. +* Fix quoting of filenames and command line arguments under Windows. +* Strict checks for length incoming network packets and return values of + cryptographic functions, +* Fix a bug in metadata handling that made the tinc daemon abort. + +# Version 1.0.1 Aug 14 2003 + +* Allow empty lines in config files. +* Fix handling of spaces and backslashes in filenames under native Windows. +* Allow scripts to be executed under native Windows. +* Update documentation, make it less Linux specific. + +# Version 1.0 Aug 4 2003 + +* Lots of small bugfixes and code cleanups. +* Throughput doubled and latency reduced. +* Added support for LZO compression. +* No need to set MAC address or disable ARP anymore. +* Added support for Windows 2000 and XP, both natively and in a Cygwin + environment. + +# Version 1.0pre8 Sep 16 2002 + +* More fixes for subnets with prefixlength undivisible by 8. +* Added support for NetBSD and MacOS/X. +* Switched from undirected graphs to directed graphs to avoid certain race + conditions and improve scalability. +* Generalized broadcasting and forwarding of protocol messages. +* Cleanup of source code. + +# Version 1.0pre7 Apr 7 2002 + +* Don't do blocking read()s when getting a signal. +* Remove RSA key checking code, since it sometimes thinks perfectly good RSA + keys are bad. +* Fix handling of subnets when prefixlength isn't divisible by 8. + +# Version 1.0pre6 Mar 27 2002 + +* Improvement of redundant links: + * Non-blocking connects. + * Protocol broadcast messages can no longer go into an infinite loop. + * Graph algorithm updated to look harder for direct connections. +* Good support for routing IPv6 packets over the VPN. Works on Linux, + FreeBSD, possibly OpenBSD but not on Solaris. +* Support for tunnels over IPv6 networks. Works on all supported + operating systems. +* Optional compression of UDP connections using zlib. +* Optionally let UDP connections inherit TOS field of tunneled packets. +* Optionally start scripts when certain hosts become (un)reachable. + +# Version 1.0pre5 Feb 9 2002 + +* Security enhancements: + * Added sequence number and optional message authentication code to + the packets. + * Configurable encryption cipher and digest algorithms. +* More robust handling of dis- and reconnects. +* Added a "switch" and a "hub" mode to allow bridging setups. +* Preliminary support for routing of IPv6 packets. +* Supports Linux, FreeBSD, OpenBSD and Solaris. + +# Version 1.0pre4 Jan 17 2001 + +* Updated documentation; the documentation now reflects the + configuration as it is. +* Some internal changes to make tinc scale better for large + networks, such as using AVL trees instead of linked lists for the + connection list. +* RSA keys can be stored in separate files if needed. See the + documentation for more information. +* Tinc has now been reported to run on Linux PowerPC and FreeBSD x86. + +# Version 1.0pre3 Oct 31 2000 + +* The protocol has been redesigned, and although some details are + still under discussion, this is secure. Care has been taken to + resist most, if not all, attacks. +* Unfortunately this protocol is not compatible with earlier versions, + nor are earlier versions compatible with this version. Because the + older protocol has huge security flaws, we feel that not + implementing backwards compatibility is justified. +* Some data about the protocol: + * It uses public/private RSA keys for authentication (this is the + actual fix for the security hole). + * All cryptographic functions have been taken out of tinc, instead + it uses the OpenSSL library functions. + * Offers support for multiple subnets per tinc daemon. +* New is also the support for the universal tun/tap device. This + means better portability to FreeBSD and Solaris. +* Tinc is tested to compile on Solaris, Linux x86, Linux alpha. +* Tinc now uses the OpenSSL library for cryptographic operations. + More information on getting and installing OpenSSL is in the manual. + This also means that the GMP library is no longer required. +* Further, thanks to Enrique Zanardi, we have Spanish messages; Matias + Carrasco provided us with a Spanish translation of the manual. + +# Version 1.0pre2 May 31 2000 + +* This version has been internationalized; and a Dutch translation has + been included. +* Two configuration variables have been added: + * VpnMask - the IP network mask for the entire VPN, not just our + subnet (as given by MyVirtualIP). The Redhat and Debian packages + use this variable in their system startup scripts, but it is + ignored by tinc. + * Hostnames - if set to `yes', look up the names of IP addresses + trying to connect to us. Default set to `no', to prevent lockups + during lookups. +* The system startup scripts for Debian and Redhat use + /etc/tinc/nets.boot to find out which networks need to be started + during system boot. +* Fixes to prevent denial of service attacks by sending random data + after connecting (and even when the connection has been established), + either random garbage or just nonsensical protocol fields. +* Tinc will retry to connect upon startup, does not quit if it doesn't + work the first time. +* Hosts that are disconnected implicitly if we lose a connection get + deleted from the internal list, to prevent hogging eachother with + add and delete requests when the connection is restored. + +# Version 1.0pre1 May 12 2000 + +* New meta-protocol +* Various other bugfixes +* Documentation updates + +# Version 0.3.3 Feb 9 2000 + +* Fixed bug that made tinc stop working with latest kernels +* Updated the manual + +# Version 0.3.2 Nov 12 1999 + +* No more `Invalid filedescriptor' when working with multiple + connections. +* Forward unknown packets to uplink. + +# Version 0.3.1 Oct 20 1999 + +* Fixed a bug where tinc would exit without a trace. + +# Version 0.3 Aug 20 1999 + +* Pings now work immediately. +* All packet sizes get transmitted correctly. + +# Version 0.2.26 Aug 15 1999 + +* Fixed some remaining bugs. +* --sysconfdir works with configure. +* Last version before 0.3. + +# Version 0.2.25 Aug 8 1999 + +* Improved stability, going towards 0.3 now. + +# Version 0.2.24 Aug 7 1999 - * Allow :: notation in IPv6 Subnets. +* Added key aging, there's a new config variable, KeyExpire. +* Updated man and info pages. - * Add support for systemd style socket activation. +# Version 0.2.23 Aug 5 1999 - * Allow environment variables to be used for the Name option. +* All known bugs fixed, this is a candidate for 0.3. + +# Version 0.2.22 Apr 11 1999 - * Add basic support for SOCKS proxies, HTTP proxies, and proxying through an - external command. +* Multiconnection thing is now working nearly perfect :) -Version 1.0.18 March 25 2012 +# Version 0.2.21 Apr 10 1999 - * Fixed IPv6 in switch mode by turning off DecrementTTL by default. - - * Allow a port number to be specified in BindToAddress, which also allows tinc - to listen on multiple ports. - - * Add support for multicast communication with UML/QEMU/KVM. - -Version 1.0.17 March 10 2012 - - * The DeviceType option can now be used to select dummy, raw socket, UML and - VDE devices without needing to recompile tinc. - - * Allow multiple BindToAddress statements. - - * Decrement TTL value of IPv4 and IPv6 packets. - - * Add LocalDiscovery option allowing tinc to detect peers that are behind the - same NAT. - - * Accept Subnets passed with the -o option when StrictSubnets = yes. - - * Disabling old RSA keys when generating new ones now also works properly on - Windows. - -Version 1.0.16 July 23 2011 - - * Fixed a performance issue with TCP communication under Windows. - - * Fixed code that, during network outages, would cause tinc to exit when it - thought two nodes with identical Names were on the VPN. - -Version 1.0.15 June 24 2011 - - * Improved logging to file. - - * Reduced amount of process wakeups on platforms which support pselect(). - - * Fixed ProcessPriority option under Windows. - - Thanks to Loïc Grenié for his contribution to this version of tinc. - -Version 1.0.14 May 8 2011 - - * Fixed reading configuration files that do not end with a newline. Again. - - * Allow arbitrary configuration options being specified on the command line. - - * Allow all options in both tinc.conf and the local host config file. - - * Configurable replay window, UDP send and receive buffers for performance tuning. - - * Try harder to get UDP communication back after falling back to TCP. - - * Initial support for attaching tinc to a VDE switch. - - * DragonFly BSD support. - - * Allow linking with OpenSSL 1.0.0. - - Thanks to Brandon Black, Julien Muchembled, Michael Tokarev, Rumko and Timothy - Redaelli for their contributions to this version of tinc. - -Version 1.0.13 Apr 11 2010 - - * Allow building tinc without LZO and/or Zlib. - - * Clamp MSS of TCP packets in both directions. - - * Experimental StrictSubnets, Forwarding and DirectOnly options, - giving more control over information and packets received from/sent to other - nodes. - - * Ensure tinc never sends symbolic names for ports over the wire. - -Version 1.0.12 Feb 3 2010 - - * Really allow fast roaming of hosts to other nodes in a switched VPN. - - * Fixes missing or incorrect environment variables when calling host-up/down - and subnet-up/down scripts in some cases. - - * Allow port to be specified in Address statements. - - * Clamp MSS of TCP packets to the discovered path MTU. - - * Let two nodes behind NAT learn each others current UDP address and port via - a third node, potentially allowing direct communications in a similar way to - STUN. - -Version 1.0.11 Nov 1 2009 - - * Fixed potential crash when the HUP signal is sent. - - * Fixes handling of weighted Subnets in switch and hub modes, preventing - unnecessary broadcasts. - - * Works around a MinGW bug that caused packets to Windows nodes to always be - sent via TCP. - - * Improvements to the PMTU discovery code, especially on Windows. - - * Use UDP again in certain cases where 1.0.10 was too conservative and fell - back to TCP unnecessarily. - - * Allow fast roaming of hosts to other nodes in a switched VPN. - -Version 1.0.10 Oct 18 2009 - - * Fixed potential crashes during shutdown and (in rare conditions) when other - nodes disconnected from the VPN. - - * Improved NAT handling: tinc now copes with mangled port numbers, and will - automatically fall back to TCP if direct UDP connection between nodes is not - possible. The TCPOnly option should not have to be used anymore. - - * Allow configuration files with CRLF line endings to be read on UNIX. - - * Disable old RSA keys when generating new ones, and raise the default size of - new RSA keys to 2048 bits. - - * Many fixes in the path MTU discovery code, especially when Compression is - being used. - - * Tinc can now drop privileges and/or chroot itself. - - * The TunnelServer code now just ignores information from clients instead of - disconnecting them. - - * Improved performance on Windows by using the new ProcessPriority option and - by making the handling of packets received from the TAP-Win32 adapter more - efficient. - - * Code cleanups: tinc now follows the C99 standard, copyright headers have - been updated to include patch authors, checkpoint tracing and localisation - features have been removed. - - * Support for (jailbroken) iPhone and iPod Touch has been added. - - Thanks to Florian Forster, Grzegorz Dymarek and especially Michael Tokarev for - their contributions to this version of tinc. - -Version 1.0.9 Dec 26 2008 - - * Fixed tinc as a service under Windows 2003. - - * Fixed reading configuration files that do not end with a newline. - - * Fixed crashes in situations where hostnames could not be resolved or hosts - would disconnect at the same time as session keys were exchanged. - - * Improved default settings of tun and tap devices on BSD platforms. - - * Make IPv6 sockets bind only to IPv6 on Linux. - - * Enable path MTU discovery by default. - - * Fixed a memory leak that occured when connections were closed. - - Thanks to Max Rijevski for his contributions to this version of tinc. - -Version 1.0.8 May 16 2007 - - * Fixed some memory and resource leaks. - - * Made network sockets non-blocking under Windows. - - Thanks to Scott Lamb and "dnk" for their contributions to this version of tinc. - -Version 1.0.7 Jan 5 2007 - - * Fixed a bug that caused slow network speeds on Windows. - - * Fixed a bug that caused tinc unable to write packets to the tun device on - OpenBSD. - -Version 1.0.6 Dec 18 2006 - - * More flexible detection of the LZO libraries when compiling. - - * Fixed a bug where broadcasts in switch and hub modes sometimes would not - work anymore when part of the VPN had become disconnected from the rest. - -Version 1.0.5 Nov 14 2006 - - * Lots of small fixes. - - * Broadcast packets no longer grow in size with each hop. This should - fix switch mode (again). - - * Generic host-up and host-down scripts. - - * Optionally dump graph in graphviz format to a file or a script. - - * Support LZO 2.0 and later. - - Thanks to Scott Lamb for his contributions to this version of tinc. - -Version 1.0.4 May 4 2005 - - * Fix switch and hub modes. - - * Optionally start scripts when a Subnet becomes (un)reachable. - -Version 1.0.3 Nov 11 2004 - - * Show error message when failing to write a PID file. - - * Ignore spaces at end of lines in config files. - - * Fix handling of late packets. - - * Unify BSD tun/tap device handling. This allows IPv6 on tun devices and - anything on tap devices as long as the underlying OS supports it. - - * Handle IPv6 on Solaris tun devices. - - * Allow tinc to work properly under Windows XP SP2. - - * Allow VLAN tagged Ethernet frames in switch and hub mode. - - * Experimental PMTUDiscovery, TunnelServer and BlockingTCP options. - -Version 1.0.2 Nov 8 2003 - - * Fix address and hostname resolving under Windows. - - * Remove warnings about non-existing scripts and unsupported address families. - - * Use the event logger under Windows. - - * Fix quoting of filenames and command line arguments under Windows. - - * Strict checks for length incoming network packets and return values of - cryptographic functions, - - * Fix a bug in metadata handling that made the tinc daemon abort. - -Version 1.0.1 Aug 14 2003 - - * Allow empty lines in config files. - - * Fix handling of spaces and backslashes in filenames under native Windows. - - * Allow scripts to be executed under native Windows. - - * Update documentation, make it less Linux specific. - -Version 1.0 Aug 4 2003 - - * Lots of small bugfixes and code cleanups. - - * Throughput doubled and latency reduced. - - * Added support for LZO compression. - - * No need to set MAC address or disable ARP anymore. - - * Added support for Windows 2000 and XP, both natively and in a Cygwin - environment. - -Version 1.0pre8 Sep 16 2002 - - * More fixes for subnets with prefixlength undivisible by 8. - - * Added support for NetBSD and MacOS/X. - - * Switched from undirected graphs to directed graphs to avoid certain race - conditions and improve scalability. - - * Generalized broadcasting and forwarding of protocol messages. - - * Cleanup of source code. - -Version 1.0pre7 Apr 7 2002 - - * Don't do blocking read()s when getting a signal. - - * Remove RSA key checking code, since it sometimes thinks perfectly good RSA - keys are bad. - - * Fix handling of subnets when prefixlength isn't divisible by 8. - -Version 1.0pre6 Mar 27 2002 - - * Improvement of redundant links: - * Non-blocking connects. - * Protocol broadcast messages can no longer go into an infinite loop. - * Graph algorithm updated to look harder for direct connections. - - * Good support for routing IPv6 packets over the VPN. Works on Linux, - FreeBSD, possibly OpenBSD but not on Solaris. - - * Support for tunnels over IPv6 networks. Works on all supported - operating systems. - - * Optional compression of UDP connections using zlib. - - * Optionally let UDP connections inherit TOS field of tunneled packets. - - * Optionally start scripts when certain hosts become (un)reachable. - -Version 1.0pre5 Feb 9 2002 - - * Security enhancements: - * Added sequence number and optional message authentication code to - the packets. - * Configurable encryption cipher and digest algorithms. - - * More robust handling of dis- and reconnects. - - * Added a "switch" and a "hub" mode to allow bridging setups. - - * Preliminary support for routing of IPv6 packets. - - * Supports Linux, FreeBSD, OpenBSD and Solaris. - -Version 1.0pre4 Jan 17 2001 - - * Updated documentation; the documentation now reflects the - configuration as it is. - - * Some internal changes to make tinc scale better for large - networks, such as using AVL trees instead of linked lists for the - connection list. - - * RSA keys can be stored in separate files if needed. See the - documentation for more information. - - * Tinc has now been reported to run on Linux PowerPC and FreeBSD x86. - -Version 1.0pre3 Oct 31 2000 - - * The protocol has been redesigned, and although some details are - still under discussion, this is secure. Care has been taken to - resist most, if not all, attacks. - - * Unfortunately this protocol is not compatible with earlier versions, - nor are earlier versions compatible with this version. Because the - older protocol has huge security flaws, we feel that not - implementing backwards compatibility is justified. - - * Some data about the protocol: - * It uses public/private RSA keys for authentication (this is the - actual fix for the security hole). - * All cryptographic functions have been taken out of tinc, instead - it uses the OpenSSL library functions. - * Offers support for multiple subnets per tinc daemon. - - * New is also the support for the universal tun/tap device. This - means better portability to FreeBSD and Solaris. - - * Tinc is tested to compile on Solaris, Linux x86, Linux alpha. - - * Tinc now uses the OpenSSL library for cryptographic operations. - More information on getting and installing OpenSSL is in the manual. - This also means that the GMP library is no longer required. - - * Further, thanks to Enrique Zanardi, we have Spanish messages; Matias - Carrasco provided us with a Spanish translation of the manual. - -Version 1.0pre2 May 31 2000 - - * This version has been internationalized; and a Dutch translation has - been included. - - * Two configuration variables have been added: - * VpnMask - the IP network mask for the entire VPN, not just our - subnet (as given by MyVirtualIP). The Redhat and Debian packages - use this variable in their system startup scripts, but it is - ignored by tinc. - * Hostnames - if set to `yes', look up the names of IP addresses - trying to connect to us. Default set to `no', to prevent lockups - during lookups. - - * The system startup scripts for Debian and Redhat use - /etc/tinc/nets.boot to find out which networks need to be started - during system boot. - - * Fixes to prevent denial of service attacks by sending random data - after connecting (and even when the connection has been established), - either random garbage or just nonsensical protocol fields. - - * Tinc will retry to connect upon startup, does not quit if it doesn't - work the first time. - - * Hosts that are disconnected implicitly if we lose a connection get - deleted from the internal list, to prevent hogging eachother with - add and delete requests when the connection is restored. - -Version 1.0pre1 May 12 2000 - - * New meta-protocol - - * Various other bugfixes - - * Documentation updates - -Version 0.3.3 Feb 9 2000 - - * Fixed bug that made tinc stop working with latest kernels - - * Updated the manual - -Version 0.3.2 Nov 12 1999 - - * No more `Invalid filedescriptor' when working with multiple - connections. - - * Forward unknown packets to uplink. - -Version 0.3.1 Oct 20 1999 - - * Fixed a bug where tinc would exit without a trace. - -Version 0.3 Aug 20 1999 - - * Pings now work immediately. - - * All packet sizes get transmitted correctly. - -Version 0.2.26 Aug 15 1999 - - * Fixed some remaining bugs. - - * --sysconfdir works with configure. - - * Last version before 0.3. - -Version 0.2.25 Aug 8 1999 - - * Improved stability, going towards 0.3 now. - -Version 0.2.24 Aug 7 1999 - - * Added key aging, there's a new config variable, KeyExpire. - - * Updated man and info pages. - -Version 0.2.23 Aug 5 1999 - - * All known bugs fixed, this is a candidate for 0.3. - -Version 0.2.22 Apr 11 1999 - - * Multiconnection thing is now working nearly perfect :) - -Version 0.2.21 Apr 10 1999 - - * You shouldn't notice a thing, but a lot has changed wrt key +* You shouldn't notice a thing, but a lot has changed wrt key management - except that it refuses to talk to versions < 0.2.20 -Version 0.2.19 Apr 3 1999 +# Version 0.2.19 Apr 3 1999 - * Don't install a libcipher.so. +* Don't install a libcipher.so. -Version 0.2.18 Apr 3 1999 +# Version 0.2.18 Apr 3 1999 - * Blowfish library dynamically loaded upon execution. +* Blowfish library dynamically loaded upon execution. +* Included Eric Young's IDEA library. - * Included Eric Young's IDEA library. +# Version 0.2.17 Apr 1 1999 -Version 0.2.17 Apr 1 1999 +* Tincd now re-executes itself in case of a segmentation fault. - * Tincd now re-executes itself in case of a segmentation fault. +# Version 0.2.16 Apr 1 1999 -Version 0.2.16 Apr 1 1999 +* Wrote tincd.conf(5) man page, which still needs a lot of work. +* Config file now accepts and tolerates spaces, and any integer base + for integer variables, and better error reporting. See + doc/tincd.conf.sample for an example. - * Wrote tincd.conf(5) man page, which still needs a lot of work. +# Version 0.2.15 Mar 29 1999 - * Config file now accepts and tolerates spaces, and any integer base - for integer variables, and better error reporting. See - doc/tincd.conf.sample for an example. +* Fixed bugs. -Version 0.2.15 Mar 29 1999 +# Version 0.2.14 Feb 10 1999 - * Fixed bugs. +* Added --timeout flag and PingTimeout configuration. +* Did some first syslog cleanup work. -Version 0.2.14 Feb 10 1999 +# Version 0.2.13 Jan 23 1999 - * Added --timeout flag and PingTimeout configuration. - * Did some first syslog cleanup work. +* Bugfixes. -Version 0.2.13 Jan 23 1999 +# Version 0.2.12 Jan 23 1999 - * Bugfixes. +* Fixed nauseating bug so that it would crash whenever a connection + got lost. -Version 0.2.12 Jan 23 1999 +# Version 0.2.11 Jan 22 1999 - * Fixed nauseating bug so that it would crash whenever a connection - got lost. +* Framework for multiple connections has been done. +* Simple manpage for tincd. -Version 0.2.11 Jan 22 1999 +# Version 0.2.10 Jan 18 1999 - * Framework for multiple connections has been done. +* Passphrase support added. - * Simple manpage for tincd. +# Version 0.2.9 Jan 13 1999 -Version 0.2.10 Jan 18 1999 +* Bugs fixed. - * Passphrase support added. +# Version 0.2.8 Jan 11 1999 -Version 0.2.9 Jan 13 1999 +* A reworked protocol version. +* A ping/pong system. +* More reliable networking code. +* Automatic reconnection. +* Still does not work with more than one connection :) +* Strips MAC addresses before sending, so there's less overhead, and + less redundancy. - * Bugs fixed. +# Version 0.2.7 Jan 3 1999 -Version 0.2.8 Jan 11 1999 +* Several updates to make extending more easy. - * A reworked protocol version. +# Version 0.2.6 Dec 20 1998 - * A ping/pong system. +* Point-to-Point connections have been established, including + Blowfish encryption and a secret key-exchange. - * More reliable networking code. +# Version 0.2.5 Dec 16 1998 - * Automatic reconnection. +* Project renamed to tinc, in honour of TINC. - * Still does not work with more than one connection :) +# Version 0.2.4 Dec 16 1998 - * Strips MAC addresses before sending, so there's less overhead, and - less redundancy. +* Now it really does ;) -Version 0.2.7 Jan 3 1999 +# Version 0.2.3 Nov 24 1998 - * Several updates to make extending more easy. +* It sort of works now. -Version 0.2.6 Dec 20 1998 +# Version 0.2.2 Nov 20 1998 - * Point-to-Point connections have been established, including - Blowfish encryption and a secret key-exchange. +* Uses GNU gmp. -Version 0.2.5 Dec 16 1998 +# Version 0.2.1 Nov 14 1998 - * Project renamed to tinc, in honour of TINC. - -Version 0.2.4 Dec 16 1998 - - * Now it really does ;) - -Version 0.2.3 Nov 24 1998 - - * It sort of works now. - -Version 0.2.2 Nov 20 1998 - - * Uses GNU gmp. - -Version 0.2.1 Nov 14 1998 - - * Bare version. +* Bare version. diff --git a/README b/README index c88027b..a44853a 100644 --- a/README +++ b/README @@ -1,11 +1,7 @@ -This is the README file for tinc version 1.1pre11. Installation +This is the README file for tinc version 1.1pre12. Installation instructions may be found in the INSTALL file. -tinc is Copyright (C) 1998-2014 by: - -Ivo Timmermans, -Guus Sliepen , -and others. +tinc is Copyright © 1998-2016 Ivo Timmermans, Guus Sliepen , and others. For a complete list of authors see the AUTHORS file. @@ -36,11 +32,12 @@ at your own risk. Compatibility ------------- -Version 1.1pre11 is compatible with 1.0pre8, 1.0 and later, but not with older +Version 1.1pre12 is compatible with 1.0pre8, 1.0 and later, but not with older versions of tinc. When the ExperimentalProtocol option is used, tinc is still compatible with -1.0.X and 1.1pre11 itself, but not with any other 1.1preX version. +1.0.X, 1.1pre11 and later, but not with any version between 1.1pre1 and +1.1pre10. Requirements @@ -49,15 +46,14 @@ Requirements In order to compile tinc, you will need a GNU C compiler environment. Please ensure you have the latest stable versions of all the required libraries: -- OpenSSL (http://www.openssl.org/) version 1.0.0 or later, with support for - elliptic curve cryptography (ECC) and Galois counter mode (GCM) enabled. +- LibreSSL (http://www.libressl.org/) or OpenSSL (https://openssl.org/) version 1.0.0 or later. The following libraries are used by default, but can be disabled if necessary: -- zlib (http://www.gzip.org/zlib/) -- lzo (http://www.oberhumer.com/opensource/lzo/) +- zlib (http://www.zlib.net/) +- LZO (https://www.oberhumer.com/opensource/lzo/) - ncurses (http://invisible-island.net/ncurses/) -- readline (ftp://ftp.gnu.org/pub/gnu/readline/) +- readline (https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html) Features @@ -70,12 +66,12 @@ those nodes, tinc will learn about all other nodes on the VPN, and will make connections automatically. When direct connections are not possible, data will be forwarded by intermediate nodes. -By default, nodes authenticate each other using 2048 bit RSA (or 521 bit -ECDSA*) keys. Traffic is encrypted using Blowfish in CBC mode (or AES-256 in -GCM mode*), authenticated using HMAC-SHA1 (or GCM*), and is protected against -replay attacks. - -*) When using the ExperimentalProtocol option. +Tinc 1.1 support two protocols. The first is a legacy protocol that provides +backwards compatibility with tinc 1.0 nodes, and which by default uses 2048 bit +RSA keys for authentication, and encrypts traffic using Blowfish in CBC mode +and HMAC-SHA1. The second is a new protocol which uses Curve25519 keys for +authentication, and encrypts traffic using Chacha20-Poly1305, and provides +forward secrecy. Tinc fully supports IPv6. @@ -85,7 +81,7 @@ modes, "switch" and "hub", let the tinc daemons work together to form a virtual Ethernet network switch or hub. Normally, when started tinc will detach and run in the background. In a native -Windows environment this means tinc will intall itself as a service, which will +Windows environment this means tinc will install itself as a service, which will restart after reboots. To prevent tinc from detaching or running as a service, use the -D option. diff --git a/README.android b/README.android index 6fffe41..7d8e853 100644 --- a/README.android +++ b/README.android @@ -1,20 +1,23 @@ -Quick how-o cross compile tinc for android (done from $HOME/android/): +Quick how-to cross compile tinc for Android (done from $HOME/android/): -- Download android NDK and setup local ARM toolchain: -wget http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2 -tar xfj android-ndk-r8b-linux-x86.tar.bz2 -./android-ndk-r8b/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain +- Download Android NDK and setup local ARM toolchain: -- Download and cross-compile openSSL for ARM: -wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz -tar xfz openssl-1.0.1c.tar.gz -cd openssl-1.0.1c -./Configure dist -make CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc AR="/tmp/my-android-toolchain/bin/arm-linux-androideabi-ar r" RANLIB=/tmp/my-android-toolchain/bin/arm-linux-androideabi-ranlib + wget http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2 + tar xfj android-ndk-r8b-linux-x86.tar.bz2 + ./android-ndk-r8b/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain + +- Download and cross-compile OpenSSL for ARM: + + wget http://www.openssl.org/source/openssl-1.0.1c.tar.gz + tar xfz openssl-1.0.1c.tar.gz + cd openssl-1.0.1c + ./Configure dist + make CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc AR="/tmp/my-android-toolchain/bin/arm-linux-androideabi-ar r" RANLIB=/tmp/my-android-toolchain/bin/arm-linux-androideabi-ranlib - Clone and cross-compile tinc: -git clone git://tinc-vpn.org/tinc -cd tinc -autoreconf -fsi -CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc ./configure --host=arm-linux --disable-lzo --with-openssl-lib=$HOME/android/openssl-1.0.1c --with-openssl-include=$HOME/android/openssl-1.0.1c/include/ -make -j5 + + git clone git://tinc-vpn.org/tinc + cd tinc + autoreconf -fsi + CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc ./configure --host=arm-linux --disable-lzo --with-openssl-lib=$HOME/android/openssl-1.0.1c --with-openssl-include=$HOME/android/openssl-1.0.1c/include/ + make -j5 diff --git a/THANKS b/THANKS index d1ee6b4..527cc61 100644 --- a/THANKS +++ b/THANKS @@ -14,6 +14,7 @@ We would like to thank the following people for their contributions to tinc: * Cheng LI * Cris van Pelt * Darius Jahandarie +* Dato Simó * David Pflug * Delf Eldkraft * Dennis Joachimsthaler @@ -22,11 +23,14 @@ We would like to thank the following people for their contributions to tinc: * Erik Tews * Etienne Dechamps * Florent Clairambault +* Florian Klink +* Florian Weik * Flynn Marquardt * Franz Pletz * Gary Kessler and Claudia Gonzalez * Grzegorz Dymarek * Hans Bayle +* Harvest * Ivo van Dong * James Cook * James MacLean @@ -34,14 +38,17 @@ We would like to thank the following people for their contributions to tinc: * Jason Harper * Jason Livesay * Jelle de Jong +* Jeroen Domburg * Jeroen Ubbink * Jerome Etienne +* Jo-Philipp Wich * Jochen Voss * Julien Muchembled * Lavrans Laading * Loïc Dachary * Loïc Grenié * Lubomír Bulej +* LunarShaddow * Mads Kiilerich * Marc A. Lehmann * Mark Glines @@ -50,36 +57,51 @@ We would like to thank the following people for their contributions to tinc: * Martin Kihlgren * Martin Schobert * Martin Schürrer +* Martin Weinelt * Matias Carrasco * Max Rijevski * Menno Smits * Mesar Hameed * Michael Tokarev * Miles Nordin +* Nathan Stratton Treadway +* Murat Donmez * Nick Hibma * Nick Patavalis * Paul Littlefield * Philipp Babel +* Pierre Emeriaud +* Rafał Leśniak +* Rhosyn Celyn * Robert van der Meulen * Rumko +* Sam Bryan +* Samuel Thibault * Saverio Proto * Scott Lamb * Steffan Karger +* Stig Fagrell * Sven-Haegar Koch * Teemu Kiviniemi * Thomas Tsiakalakis +* thorkill * Timothy Redaelli +* Tomasz Fortuna * Tomislav Čohar * Tommy Arnkværn * Tonnerre Lombard +* Ulrich Seifert * Vil Brekin * Vittorio Gambaletta * Wessel Dankers * William A. Kennington III * William McArthur * Wouter van Heyst +* xentec +* 戴 鸣 And everyone we forgot (if we did, please let us know). Thank you! -Ivo Timmermans -Guus Sliepen +--- +Ivo Timmermans, +Guus Sliepen. diff --git a/aclocal.m4 b/aclocal.m4 index 16c89a3..8d101b4 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.14.1 -*- Autoconf -*- +# generated automatically by aclocal 1.15 -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# Copyright (C) 2002-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.]) # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.14' +[am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.14.1], [], +m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.14.1])dnl +[AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -110,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -141,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -332,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -408,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -498,8 +498,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl @@ -573,6 +573,9 @@ END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not @@ -602,7 +605,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -613,7 +616,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -623,7 +626,7 @@ if test x"${install_sh}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# Copyright (C) 2003-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -644,7 +647,7 @@ AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -694,7 +697,7 @@ rm -f confinc confmf # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -733,7 +736,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -762,7 +765,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -809,7 +812,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -828,7 +831,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -909,7 +912,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -969,7 +972,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -997,7 +1000,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# Copyright (C) 2006-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1016,7 +1019,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# Copyright (C) 2004-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1153,6 +1156,7 @@ m4_include([m4/ax_check_link_flag.m4]) m4_include([m4/curses.m4]) m4_include([m4/libgcrypt.m4]) m4_include([m4/lzo.m4]) +m4_include([m4/miniupnpc.m4]) m4_include([m4/openssl.m4]) m4_include([m4/readline.m4]) m4_include([m4/zlib.m4]) diff --git a/compile b/compile index 531136b..a85b723 100755 --- a/compile +++ b/compile @@ -3,7 +3,7 @@ scriptversion=2012-10-14.11; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify diff --git a/config.guess b/config.guess index 1f5c50c..1659250 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2015-08-20' # 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 @@ -24,12 +24,12 @@ timestamp='2014-03-23' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in - arm*|i386|m68k|ns32k|sh3*|sparc|vax) + arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ @@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -235,6 +249,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -579,8 +596,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -932,6 +950,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -1020,7 +1041,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} diff --git a/config.h.in b/config.h.in index 96a6079..1a567a2 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Disable support for the legacy (tinc 1.0) protocol */ +#undef DISABLE_LEGACY + /* Support for jumbograms (packets up to 9000 bytes) */ #undef ENABLE_JUMBOGRAMS @@ -36,22 +39,6 @@ /* Darwin (MacOS/X) */ #undef HAVE_DARWIN -/* Define to 1 if you have the declaration of `freeaddrinfo', and to 0 if you - don't. */ -#undef HAVE_DECL_FREEADDRINFO - -/* Define to 1 if you have the declaration of `gai_strerror', and to 0 if you - don't. */ -#undef HAVE_DECL_GAI_STRERROR - -/* Define to 1 if you have the declaration of `getaddrinfo', and to 0 if you - don't. */ -#undef HAVE_DECL_GETADDRINFO - -/* Define to 1 if you have the declaration of `getnameinfo', and to 0 if you - don't. */ -#undef HAVE_DECL_GETNAMEINFO - /* Define to 1 if you have the declaration of `OpenSSL_add_all_algorithms', and to 0 if you don't. */ #undef HAVE_DECL_OPENSSL_ADD_ALL_ALGORITHMS @@ -60,6 +47,9 @@ don't. */ #undef HAVE_DECL_RES_INIT +/* Define to 1 if you have the `devname' function. */ +#undef HAVE_DEVNAME + /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H @@ -72,6 +62,9 @@ /* Define to 1 if you have the `fchmod' function. */ #undef HAVE_FCHMOD +/* Define to 1 if you have the `fdevname' function. */ +#undef HAVE_FDEVNAME + /* Define to 1 if you have the `flock' function. */ #undef HAVE_FLOCK @@ -87,18 +80,18 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GCRYPT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_GETOPT_H + +/* getopt_long() */ +#undef HAVE_GETOPT_LONG + /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY -/* Define to 1 if you have the `get_current_dir_name' function. */ -#undef HAVE_GET_CURRENT_DIR_NAME - /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `nsl' library (-lnsl). */ -#undef HAVE_LIBNSL - /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV @@ -132,9 +125,18 @@ /* MinGW */ #undef HAVE_MINGW +/* have miniupnpc support */ +#undef HAVE_MINIUPNPC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MINIUPNPC_MINIUPNPC_H + /* Define to 1 if you have the `mlockall' function. */ #undef HAVE_MLOCKALL +/* Define to 1 if you have the `nanosleep' function. */ +#undef HAVE_NANOSLEEP + /* NetBSD */ #undef HAVE_NETBSD @@ -189,6 +191,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_IF_UTUN_H + /* Define to 1 if you have the header file. */ #undef HAVE_NET_TAP_IF_TAP_H @@ -222,9 +227,6 @@ /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV -/* Define to 1 if you have the `random' function. */ -#undef HAVE_RANDOM - /* Define to 1 if you have the `RAND_status' function. */ #undef HAVE_RAND_STATUS @@ -237,33 +239,21 @@ /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_READLINE_H +/* Define to 1 if you have the `recvmmsg' function. */ +#undef HAVE_RECVMMSG + /* Define to 1 if you have the header file. */ #undef HAVE_RESOLV_H -/* Define to 1 if you have the `select' function. */ -#undef HAVE_SELECT - -/* Define to 1 if the system has the type `socklen_t'. */ -#undef HAVE_SOCKLEN_T - /* Solaris/SunOS */ #undef HAVE_SOLARIS -/* Define to 1 if you have the header file. */ -#undef HAVE_STDBOOL_H - /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H @@ -273,12 +263,6 @@ /* Define to 1 if you have the `strsignal' function. */ #undef HAVE_STRSIGNAL -/* Define to 1 if you have the `strtol' function. */ -#undef HAVE_STRTOL - -/* Define to 1 if the system has the type `struct addrinfo'. */ -#undef HAVE_STRUCT_ADDRINFO - /* Define to 1 if the system has the type `struct arphdr'. */ #undef HAVE_STRUCT_ARPHDR @@ -294,12 +278,6 @@ /* Define to 1 if the system has the type `struct icmp6_hdr'. */ #undef HAVE_STRUCT_ICMP6_HDR -/* Define to 1 if the system has the type `struct in6_addr'. */ -#undef HAVE_STRUCT_IN6_ADDR - -/* Define to 1 if the system has the type `struct in_addr'. */ -#undef HAVE_STRUCT_IN_ADDR - /* Define to 1 if the system has the type `struct ip'. */ #undef HAVE_STRUCT_IP @@ -312,15 +290,9 @@ /* Define to 1 if the system has the type `struct nd_opt_hdr'. */ #undef HAVE_STRUCT_ND_OPT_HDR -/* Define to 1 if the system has the type `struct sockaddr_in6'. */ -#undef HAVE_STRUCT_SOCKADDR_IN6 - /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H -/* Define to 1 if you have the `system' function. */ -#undef HAVE_SYSTEM - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H @@ -348,36 +320,21 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UIO_H - /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H -/* Define to 1 if you have the `time' function. */ -#undef HAVE_TIME - -/* Define to 1 if you have the header file. */ -#undef HAVE_TIME_H - /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV -/* Define to 1 if you have the `usleep' function. */ -#undef HAVE_USLEEP - /* Define to 1 if you have the `vsyslog' function. */ #undef HAVE_VSYSLOG -/* Define to 1 if you have the `writev' function. */ -#undef HAVE_WRITEV - /* have zlib compression support */ #undef HAVE_ZLIB @@ -414,12 +371,6 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS -/* Define to 1 if you can safely include both and . */ -#undef TIME_WITH_SYS_TIME - -/* Define to 1 if your declares `struct tm'. */ -#undef TM_IN_SYS_TIME - /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE @@ -445,9 +396,6 @@ /* Version number of package */ #undef VERSION -/* Compile with support for Windows 2000 */ -#undef WITH_WINDOWS2000 - /* Define to 1 if on MINIX. */ #undef _MINIX @@ -466,16 +414,3 @@ /* Defined if the __warn_unused_result__ attribute is not supported. */ #undef __warn_unused_result__ - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `int' if does not define. */ -#undef pid_t - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to empty if the keyword `volatile' does not work. Warning: valid - code using `volatile' can become incorrect without. Disable with care. */ -#undef volatile diff --git a/config.sub b/config.sub index bba4efb..1acc966 100755 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2014-09-11' +timestamp='2015-08-20' # 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 @@ -25,7 +25,7 @@ timestamp='2014-09-11' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -68,7 +68,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,7 +117,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os @@ -255,12 +255,13 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -305,7 +306,7 @@ case $basic_machine in | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -313,6 +314,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -327,6 +329,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -372,12 +377,13 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ @@ -424,12 +430,13 @@ case $basic_machine in | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -437,6 +444,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -513,6 +521,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -774,6 +785,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -1365,7 +1379,7 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ diff --git a/configure b/configure index e1bc385..61f340b 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for tinc 1.1pre11. +# Generated by GNU Autoconf 2.69 for tinc tinc-1.1pre12. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tinc' PACKAGE_TARNAME='tinc' -PACKAGE_VERSION='1.1pre11' -PACKAGE_STRING='tinc 1.1pre11' +PACKAGE_VERSION='tinc-1.1pre12' +PACKAGE_STRING='tinc tinc-1.1pre12' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -623,12 +623,19 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +MINIUPNPC_FALSE +MINIUPNPC_TRUE +MINIUPNPC_LIBS GCRYPT_FALSE GCRYPT_TRUE OPENSSL_FALSE OPENSSL_TRUE READLINE_LIBS CURSES_LIBS +GETOPT_FALSE +GETOPT_TRUE +WITH_SYSTEMD_FALSE +WITH_SYSTEMD_TRUE TUNEMU_FALSE TUNEMU_TRUE VDE_FALSE @@ -645,6 +652,7 @@ BSD_FALSE BSD_TRUE LINUX_FALSE LINUX_TRUE +systemd_path host_os host_vendor host_cpu @@ -720,6 +728,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -747,8 +756,9 @@ enable_silent_rules enable_uml enable_vde enable_tunemu -with_windows2000 +with_systemd enable_hardening +enable_legacy_protocol enable_curses with_curses with_curses_include @@ -771,6 +781,10 @@ with_libgcrypt_lib with_openssl with_openssl_include with_openssl_lib +enable_miniupnpc +with_miniupnpc +with_miniupnpc_include +with_miniupnpc_lib enable_jumbograms ' ac_precious_vars='build_alias @@ -820,6 +834,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1072,6 +1087,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1209,7 +1233,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1322,7 +1346,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures tinc 1.1pre11 to adapt to many kinds of systems. +\`configure' configures tinc tinc-1.1pre12 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1362,6 +1386,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1392,7 +1417,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of tinc 1.1pre11:";; + short | recursive ) echo "Configuration of tinc tinc-1.1pre12:";; esac cat <<\_ACEOF @@ -1410,18 +1435,20 @@ Optional Features: --enable-vde enable support for Virtual Distributed Ethernet --enable-tunemu enable support for the tunemu driver --disable-hardening disable compiler and linker hardening flags + --disable-legacy-protocol + disable support for the legacy (tinc 1.0) protocol --disable-curses disable curses support --disable-readline disable readline support --disable-zlib disable zlib compression support --disable-lzo disable lzo compression support + --enable-miniupnpc enable miniupnpc support --enable-jumbograms enable support for jumbograms (packets up to 9000 bytes) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-windows2000 compile with support for Windows 2000. This disables - support for tunneling over existing IPv6 networks. + --with-systemd[=DIR] install systemd service files [to DIR if specified] --with-curses=DIR curses base directory, or: --with-curses-include=DIR curses headers directory @@ -1442,11 +1469,16 @@ Optional Packages: /libgcrypt) --with-libgcrypt-lib=DIR libgcrypt library directory - --with-openssl=DIR OpenSSL base directory, or: + --with-openssl=DIR LibreSSL/OpenSSL base directory, or: --with-openssl-include=DIR - OpenSSL headers directory (without trailing + LibreSSL/OpenSSL headers directory (without trailing /openssl) - --with-openssl-lib=DIR OpenSSL library directory + --with-openssl-lib=DIR LibreSSL/OpenSSL library directory + --with-miniupnpc=DIR miniupnpc base directory, or: + --with-miniupnpc-include=DIR + miniupnpc headers directory + --with-miniupnpc-lib=DIR + miniupnpc library directory Some influential environment variables: CC C compiler command @@ -1524,7 +1556,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -tinc configure 1.1pre11 +tinc configure tinc-1.1pre12 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1989,7 +2021,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by tinc $as_me 1.1pre11, which was +It was created by tinc $as_me tinc-1.1pre12, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3678,7 +3710,7 @@ $as_echo "$ac_cv_safe_to_define___extensions__" >&6; } -am__api_version='1.14' +am__api_version='1.15' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or @@ -3867,7 +3899,7 @@ else $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi -if test x"${install_sh}" != xset; then +if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; @@ -4224,7 +4256,7 @@ fi # Define the identity of the package. PACKAGE='tinc' - VERSION='1.1pre11' + VERSION='tinc-1.1pre12' cat >>confdefs.h <<_ACEOF @@ -4258,8 +4290,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # mkdir_p='$(MKDIR_P)' -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. # 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}' @@ -4448,6 +4480,46 @@ fi ac_config_headers="$ac_config_headers config.h" +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + # Enable GNU extensions. # Define this here, not in acconfig's @TOP@ section, since definitions # in the latter don't make it into the configure-time tests. @@ -4920,7 +4992,9 @@ $as_echo "#define HAVE_CYGWIN 1" >>confdefs.h $as_echo "#define HAVE_MINGW 1" >>confdefs.h - LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32" + LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi" + LDFLAGS="$LDFLAGS -static" + CPPFLAGS="$CPPFLAGS -DMINIUPNP_STATICLIB" ;; *) as_fn_error $? "\"Unknown operating system.\"" "$LINENO" 5 @@ -4996,16 +5070,24 @@ fi -# Check whether --with-windows2000 was given. -if test "${with_windows2000+set}" = set; then : - withval=$with_windows2000; if test "x$with_windows2000" = "xyes"; then : - -$as_echo "#define WITH_WINDOWS2000 1" >>confdefs.h +# Check whether --with-systemd was given. +if test "${with_systemd+set}" = set; then : + withval=$with_systemd; systemd=true; systemd_path="$with_systemd" +else + systemd=false fi +if test "x$with_systemd" = "xyes"; then : + systemd_path="/lib/systemd/system" +else + if test "x$with_systemd" = "xno"; then : + systemd=false fi +fi + +systemd_path=$systemd_path if test "$linux" = true; then @@ -5072,6 +5154,14 @@ else TUNEMU_FALSE= fi + if test "$systemd" = true; then + WITH_SYSTEMD_TRUE= + WITH_SYSTEMD_FALSE='#' +else + WITH_SYSTEMD_TRUE='#' + WITH_SYSTEMD_FALSE= +fi + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -5159,10 +5249,10 @@ $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi rm -f confcache -if test -d /sw/include ; then +if test -d /sw/include; then : CPPFLAGS="$CPPFLAGS -I/sw/include" fi -if test -d /sw/lib ; then +if test -d /sw/lib; then : LIBS="$LIBS -L/sw/lib" fi @@ -5208,7 +5298,39 @@ else : fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-strict-overflow" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fwrapv" >&5 +$as_echo_n "checking whether C compiler accepts -fwrapv... " >&6; } +if ${ax_cv_check_cflags___fwrapv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CFLAGS + CFLAGS="$CFLAGS -fwrapv" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ax_cv_check_cflags___fwrapv=yes +else + ax_cv_check_cflags___fwrapv=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fwrapv" >&5 +$as_echo "$ax_cv_check_cflags___fwrapv" >&6; } +if test x"$ax_cv_check_cflags___fwrapv" = xyes; then : + CPPFLAGS="$CPPFLAGS -fwrapv" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-strict-overflow" >&5 $as_echo_n "checking whether C compiler accepts -fno-strict-overflow... " >&6; } if ${ax_cv_check_cflags___fno_strict_overflow+:} false; then : $as_echo_n "(cached) " >&6 @@ -5243,39 +5365,6 @@ else : fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fwrapv" >&5 -$as_echo_n "checking whether C compiler accepts -fwrapv... " >&6; } -if ${ax_cv_check_cflags___fwrapv+:} false; then : - $as_echo_n "(cached) " >&6 -else - - ax_check_save_flags=$CFLAGS - CFLAGS="$CFLAGS -fwrapv" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ax_cv_check_cflags___fwrapv=yes -else - ax_cv_check_cflags___fwrapv=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$ax_check_save_flags -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fwrapv" >&5 -$as_echo "$ax_cv_check_cflags___fwrapv" >&6; } -if test x"$ax_cv_check_cflags___fwrapv" = xyes; then : - CPPFLAGS="$CPPFLAGS -fwrapv" -else - : fi case $host_os in @@ -5504,119 +5593,7 @@ fi fi; -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -for ac_header in 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 +for ac_header in syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h getopt.h 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" @@ -5629,10 +5606,10 @@ fi done -for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h +for ac_header in net/if.h net/if_types.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\" " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : @@ -5647,7 +5624,7 @@ done for ac_header in netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\" " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : @@ -5662,7 +5639,7 @@ done for ac_header in netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\" " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : @@ -5675,214 +5652,6 @@ fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - -#ifndef __cplusplus - /* Ultrix mips cc rejects this sort of thing. */ - typedef int charset[2]; - const charset cs = { 0, 0 }; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *pcpcc; - char **ppc; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - pcpcc = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++pcpcc; - ppc = (char**) pcpcc; - pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this sort of thing. */ - char tx; - char *t = &tx; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - if (s) return 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; } bx; - struct s *b = &bx; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - if (!foo) return 0; - } - return !cs[0] && !zero.x; -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_const=yes -else - ac_cv_c_const=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } -if test $ac_cv_c_const = no; then - -$as_echo "#define const /**/" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 -$as_echo_n "checking for working volatile... " >&6; } -if ${ac_cv_c_volatile+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - -volatile int x; -int * volatile y = (int *) 0; -return !x && !y; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_volatile=yes -else - ac_cv_c_volatile=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 -$as_echo "$ac_cv_c_volatile" >&6; } -if test $ac_cv_c_volatile = no; then - -$as_echo "#define volatile /**/" >>confdefs.h - -fi - -ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define pid_t int -_ACEOF - -fi - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 -$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if ${ac_cv_header_time+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include - -int -main () -{ -if ((struct tm *) 0) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_time=yes -else - ac_cv_header_time=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 -$as_echo "$ac_cv_header_time" >&6; } -if test $ac_cv_header_time = yes; then - -$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 -$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -struct tm tm; - int *p = &tm.tm_sec; - return !p; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_struct_tm=time.h -else - ac_cv_struct_tm=sys/time.h -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 -$as_echo "$ac_cv_struct_tm" >&6; } -if test $ac_cv_struct_tm = sys/time.h; then - -$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working __malloc__ attribute" >&5 $as_echo_n "checking for working __malloc__ attribute... " >&6; } @@ -5894,8 +5663,8 @@ else CFLAGS="$CFLAGS -Wall -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -void test(void) __attribute__ ((__malloc__)); - void test(void) { return; } +void *test(void) __attribute__ ((__malloc__)); + void *test(void) { return (void *)0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : @@ -5928,8 +5697,8 @@ else CFLAGS="$CFLAGS -Wall -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -void test(void) __attribute__ ((__warn_unused_result__)); - void test(void) { return; } +void *test(void) __attribute__ ((__warn_unused_result__)); + void *test(void) { return (void *)0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : @@ -5952,18 +5721,7 @@ $as_echo "#define __warn_unused_result__ /**/" >>confdefs.h fi -ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include \"src/have.h\" - -" -if test "x$ac_cv_type_socklen_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_SOCKLEN_T 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "struct ether_header" "ac_cv_type_struct_ether_header" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct ether_header" "ac_cv_type_struct_ether_header" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_ether_header" = xyes; then : @@ -5974,7 +5732,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct arphdr" "ac_cv_type_struct_arphdr" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct arphdr" "ac_cv_type_struct_arphdr" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_arphdr" = xyes; then : @@ -5985,7 +5743,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct ether_arp" "ac_cv_type_struct_ether_arp" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct ether_arp" "ac_cv_type_struct_ether_arp" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_ether_arp" = xyes; then : @@ -5996,29 +5754,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct in_addr" "ac_cv_type_struct_in_addr" "#include \"src/have.h\" - -" -if test "x$ac_cv_type_struct_in_addr" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IN_ADDR 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "#include \"src/have.h\" - -" -if test "x$ac_cv_type_struct_addrinfo" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_ADDRINFO 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "struct ip" "ac_cv_type_struct_ip" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct ip" "ac_cv_type_struct_ip" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_ip" = xyes; then : @@ -6029,7 +5765,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct icmp" "ac_cv_type_struct_icmp" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct icmp" "ac_cv_type_struct_icmp" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_icmp" = xyes; then : @@ -6040,29 +5776,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#include \"src/have.h\" - -" -if test "x$ac_cv_type_struct_in6_addr" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IN6_ADDR 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#include \"src/have.h\" - -" -if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_SOCKADDR_IN6 1 -_ACEOF - - -fi -ac_fn_c_check_type "$LINENO" "struct ip6_hdr" "ac_cv_type_struct_ip6_hdr" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct ip6_hdr" "ac_cv_type_struct_ip6_hdr" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_ip6_hdr" = xyes; then : @@ -6073,7 +5787,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct icmp6_hdr" "ac_cv_type_struct_icmp6_hdr" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct icmp6_hdr" "ac_cv_type_struct_icmp6_hdr" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_icmp6_hdr" = xyes; then : @@ -6084,7 +5798,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct nd_neighbor_solicit" "ac_cv_type_struct_nd_neighbor_solicit" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct nd_neighbor_solicit" "ac_cv_type_struct_nd_neighbor_solicit" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_nd_neighbor_solicit" = xyes; then : @@ -6095,7 +5809,7 @@ _ACEOF fi -ac_fn_c_check_type "$LINENO" "struct nd_opt_hdr" "ac_cv_type_struct_nd_opt_hdr" "#include \"src/have.h\" +ac_fn_c_check_type "$LINENO" "struct nd_opt_hdr" "ac_cv_type_struct_nd_opt_hdr" "#include \"$srcdir/src/have.h\" " if test "x$ac_cv_type_struct_nd_opt_hdr" = xyes; then : @@ -6141,7 +5855,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -for ac_func in asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev +for ac_func in asprintf daemon fchmod flock ftime fork gettimeofday mlockall putenv recvmmsg strsignal nanosleep unsetenv vsyslog devname fdevname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -6154,162 +5868,22 @@ fi done - -ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" -if test "x$ac_cv_func_socket" = xyes; then : +ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long" +if test "x$ac_cv_func_getopt_long" = xyes; then : + getopt=true; +$as_echo "#define HAVE_GETOPT_LONG 1" >>confdefs.h else + getopt=false +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 -$as_echo_n "checking for connect in -lsocket... " >&6; } -if ${ac_cv_lib_socket_connect+:} false; then : - $as_echo_n "(cached) " >&6 + if test "$getopt" = true; then + GETOPT_TRUE= + GETOPT_FALSE='#' else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket $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 connect (); -int -main () -{ -return connect (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_connect=yes -else - ac_cv_lib_socket_connect=no + GETOPT_TRUE='#' + GETOPT_FALSE= 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_socket_connect" >&5 -$as_echo "$ac_cv_lib_socket_connect" >&6; } -if test "x$ac_cv_lib_socket_connect" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSOCKET 1 -_ACEOF - - LIBS="-lsocket $LIBS" - -fi - - -fi - -ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 -$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_gethostbyname+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $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 gethostbyname (); -int -main () -{ -return gethostbyname (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nsl_gethostbyname=yes -else - ac_cv_lib_nsl_gethostbyname=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_nsl_gethostbyname" >&5 -$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } -if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBNSL 1 -_ACEOF - - LIBS="-lnsl $LIBS" - -fi - - -fi - - -ac_fn_c_check_decl "$LINENO" "freeaddrinfo" "ac_cv_have_decl_freeaddrinfo" "#include \"src/have.h\" - -" -if test "x$ac_cv_have_decl_freeaddrinfo" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_FREEADDRINFO $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "gai_strerror" "ac_cv_have_decl_gai_strerror" "#include \"src/have.h\" - -" -if test "x$ac_cv_have_decl_gai_strerror" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_GAI_STRERROR $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "getaddrinfo" "ac_cv_have_decl_getaddrinfo" "#include \"src/have.h\" - -" -if test "x$ac_cv_have_decl_getaddrinfo" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_GETADDRINFO $ac_have_decl -_ACEOF -ac_fn_c_check_decl "$LINENO" "getnameinfo" "ac_cv_have_decl_getnameinfo" "#include \"src/have.h\" - -" -if test "x$ac_cv_have_decl_getnameinfo" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_GETNAMEINFO $ac_have_decl -_ACEOF ac_fn_c_check_decl "$LINENO" "res_init" "ac_cv_have_decl_res_init" " @@ -6375,6 +5949,99 @@ fi fi +case $host_os in + *linux*) + for ac_header in linux/if_tun.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/if_tun.h" "ac_cv_header_linux_if_tun_h" "#include \"$srcdir/src/have.h\" + +" +if test "x$ac_cv_header_linux_if_tun_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_IF_TUN_H 1 +_ACEOF + +else + as_fn_error $? "Required header file missng" "$LINENO" 5 +fi + +done + + ;; + *bsd*|*dragonfly*|*darwin*) + for ac_header in net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\" + +" +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 + +fi + +done + + ;; + *solaris*) + ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" +if test "x$ac_cv_func_socket" = xyes; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $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 connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=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_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + +fi + + ;; + *) + ;; +esac + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -6461,6 +6128,18 @@ $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi rm -f confcache +# Check whether --enable-legacy-protocol was given. +if test "${enable_legacy_protocol+set}" = set; then : + enableval=$enable_legacy_protocol; if test "x$enable_legacy_protocol" = "xno"; then : + +$as_echo "#define DISABLE_LEGACY 1" >>confdefs.h + +fi + + +fi + + @@ -6993,9 +6672,9 @@ done fi -if test -n "$with_libgcrypt"; then - gcrypt=true - +if test "x$enable_legacy_protocol" != "xno"; then : + if test -n "$with_libgcrypt"; then : + gcrypt=true; # Check whether --with-libgcrypt was given. if test "${with_libgcrypt+set}" = set; then : @@ -7085,8 +6764,7 @@ fi else - openssl=true - + openssl=true; case $host_os in *mingw*) ;; @@ -7134,7 +6812,7 @@ $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : LIBS="$LIBS -ldl" else - as_fn_error $? "OpenSSL depends on libdl." "$LINENO" 5; break + as_fn_error $? "LibreSSL/OpenSSL depends on libdl." "$LINENO" 5; break fi @@ -7182,7 +6860,7 @@ if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : _ACEOF else - as_fn_error $? "OpenSSL header files not found." "$LINENO" 5; break + as_fn_error $? "LibreSSL/OpenSSL header files not found." "$LINENO" 5; break fi @@ -7228,7 +6906,7 @@ $as_echo "$ac_cv_lib_crypto_EVP_EncryptInit_ex" >&6; } if test "x$ac_cv_lib_crypto_EVP_EncryptInit_ex" = xyes; then : LIBS="-lcrypto $LIBS" else - as_fn_error $? "OpenSSL libraries not found." "$LINENO" 5 + as_fn_error $? "LibreSSL/OpenSSL libraries not found." "$LINENO" 5 fi @@ -7243,7 +6921,7 @@ if eval test \"x\$"$as_ac_var"\" = x"yes"; then : _ACEOF else - as_fn_error $? "Missing OpenSSL functionality, make sure you have installed the latest version." "$LINENO" 5; break + as_fn_error $? "Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version." "$LINENO" 5; break fi done @@ -7263,7 +6941,10 @@ _ACEOF if test $ac_have_decl = 1; then : else - as_fn_error $? "Missing OpenSSL functionality, make sure you have installed the latest version." "$LINENO" 5; break + as_fn_error $? "Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version." "$LINENO" 5; break +fi + + fi @@ -7286,6 +6967,118 @@ else fi + + # Check whether --enable-miniupnpc was given. +if test "${enable_miniupnpc+set}" = set; then : + enableval=$enable_miniupnpc; +fi + + if test "x$enable_miniupnpc" = "xyes"; then : + + +$as_echo "#define HAVE_MINIUPNPC 1" >>confdefs.h + + +# Check whether --with-miniupnpc was given. +if test "${with_miniupnpc+set}" = set; then : + withval=$with_miniupnpc; miniupnpc="$withval" + CPPFLAGS="$CPPFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib" + +fi + + + +# Check whether --with-miniupnpc-include was given. +if test "${with_miniupnpc_include+set}" = set; then : + withval=$with_miniupnpc_include; miniupnpc_include="$withval" + CPPFLAGS="$CPPFLAGS -I$withval" + +fi + + + +# Check whether --with-miniupnpc-lib was given. +if test "${with_miniupnpc_lib+set}" = set; then : + withval=$with_miniupnpc_lib; miniupnpc_lib="$withval" + LDFLAGS="$LDFLAGS -L$withval" + +fi + + + for ac_header in miniupnpc/miniupnpc.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "miniupnpc/miniupnpc.h" "ac_cv_header_miniupnpc_miniupnpc_h" "$ac_includes_default" +if test "x$ac_cv_header_miniupnpc_miniupnpc_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MINIUPNPC_MINIUPNPC_H 1 +_ACEOF + +else + as_fn_error $? "\"miniupnpc header files not found.\"" "$LINENO" 5; break + +fi + +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for upnpDiscover in -lminiupnpc" >&5 +$as_echo_n "checking for upnpDiscover in -lminiupnpc... " >&6; } +if ${ac_cv_lib_miniupnpc_upnpDiscover+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lminiupnpc $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 upnpDiscover (); +int +main () +{ +return upnpDiscover (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_miniupnpc_upnpDiscover=yes +else + ac_cv_lib_miniupnpc_upnpDiscover=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_miniupnpc_upnpDiscover" >&5 +$as_echo "$ac_cv_lib_miniupnpc_upnpDiscover" >&6; } +if test "x$ac_cv_lib_miniupnpc_upnpDiscover" = xyes; then : + MINIUPNPC_LIBS="$LIBS -lminiupnpc" +else + as_fn_error $? "\"miniupnpc libraries not found.\"" "$LINENO" 5 + +fi + + +fi + + + + if test "x$enable_miniupnpc" = "xyes"; then + MINIUPNPC_TRUE= + MINIUPNPC_FALSE='#' +else + MINIUPNPC_TRUE='#' + MINIUPNPC_FALSE= +fi + + # Check whether --enable-jumbograms was given. if test "${enable_jumbograms+set}" = set; then : enableval=$enable_jumbograms; if test "x$enable_jumbograms" = "xyes"; then : @@ -7298,7 +7091,7 @@ fi fi -ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile m4/Makefile gui/Makefile test/Makefile" +ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile gui/Makefile test/Makefile systemd/Makefile" cat >confcache <<\_ACEOF @@ -7466,6 +7259,14 @@ if test -z "${TUNEMU_TRUE}" && test -z "${TUNEMU_FALSE}"; then as_fn_error $? "conditional \"TUNEMU\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${WITH_SYSTEMD_TRUE}" && test -z "${WITH_SYSTEMD_FALSE}"; then + as_fn_error $? "conditional \"WITH_SYSTEMD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GETOPT_TRUE}" && test -z "${GETOPT_FALSE}"; then + as_fn_error $? "conditional \"GETOPT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${OPENSSL_TRUE}" && test -z "${OPENSSL_FALSE}"; then as_fn_error $? "conditional \"OPENSSL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -7474,6 +7275,10 @@ if test -z "${GCRYPT_TRUE}" && test -z "${GCRYPT_FALSE}"; then as_fn_error $? "conditional \"GCRYPT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${MINIUPNPC_TRUE}" && test -z "${MINIUPNPC_FALSE}"; then + as_fn_error $? "conditional \"MINIUPNPC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -7871,7 +7676,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by tinc $as_me 1.1pre11, which was +This file was extended by tinc $as_me tinc-1.1pre12, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7937,7 +7742,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -tinc config.status 1.1pre11 +tinc config.status tinc-1.1pre12 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -8071,9 +7876,9 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; - "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; "gui/Makefile") CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; + "systemd/Makefile") CONFIG_FILES="$CONFIG_FILES systemd/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index 6fd2621..4c0f926 100644 --- a/configure.ac +++ b/configure.ac @@ -1,11 +1,13 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([tinc], [1.1pre11]) +AC_INIT([tinc], m4_esyscmd_s((git describe || echo UNKNOWN) | sed 's/release-//')) AC_CONFIG_SRCDIR([src/tincd.c]) AC_GNU_SOURCE -AM_INIT_AUTOMAKE([check-news std-options subdir-objects -Wall]) +AM_INIT_AUTOMAKE([std-options subdir-objects nostdinc silent-rules -Wall]) AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AM_SILENT_RULES([yes]) # Enable GNU extensions. # Define this here, not in acconfig's @TOP@ section, since definitions @@ -66,7 +68,9 @@ case $host_os in *mingw*) mingw=true AC_DEFINE(HAVE_MINGW, 1, [MinGW]) - LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32" + LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi" + LDFLAGS="$LDFLAGS -static" + CPPFLAGS="$CPPFLAGS -DMINIUPNP_STATICLIB" ;; *) AC_MSG_ERROR("Unknown operating system.") @@ -107,13 +111,17 @@ AC_ARG_ENABLE(tunemu, [tunemu=false] ) -AC_ARG_WITH(windows2000, - AS_HELP_STRING([--with-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]), - [ AS_IF([test "x$with_windows2000" = "xyes"], - [AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])]) - ] +AC_ARG_WITH(systemd, + AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd service files @<:@to DIR if specified@:>@]), + [ systemd=true; systemd_path="$with_systemd" ], + [ systemd=false ] ) +AS_IF([test "x$with_systemd" = "xyes"], [systemd_path="/lib/systemd/system"], + [AS_IF([test "x$with_systemd" = "xno"], [systemd=false])]) + +AC_SUBST(systemd_path, $systemd_path) + AM_CONDITIONAL(LINUX, test "$linux" = true) AM_CONDITIONAL(BSD, test "$bsd" = true) AM_CONDITIONAL(SOLARIS, test "$solaris" = true) @@ -122,15 +130,12 @@ AM_CONDITIONAL(CYGWIN, test "$cygwin" = true) AM_CONDITIONAL(UML, test "$uml" = true) AM_CONDITIONAL(VDE, test "$vde" = true) AM_CONDITIONAL(TUNEMU, test "$tunemu" = true) +AM_CONDITIONAL(WITH_SYSTEMD, test "$systemd" = true) AC_CACHE_SAVE -if test -d /sw/include ; then - CPPFLAGS="$CPPFLAGS -I/sw/include" -fi -if test -d /sw/lib ; then - LIBS="$LIBS -L/sw/lib" -fi +AS_IF([test -d /sw/include], [CPPFLAGS="$CPPFLAGS -I/sw/include"]) +AS_IF([test -d /sw/lib], [LIBS="$LIBS -L/sw/lib"]) dnl Compiler hardening flags dnl No -fstack-protector-all because it doesn't work on all platforms or architectures. @@ -138,8 +143,8 @@ dnl No -fstack-protector-all because it doesn't work on all platforms or archite AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [disable compiler and linker hardening flags])) AS_IF([test "x$enable_hardening" != "xno"], [AX_CHECK_COMPILE_FLAG([-DFORTIFY_SOURCE=2], [CPPFLAGS="$CPPFLAGS -DFORTIFY_SOURCE=2"]) - AX_CHECK_COMPILE_FLAG([-fno-strict-overflow], [CPPFLAGS="$CPPFLAGS -fno-strict-overflow"]) - AX_CHECK_COMPILE_FLAG([-fwrapv], [CPPFLAGS="$CPPFLAGS -fwrapv"]) + AX_CHECK_COMPILE_FLAG([-fwrapv], [CPPFLAGS="$CPPFLAGS -fwrapv"], + AX_CHECK_COMPILE_FLAG([-fno-strict-overflow], [CPPFLAGS="$CPPFLAGS -fno-strict-overflow"])) case $host_os in *mingw*) AX_CHECK_LINK_FLAG([-Wl,--dynamicbase], [LDFLAGS="$LDFLAGS -Wl,--dynamicbase"]) @@ -158,79 +163,90 @@ AS_IF([test "x$enable_hardening" != "xno"], dnl Checks for header files. dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies. -AC_HEADER_STDC -AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h]) -AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h], - [], [], [#include "src/have.h"] +AC_CHECK_HEADERS([syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h getopt.h]) +AC_CHECK_HEADERS([net/if.h net/if_types.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h], + [], [], [#include "$srcdir/src/have.h"] ) AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h], - [], [], [#include "src/have.h"] + [], [], [#include "$srcdir/src/have.h"] ) AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h], - [], [], [#include "src/have.h"] + [], [], [#include "$srcdir/src/have.h"] ) dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_VOLATILE -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_STRUCT_TM - tinc_ATTRIBUTE(__malloc__) tinc_ATTRIBUTE(__warn_unused_result__) -AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , , - [#include "src/have.h"] +AC_CHECK_TYPES([struct ether_header, struct arphdr, struct ether_arp, struct ip, struct icmp, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , , + [#include "$srcdir/src/have.h"] ) dnl Checks for library functions. AC_TYPE_SIGNAL -AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev], - [], [], [#include "src/have.h"] +AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork gettimeofday mlockall putenv recvmmsg strsignal nanosleep unsetenv vsyslog devname fdevname], + [], [], [#include "$srcdir/src/have.h"] ) -dnl Support for SunOS - -AC_CHECK_FUNC(socket, [], [ - AC_CHECK_LIB(socket, connect) -]) -AC_CHECK_FUNC(gethostbyname, [], [ - AC_CHECK_LIB(nsl, gethostbyname) -]) - -AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo], - [], [], [#include "src/have.h"] -) +AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false]) +AM_CONDITIONAL(GETOPT, test "$getopt" = true) AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [ #include #include ]) +dnl Operating system specific checks +case $host_os in + *linux*) + AC_CHECK_HEADERS([linux/if_tun.h], + [], [AC_MSG_ERROR([Required header file missng])], [#include "$srcdir/src/have.h"] + ) + ;; + *bsd*|*dragonfly*|*darwin*) + AC_CHECK_HEADERS([net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h], + [], [], [#include "$srcdir/src/have.h"] + ) + ;; + *solaris*) + AC_CHECK_FUNC(socket, [], [AC_CHECK_LIB(socket, connect)]) + ;; + *) + ;; +esac + AC_CACHE_SAVE +AC_ARG_ENABLE(legacy-protocol, + AS_HELP_STRING([--disable-legacy-protocol], [disable support for the legacy (tinc 1.0) protocol]), + [ AS_IF([test "x$enable_legacy_protocol" = "xno"], + [ AC_DEFINE(DISABLE_LEGACY, 1, [Disable support for the legacy (tinc 1.0) protocol]) ]) + ] +) + dnl These are defined in files in m4/ dnl AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], []) +dnl AC_ARG_WITH(openssl, AC_HELP_STRING([--without-openssl], [disable support for OpenSSL])], []) tinc_CURSES tinc_READLINE tinc_ZLIB tinc_LZO -if test -n "$with_libgcrypt"; then - gcrypt=true - tinc_LIBGCRYPT -else - openssl=true - tinc_OPENSSL -fi - +AS_IF([test "x$enable_legacy_protocol" != "xno"], + [AS_IF([test -n "$with_libgcrypt"], + [gcrypt=true; tinc_LIBGCRYPT], + [openssl=true; tinc_OPENSSL]) + ] +) + AM_CONDITIONAL(OPENSSL, test -n "$openssl") AM_CONDITIONAL(GCRYPT, test -n "$gcrypt") +tinc_MINIUPNPC +AM_CONDITIONAL(MINIUPNPC, test "x$enable_miniupnpc" = "xyes") + dnl Check if support for jumbograms is requested AC_ARG_ENABLE(jumbograms, AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]), @@ -239,6 +255,6 @@ AC_ARG_ENABLE(jumbograms, ] ) -AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile m4/Makefile gui/Makefile test/Makefile]) +AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile gui/Makefile test/Makefile systemd/Makefile]) AC_OUTPUT diff --git a/debian/changelog b/debian/changelog index 45d32c5..c2df60c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +tinc (1.1~pre12-1) experimental; urgency=medium + + * New upstream release. + * Bump Standards-Version. + * Depend on python-wxgtk3.0 for the GUI. + * Use dh --with python2. + * Add Build-Depends for dh-python. + * Update links in debian/control and debian/copyright. + + -- Guus Sliepen Sun, 24 Apr 2016 14:51:14 +0200 + tinc (1.1~pre11-1) experimental; urgency=medium * New upstream release. diff --git a/debian/control b/debian/control index 04797e5..a701a93 100644 --- a/debian/control +++ b/debian/control @@ -2,9 +2,9 @@ Source: tinc Section: net Priority: optional Maintainer: Guus Sliepen -Standards-Version: 3.9.6 -Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 9), texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libreadline-dev, libvdeplug-dev -Homepage: http://www.tinc-vpn.org/ +Standards-Version: 3.9.7 +Build-Depends: libssl-dev (>>1.0.0), debhelper (>= 9), texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libreadline-dev, libvdeplug-dev, python | python-all | python-dev | python-all-dev, dh-python +Homepage: https://www.tinc-vpn.org/ Package: tinc Architecture: any @@ -17,7 +17,7 @@ Description: Virtual Private Network daemon Package: tinc-gui Architecture: all -Depends: ${misc:Depends}, python, python-wxgtk2.8, tinc (>= 1.1~pre3-1) +Depends: ${misc:Depends}, ${python:Depends}, python-wxgtk3.0, 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 diff --git a/debian/copyright b/debian/copyright index c8a6fb8..02e3a92 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,14 +1,14 @@ This package was debianized by Ivo Timmermans on Fri, 21 Apr 2000 17:07:50 +0200. -It was downloaded from http://www.tinc-vpn.org/ +It was downloaded from https://www.tinc-vpn.org/ Upstream Authors: Guus Sliepen - Ivo Timmermans + Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans - 1998-2008 Guus Sliepen + 1998-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ all other requirements of the GPL are met. The following applies to the LZO library: Hereby I grant a special exception to the tinc VPN project -(http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library -(http://www.openssl.org). +(https://wwww.tinc-vpn.org/) to link the LZO library with the OpenSSL library +(https://openssl.org). Markus F.X.J. Oberhumer diff --git a/debian/preinst b/debian/preinst index 9225855..030c1d0 100644 --- a/debian/preinst +++ b/debian/preinst @@ -8,7 +8,7 @@ set -e case "$1" in upgrade) - if dpkg --compare-versions "$2" '<' "1.1~pre11-1"; then + if dpkg --compare-versions "$2" '<<' "1.1~pre11-1"; then if [ -f "$NETSFILE" ]; then echo -n "Creating systemd service instances from nets.boot:" mkdir -p "$WANTS" diff --git a/debian/rules b/debian/rules index bfeb280..7b3d797 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ #include /usr/share/dpkg/buildflags.mk %: - dh $@ --parallel + dh $@ --parallel --with python2 override_dh_auto_configure: dh_auto_configure -- --enable-uml --enable-vde diff --git a/depcomp b/depcomp index 4ebd5b3..fc98710 100755 --- a/depcomp +++ b/depcomp @@ -3,7 +3,7 @@ scriptversion=2013-05-30.07; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/doc/Makefile.am b/doc/Makefile.am index a666d3b..aa15b24 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -6,7 +6,7 @@ man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz -CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi +CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi sample-config.tar.gz # Use `ginstall' in the definition of man_MANS to avoid # confusion with the `install' target. The install rule transforms `ginstall' @@ -17,19 +17,19 @@ transform = s/ginstall/install/; @program_transform_name@ # see GNUmakefile and Makefile.maint. sample-config.tar.gz: sample-config - GZIP=$(GZIP_ENV) $(AMTAR) chozf sample-config.tar.gz --exclude .svn sample-config + $(AM_V_GEN)GZIP=$(GZIP_ENV) $(AMTAR) chozf $@ --exclude .svn $< tincd.8.html: tincd.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc.8.html: tinc.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc-gui.8.html: tinc-gui.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc.conf.5.html: tinc.conf.5 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ substitute = sed \ -e s,'@PACKAGE\@',"$(PACKAGE)",g \ @@ -38,18 +38,18 @@ substitute = sed \ -e s,'@localstatedir\@',"$(localstatedir)",g tincd.8: tincd.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.8: tinc.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc-gui.8: tinc-gui.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.conf.5: tinc.conf.5.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tincinclude.texi: tincinclude.texi.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.texi: tincinclude.texi diff --git a/doc/Makefile.in b/doc/Makefile.in index db0d219..6f5c228 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -77,17 +87,17 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am texinfo.tex ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -185,6 +195,7 @@ man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in texinfo.tex DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) # Use `ginstall' in the definition of man_MANS to avoid @@ -224,6 +235,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -281,10 +293,12 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ @@ -292,7 +306,7 @@ top_srcdir = @top_srcdir@ info_TEXINFOS = tinc.texi man_MANS = tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.8.in tinc.conf.5.in tinc-gui.8.in sample-config.tar.gz -CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi +CLEANFILES = *.html tincd.8 tinc.8 tinc.conf.5 tinc-gui.8 tincinclude.texi sample-config.tar.gz substitute = sed \ -e s,'@PACKAGE\@',"$(PACKAGE)",g \ -e s,'@VERSION\@',"$(VERSION)",g \ @@ -315,7 +329,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -816,39 +829,41 @@ uninstall-man: uninstall-man5 uninstall-man8 uninstall-html-am uninstall-info-am uninstall-man \ uninstall-man5 uninstall-man8 uninstall-pdf-am uninstall-ps-am +.PRECIOUS: Makefile + # For additional rules usually of interest only to the maintainer, # see GNUmakefile and Makefile.maint. sample-config.tar.gz: sample-config - GZIP=$(GZIP_ENV) $(AMTAR) chozf sample-config.tar.gz --exclude .svn sample-config + $(AM_V_GEN)GZIP=$(GZIP_ENV) $(AMTAR) chozf $@ --exclude .svn $< tincd.8.html: tincd.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc.8.html: tinc.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc-gui.8.html: tinc-gui.8 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tinc.conf.5.html: tinc.conf.5 - w3mman2html $? > $@ + $(AM_V_GEN)w3mman2html $? > $@ tincd.8: tincd.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.8: tinc.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc-gui.8: tinc-gui.8.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.conf.5: tinc.conf.5.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tincinclude.texi: tincinclude.texi.in - $(substitute) $? > $@ + $(AM_V_GEN)$(substitute) $? > $@ tinc.texi: tincinclude.texi diff --git a/doc/sample-config.tar.gz b/doc/sample-config.tar.gz index 1a766a6..474a24f 100644 Binary files a/doc/sample-config.tar.gz and b/doc/sample-config.tar.gz differ diff --git a/doc/tinc.8.in b/doc/tinc.8.in index bb56386..6644add 100644 --- a/doc/tinc.8.in +++ b/doc/tinc.8.in @@ -11,6 +11,7 @@ .Op Fl -config Ns = Ns Ar DIR .Op Fl -net Ns = Ns Ar NETNAME .Op Fl -pidfile Ns = Ns Ar FILENAME +.Op Fl -force .Op Fl -help .Op Fl -version .Op Ar COMMAND @@ -54,6 +55,8 @@ Use the cookie from to authenticate with a running tinc daemon. If unspecified, the default is .Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid. +.It Fl -force +Force some commands to work despite warnings. .It Fl -help Display short list of options. .It Fl -version @@ -88,6 +91,7 @@ To set a variable for a specific host, use the notation .Ar host Ns Li . Ns Ar variable . .It add Ar variable Ar value As above, but without removing any previously existing configuration variables. +If the variable already exists with the given value, nothing happens. .It del Ar variable Op Ar value Remove configuration variables with the same name and .Ar value . @@ -101,16 +105,16 @@ You do not need to specify the full path to the file. 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 +.It import Import host configuration data generated by the .Nm export command from standard input. Already existing host configuration files are not overwritten unless the option .Fl -force is used. -.It exchange Op Fl -force +.It exchange The same as export followed by import. -.It exchange-all Op Fl -force +.It exchange-all The same as export-all followed by import. .It invite Ar name Prepares an invitation for a new node with the given @@ -168,6 +172,9 @@ format. Nodes are colored according to their reachability: red nodes are unreachable, orange nodes are indirectly reachable, green nodes are directly reachable. Black nodes are either directly or indirectly reachable, but direct reachability has not been tried yet. +.It dump invitations +Dump a list of outstanding invitations. +The filename of the invitation, as well as the name of the node that is being invited is shown for each invitation. .It info Ar node | subnet | address Show information about a particular node, subnet or address. If an address is given, any matching subnet will be shown. @@ -215,6 +222,38 @@ If .Ar netname is given, switch to that network. Otherwise, display a list of all networks for which configuration files exist. +.It fsck +This will check the configuration files for possible problems, +such as unsafe file permissions, missing executable bit on script, +unknown and obsolete configuration variables, wrong public and/or private keys, and so on. +.Pp +When problems are found, this will be printed on a line with WARNING or ERROR in front of it. +Most problems must be corrected by the user itself, however in some cases (like file permissions and missing public keys), +tinc will ask if it should fix the problem. +.It sign Op Ar filename +Sign a file with the local node's private key. +If no +.Ar filename +is given, the file is read from standard input. +The signed file is written to standard output. +.It verify Ar name Op Ar filename +Check the signature of a file against a node's public key. +The +.Ar name +of the node must be given, +or can be +.Li . +to check against the local node's public key, or +.Li * +to allow a signature from any node whose public key is known. +If no +.Ar filename +is given, the file is read from standard input. +If the verification is succesful, +a copy of the input with the signature removed is written to standard output, +and the exit code will be zero. +If the verification failed, +nothing will be written to standard output, and the exit code will be non-zero. .El .Sh EXAMPLES Examples of some commands: diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 9d9bf76..783c299 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -1,4 +1,4 @@ -.Dd 2014-01-29 +.Dd 2016-04-11 .Dt TINC.CONF 5 .\" Manual page created by: .\" Ivo Timmermans @@ -42,7 +42,7 @@ the configuration file should be and the host configuration files are now expected to be in .Pa @sysconfdir@/tinc/hosts/ . .Sh NAMES -Each tinc daemon should have a name that is unique in the network which it will be part of. +Each tinc daemon must have a name that is unique in the network which it will be part of. The name will be used by other tinc daemons for identification. The name has to be declared in the .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf @@ -266,6 +266,10 @@ Tinc will expect packets read from the virtual network device to start with a four byte header containing the address family, followed by an IP header. This mode should support both IPv4 and IPv6 packets. +.It utun Pq OS X +Set type to utun. +This is only supported on OS X version 10.6.8 and higher, but doesn't require the tuntaposx module. +This mode should support both IPv4 and IPv6 packets. .It tap Pq BSD and Linux Set type to tap. Tinc will expect packets read from the virtual network device @@ -358,7 +362,7 @@ This will allow direct communication using LAN addresses, even if both peers are 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 some packets to the local address of the node during path MTU discovery. This will not work with old nodes that don't transmit their local address. +Currently, local discovery is implemented by sending some packets to the local address of the node during UDP discovery. This will not work with old nodes that don't transmit their local address. .It Va MACExpire Li = Ar seconds Pq 600 This option controls the amount of time MAC addresses are kept before they are removed. This only has effect when @@ -464,10 +468,10 @@ and .Ev REMOTEPORT are available. .El -.It Va ReplayWindow Li = Ar bytes Pq 16 +.It Va ReplayWindow Li = Ar bytes Pq 32 This is the size of the replay tracking window for each remote node, in bytes. The window is a bitfield which tracks 1 packet per bit, so for example -the default setting of 16 will track up to 128 packets in the window. In high +the default setting of 32 will track up to 256 packets in the window. In high bandwidth scenarios, setting this to a higher value can reduce packet loss from the interaction of replay tracking with underlying real packet loss and/or reordering. Setting this to zero will disable replay tracking completely and @@ -485,12 +489,42 @@ and will only allow connections with nodes for which host config files are prese .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ directory. Setting this options also implicitly sets StrictSubnets. -.It Va UDPRcvBuf Li = Ar bytes Pq OS default +.It Va UDPDiscovery Li = yes | no Po yes Pc +When this option is enabled tinc will try to establish UDP connectivity to nodes, +using TCP while it determines if a node is reachable over UDP. If it is disabled, +tinc always assumes a node is reachable over UDP. +Note that tinc will never use UDP with nodes that have +.Va TCPOnly +enabled. +.It Va UDPDiscoveryKeepaliveInterval Li = Ar seconds Pq 9 +The minimum amount of time between sending UDP ping datagrams to check UDP connectivity once it has been established. +Note that these pings are large, since they are used to verify link MTU as well. +.It Va UDPDiscoveryInterval Li = Ar seconds Pq 2 +The minimum amount of time between sending UDP ping datagrams to try to establish UDP connectivity. +.It Va UDPDiscoveryTimeout Li = Ar seconds Pq 30 +If tinc doesn't receive any UDP ping replies over the specified interval, +it will assume UDP communication is broken and will fall back to TCP. +.It Va UDPInfoInterval Li = Ar seconds Pq 5 +The minimum amount of time between sending periodic updates about UDP addresses, which are mostly useful for UDP hole punching. +.It Va UDPRcvBuf Li = Ar bytes Pq 1048576 Sets the socket receive buffer size for the UDP socket, in bytes. -If unset, the default buffer size will be used by the operating system. -.It Va UDPSndBuf Li = Ar bytes Pq OS default +If set to zero, the default buffer size will be used by the operating system. +Note: this setting can have a significant impact on performance, especially raw throughput. +.It Va UDPSndBuf Li = Ar bytes Pq 1048576 Sets the socket send buffer size for the UDP socket, in bytes. -If unset, the default buffer size will be used by the operating system. +If set to zero, the default buffer size will be used by the operating system. +Note: this setting can have a significant impact on performance, especially raw throughput. +.It Va UPnP Li = yes | udponly | no Po no Pc +If this option is enabled then tinc will search for UPnP-IGD devices on the local network. +It will then create and maintain port mappings for tinc's listening TCP and UDP ports. +If set to "udponly", tinc will only create a mapping for its UDP (data) port, not for its TCP (metaconnection) port. +Note that tinc must have been built with miniupnpc support for this feature to be available. +Furthermore, be advised that enabling this can have security implications, because the miniupnpc library that +tinc uses might not be well-hardened with regard to malicious UPnP replies. +.It Va UPnPDiscoverWait Li = Ar seconds Pq 5 +The amount of time to wait for replies when probing the local network for UPnP devices. +.It Va UPnPRefreshPeriod Li = Ar seconds Pq 60 +How often tinc will re-add the port mapping, in case it gets reset on the UPnP device. This also controls the duration of the port mapping itself, which will be set to twice that duration. .El .Sh HOST CONFIGURATION FILES The host configuration files contain all information needed @@ -515,7 +549,7 @@ variables can be specified, in which case each address will be tried until a wor connection has been established. .It Va Cipher Li = Ar cipher Pq blowfish The symmetric cipher algorithm used to encrypt UDP packets. -Any cipher supported by OpenSSL is recognised. +Any cipher supported by LibreSSL or OpenSSL is recognised. Furthermore, specifying .Qq none will turn off packet encryption. @@ -532,7 +566,7 @@ Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib), 10 (fast lzo) and 11 (best lzo). .It Va Digest Li = Ar digest Pq sha1 The digest algorithm used to authenticate UDP packets. -Any digest supported by OpenSSL is recognised. +Any digest supported by LibreSSL or OpenSSL is recognised. Furthermore, specifying .Qq none will turn off packet authentication. @@ -554,6 +588,8 @@ This option controls the initial path MTU to this node. .It Va PMTUDiscovery Li = yes | no Po yes Pc When this option is enabled, tinc will try to discover the path MTU to this node. After the path MTU has been discovered, it will be enforced on the VPN. +.It Va MTUInfoInterval Li = Ar seconds Pq 5 +The minimum amount of time between sending periodic updates about relay path MTU. Useful for quickly determining MTU to indirect nodes. .It Va Port Li = Ar port Pq 655 The port number on which this tinc daemon is listening for incoming connections, which is used if no port number is specified in an @@ -625,10 +661,18 @@ forwarding packets. .Sh SCRIPTS Apart from reading the server and host configuration files, tinc can also run scripts at certain moments. -Under Windows (not Cygwin), the scripts should have the extension +Below is a list of filenames of scripts and a description of when they are run. +A script is only run if it exists and if it is executable. +.Pp +Scripts are run synchronously; +this means that tinc will temporarily stop processing packets until the called script finishes executing. +This guarantees that scripts will execute in the exact same order as the events that trigger them. +If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background. +.Pp +Under Windows (not Cygwin), the scripts must have the extension .Pa .bat or -.Pa cmd . +.Pa .cmd . .Bl -tag -width indent .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up This is the most important script. @@ -637,6 +681,7 @@ If it is present it will be executed right after the tinc daemon has been starte is used). It should be used to set up the corresponding network interface, but can also be used to start other things. +.Pp Under Windows you can use the Network Connections control panel instead of creating this script. .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down This script is started right before the tinc daemon quits (or when the last node becomes unreachable if @@ -734,7 +779,7 @@ its connection to the virtual network device. .Sh SEE ALSO .Xr tincd 8 , .Xr tinc 8 , -.Pa http://www.tinc-vpn.org/ , +.Pa https://www.tinc-vpn.org/ , .Pa http://www.tldp.org/LDP/nag2/ . .Pp The full documentation for diff --git a/doc/tinc.info b/doc/tinc.info index d294c78..9540627 100644 --- a/doc/tinc.info +++ b/doc/tinc.info @@ -1,14 +1,14 @@ -This is tinc.info, produced by makeinfo version 5.2 from tinc.texi. +This is tinc.info, produced by makeinfo version 6.1 from tinc.texi. INFO-DIR-SECTION Networking tools START-INFO-DIR-ENTRY * tinc: (tinc). The tinc Manual. END-INFO-DIR-ENTRY -This is the info manual for tinc version 1.1pre10, a Virtual Private -Network daemon. +This is the info manual for tinc version 1.1pre11-263-g51a0dc5, a +Virtual Private Network daemon. - Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen + Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and Wessel Dankers . Permission is granted to make and distribute verbatim copies of this @@ -34,6 +34,7 @@ Top * Configuration:: * Running tinc:: * Controlling tinc:: +* Invitations:: * Technical information:: * Platform specific information:: * About us:: @@ -148,7 +149,7 @@ will most likely compile and run, but it will not be able to send or receive data packets. For an up to date list of supported platforms, please check the list on -our website: . +our website: .  File: tinc.info, Node: Preparations, Next: Installation, Prev: Introduction, Up: Top @@ -220,12 +221,8 @@ File: tinc.info, Node: Configuration of OpenBSD kernels, Next: Configuration o 2.1.3 Configuration of OpenBSD kernels -------------------------------------- -For OpenBSD version 2.9 and higher, the tun driver is included in the -default kernel configuration. There is also a kernel patch from - which adds a tap device to -OpenBSD which should work with tinc, but with recent versions of -OpenBSD, a tun device can act as a tap device by setting the link0 -option with ifconfig. +Recent versions of OpenBSD come with both tun and tap devices enabled in +the default kernel configuration.  File: tinc.info, Node: Configuration of NetBSD kernels, Next: Configuration of Solaris kernels, Prev: Configuration of OpenBSD kernels, Up: Configuring the kernel @@ -248,7 +245,7 @@ For Solaris 8 (SunOS 5.8) and higher, the tun driver may or may not be included in the default kernel configuration. If it isn't, the source can be downloaded from . For x86 and sparc64 architectures, precompiled versions can be found at -. If the 'net/if_tun.h' +. If the 'net/if_tun.h' header file is missing, install it from the source package.  @@ -258,14 +255,15 @@ File: tinc.info, Node: Configuration of Darwin (MacOS/X) kernels, Next: Config ----------------------------------------------- Tinc on Darwin relies on a tunnel driver for its data acquisition from -the kernel. Tinc supports either the driver from +the kernel. OS X version 10.6.8 and later have a built-in tun driver +called "utun". Tinc also supports the driver from , which supports both tun and tap -style devices, and also the driver from from -. The former driver is -recommended. The tunnel driver must be loaded before starting tinc with -the following command: +style devices, - kmodload tunnel +By default, tinc expects the tuntaposx driver to be installed. To use +the utun driver, set add 'Device = utunX' to 'tinc.conf', where X is the +desired number for the utun interface. You can also omit the number, in +which case the first free number will be chosen.  File: tinc.info, Node: Configuration of Windows, Prev: Configuration of Darwin (MacOS/X) kernels, Up: Configuring the kernel @@ -274,7 +272,8 @@ File: tinc.info, Node: Configuration of Windows, Prev: Configuration of Darwin ------------------------------ You will need to install the latest TAP-Win32 driver from OpenVPN. You -can download it from . Using the +can download it from +. Using the Network Connections control panel, configure the TAP-Win32 network interface in the same way as you would do from the tinc-up script, as explained in the rest of the documentation. @@ -285,27 +284,27 @@ File: tinc.info, Node: Libraries, Prev: Configuring the kernel, Up: Preparati 2.2 Libraries ============= -Before you can configure or build tinc, you need to have the OpenSSL, -zlib, lzo, curses and readline libraries installed on your system. If -you try to configure tinc without having them installed, configure will -give you an error message, and stop. +Before you can configure or build tinc, you need to have the LibreSSL or +OpenSSL, zlib, lzo, curses and readline libraries installed on your +system. If you try to configure tinc without having them installed, +configure will give you an error message, and stop. * Menu: -* OpenSSL:: +* LibreSSL/OpenSSL:: * zlib:: * lzo:: * libcurses:: * libreadline::  -File: tinc.info, Node: OpenSSL, Next: zlib, Up: Libraries +File: tinc.info, Node: LibreSSL/OpenSSL, Next: zlib, Up: Libraries -2.2.1 OpenSSL -------------- +2.2.1 LibreSSL/OpenSSL +---------------------- For all cryptography-related functions, tinc uses the functions provided -by the OpenSSL library. +by the LibreSSL or the OpenSSL library. If this library is not installed, you wil get an error when configuring tinc for build. Support for running tinc with other cryptographic @@ -315,19 +314,22 @@ You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions of this package. -If you have to install OpenSSL manually, you can get the source code -from . Instructions on how to configure, build -and install this package are included within the package. Please make -sure you build development and runtime libraries (which is the default). +If your operating system comes neither with LibreSSL or OpenSSL, you +have to install one manually. It is recommended that you get the latest +version of LibreSSL from . Instructions on +how to configure, build and install this package are included within the +package. Please make sure you build development and runtime libraries +(which is the default). -If you installed the OpenSSL libraries from source, it may be necessary -to let configure know where they are, by passing configure one of the --with-openssl-* parameters. +If you installed the LibreSSL or OpenSSL libraries from source, it may +be necessary to let configure know where they are, by passing configure +one of the -with-openssl-* parameters. Note that you even have to use +-with-openssl-* if you are using LibreSSL. - --with-openssl=DIR OpenSSL library and headers prefix - --with-openssl-include=DIR OpenSSL headers directory + --with-openssl=DIR LibreSSL/OpenSSL library and headers prefix + --with-openssl-include=DIR LibreSSL/OpenSSL headers directory (Default is OPENSSL_DIR/include) - --with-openssl-lib=DIR OpenSSL library directory + --with-openssl-lib=DIR LibreSSL/OpenSSL library directory (Default is OPENSSL_DIR/lib) License @@ -336,7 +338,7 @@ License The complete source code of tinc is covered by the GNU GPL version 2. Since the license under which OpenSSL is distributed is not directly compatible with the terms of the GNU GPL -, we include an +, we include an exemption to the GPL (see also the file COPYING.README) to allow everyone to create a statically or dynamically linked executable: @@ -349,13 +351,13 @@ Since the LZO library used by tinc is also covered by the GPL, we also present the following exemption: Hereby I grant a special exception to the tinc VPN project - (http://www.tinc-vpn.org/) to link the LZO library with the OpenSSL - library (http://www.openssl.org). + (https://www.tinc-vpn.org/) to link the LZO library with the + OpenSSL library (https://www.openssl.org). Markus F.X.J. Oberhumer  -File: tinc.info, Node: zlib, Next: lzo, Prev: OpenSSL, Up: Libraries +File: tinc.info, Node: zlib, Next: lzo, Prev: LibreSSL/OpenSSL, Up: Libraries 2.2.2 zlib ---------- @@ -375,9 +377,9 @@ available. Make sure you install the development AND runtime versions of this package. If you have to install zlib manually, you can get the source code from -. Instructions on how to configure, build -and install this package are included within the package. Please make -sure you build development and runtime libraries (which is the default). +. Instructions on how to configure, build and +install this package are included within the package. Please make sure +you build development and runtime libraries (which is the default).  File: tinc.info, Node: lzo, Next: libcurses, Prev: zlib, Up: Libraries @@ -399,7 +401,7 @@ available. Make sure you install the development AND runtime versions of this package. If you have to install lzo manually, you can get the source code from -. Instructions on how to +. Instructions on how to configure, build and install this package are included within the package. Please make sure you build development and runtime libraries (which is the default). @@ -464,9 +466,7 @@ startup scripts and sample configurations. If you cannot use one of the precompiled packages, or you want to compile tinc for yourself, you can use the source. The source is distributed under the GNU General Public License (GPL). Download the -source from the download page (http://www.tinc-vpn.org/download/), which -has the checksums of these files listed; you may wish to check these -with md5sum before continuing. +source from the download page (https://www.tinc-vpn.org/download/). Tinc comes in a convenient autoconf/automake package, which you can just treat the same as any other package. Which is just untar it, type @@ -504,12 +504,12 @@ File: tinc.info, Node: Darwin (MacOS/X) build environment, Next: Cygwin (Windo 3.1.1 Darwin (MacOS/X) build environment ---------------------------------------- -In order to build tinc on Darwin, you need to install the MacOS/X -Developer Tools from -and a recent version of Fink from . +In order to build tinc on Darwin, you need to install Xcode from +. It might also help to install a +recent version of Fink from . -After installation use fink to download and install the following -packages: autoconf25, automake, dlcompat, m4, openssl, zlib and lzo. +You need to download and install LibreSSL (or OpenSSL) and LZO, either +directly from their websites (see *note Libraries::) or using Fink.  File: tinc.info, Node: Cygwin (Windows) build environment, Next: MinGW (Windows) build environment, Prev: Darwin (MacOS/X) build environment, Up: Building and installing tinc @@ -518,7 +518,7 @@ File: tinc.info, Node: Cygwin (Windows) build environment, Next: MinGW (Window ---------------------------------------- If Cygwin hasn't already been installed, install it directly from -. +. When tinc is compiled in a Cygwin environment, it can only be run in this environment, but all programs, including those started outside the @@ -532,7 +532,8 @@ File: tinc.info, Node: MinGW (Windows) build environment, Prev: Cygwin (Window --------------------------------------- You will need to install the MinGW environment from -. +. You also need to download and install LibreSSL +(or OpenSSL) and LZO. When tinc is compiled using MinGW it runs natively under Windows, it is not necessary to keep MinGW installed. @@ -661,7 +662,7 @@ the name of the virtual network interface will be the same as the network name. However, it is not strictly necessary that you call tinc with the -n -option. If you don not use it, the network name will just be empty, and +option. If you do not use it, the network name will just be empty, and tinc will look for files in '/etc/tinc/' instead of '/etc/tinc/NETNAME/'; the configuration file will then be '/etc/tinc/tinc.conf', and the host configuration files are expected to @@ -918,6 +919,11 @@ DeviceType = (platform dependent) followed by an IP header. This mode should support both IPv4 and IPv6 packets. + utun (OS X) + Set type to utun. This is only supported on OS X version + 10.6.8 and higher, but doesn't require the tuntaposx module. + This mode should support both IPv4 and IPv6 packets. + tap (BSD and Linux) Set type to tap. Tinc will expect packets read from the virtual network device to start with an Ethernet header. @@ -998,9 +1004,9 @@ LocalDiscovery = (no) 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. + Currently, local discovery is implemented by sending some packets + to the local address of the node during UDP discovery. This will + not work with old nodes that don't transmit their local address. LocalDiscoveryAddress
If this variable is specified, local discovery packets are sent to @@ -1051,9 +1057,9 @@ MaxConnectionBurst = (100) connections to only one per second, until the burst has passed. Name = [required] - This is a symbolic name for this connection. The name should - consist only of alfanumeric and underscore characters (a-z, A-Z, - 0-9 and _), and is case sensitive. + This is a symbolic name for this connection. The name must consist + only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and + _), and is case sensitive. If Name starts with a $, then the contents of the environment variable that follows will be used. In that case, invalid @@ -1092,7 +1098,7 @@ ProcessPriority = adjusted. Increasing the priority may help to reduce latency and packet loss on the VPN. -Proxy = socks4 | socks5 | http | exec ... [experimental] +Proxy = socks4 | socks5 | http | exec ... [experimental] Use a proxy when making outgoing connections. The following proxy types are currently supported: @@ -1115,10 +1121,10 @@ Proxy = socks4 | socks5 | http | exec ... [experimental] connection. The environment variables 'NAME', 'NODE', 'REMOTEADDRES' and 'REMOTEPORT' are available. -ReplayWindow = (16) +ReplayWindow = (32) This is the size of the replay tracking window for each remote node, in bytes. The window is a bitfield which tracks 1 packet per - bit, so for example the default setting of 16 will track up to 128 + bit, so for example the default setting of 32 will track up to 256 packets in the window. In high bandwidth scenarios, setting this to a higher value can reduce packet loss from the interaction of replay tracking with underlying real packet loss and/or reordering. @@ -1140,15 +1146,63 @@ TunnelServer = (no) [experimental] '/etc/tinc/NETNAME/hosts/' directory. Setting this options also implicitly sets StrictSubnets. -UDPRcvBuf = (OS default) - Sets the socket receive buffer size for the UDP socket, in bytes. - If unset, the default buffer size will be used by the operating - system. +UDPDiscovery = (yes) + When this option is enabled tinc will try to establish UDP + connectivity to nodes, using TCP while it determines if a node is + reachable over UDP. If it is disabled, tinc always assumes a node + is reachable over UDP. Note that tinc will never use UDP with nodes + that have TCPOnly enabled. -UDPSndBuf = Pq OS default +UDPDiscoveryKeepaliveInterval = (9) + The minimum amount of time between sending UDP ping datagrams to + check UDP connectivity once it has been established. Note that + these pings are large, since they are used to verify link MTU as + well. + +UDPDiscoveryInterval = (2) + The minimum amount of time between sending UDP ping datagrams to + try to establish UDP connectivity. + +UDPDiscoveryTimeout = (30) + If tinc doesn't receive any UDP ping replies over the specified + interval, it will assume UDP communication is broken and will fall + back to TCP. + +UDPInfoInterval = (5) + The minimum amount of time between sending periodic updates about + UDP addresses, which are mostly useful for UDP hole punching. + +UDPRcvBuf = (1048576) + Sets the socket receive buffer size for the UDP socket, in bytes. + If set to zero, the default buffer size will be used by the + operating system. Note: this setting can have a significant impact + on performance, especially raw throughput. + +UDPSndBuf = (1048576) Sets the socket send buffer size for the UDP socket, in bytes. If - unset, the default buffer size will be used by the operating - system. + set to zero, the default buffer size will be used by the operating + system. Note: this setting can have a significant impact on + performance, especially raw throughput. + +UPnP = (no) + If this option is enabled then tinc will search for UPnP-IGD + devices on the local network. It will then create and maintain + port mappings for tinc's listening TCP and UDP ports. If set to + "udponly", tinc will only create a mapping for its UDP (data) port, + not for its TCP (metaconnection) port. Note that tinc must have + been built with miniupnpc support for this feature to be available. + Furthermore, be advised that enabling this can have security + implications, because the miniupnpc library that tinc uses might + not be well-hardened with regard to malicious UPnP replies. + +UPnPDiscoverWait = (5) + The amount of time to wait for replies when probing the local + network for UPnP devices. + +UPnPRefreshPeriod = (5) + How often tinc will re-add the port mapping, in case it gets reset + on the UPnP device. This also controls the duration of the port + mapping itself, which will be set to twice that duration.  File: tinc.info, Node: Host configuration variables, Next: Scripts, Prev: Main configuration variables, Up: Configuration files @@ -1166,8 +1220,8 @@ Address = [] [recommended] Cipher = (blowfish) The symmetric cipher algorithm used to encrypt UDP packets using - the legacy protocol. Any cipher supported by OpenSSL is - recognized. Furthermore, specifying "none" will turn off packet + the legacy protocol. Any cipher supported by LibreSSL or OpenSSL + is recognized. Furthermore, specifying "none" will turn off packet encryption. It is best to use only those ciphers which support CBC mode. This option has no effect for connections using the SPTPS protocol, which always use AES-256-CTR. @@ -1185,10 +1239,10 @@ Compression = (0) Digest = (sha1) The digest algorithm used to authenticate UDP packets using the - legacy protocol. Any digest supported by OpenSSL is recognized. - Furthermore, specifying "none" will turn off packet authentication. - This option has no effect for connections using the SPTPS protocol, - which always use HMAC-SHA-256. + legacy protocol. Any digest supported by LibreSSL or OpenSSL is + recognized. Furthermore, specifying "none" will turn off packet + authentication. This option has no effect for connections using + the SPTPS protocol, which always use HMAC-SHA-256. IndirectData = (no) When set to yes, other nodes which do not already have a meta @@ -1210,6 +1264,11 @@ PMTUDiscovery = (yes) to this node. After the path MTU has been discovered, it will be enforced on the VPN. +MTUInfoInterval = (5) + The minimum amount of time between sending periodic updates about + relay path MTU. Useful for quickly determining MTU to indirect + nodes. + Port = (655) This is the port this tinc daemon listens on. You can use decimal portnumbers or symbolic names (as listed in '/etc/services'). @@ -1249,7 +1308,7 @@ Subnet = Prefixlength is the number of bits set to 1 in the netmask part; for example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes /22. This conforms to standard CIDR notation as described - in RFC1519 (http://www.ietf.org/rfc/rfc1519.txt) + in RFC1519 (https://www.ietf.org/rfc/rfc1519.txt) A Subnet can be given a weight to indicate its priority over identical Subnets owned by different nodes. The default weight is @@ -1278,16 +1337,28 @@ File: tinc.info, Node: Scripts, Next: How to configure, Prev: Host configurat ------------- Apart from reading the server and host configuration files, tinc can -also run scripts at certain moments. Under Windows (not Cygwin), the -scripts should have the extension '.bat' or '.cmd'. +also run scripts at certain moments. Below is a list of filenames of +scripts and a description of when they are run. A script is only run if +it exists and if it is executable. + +Scripts are run synchronously; this means that tinc will temporarily +stop processing packets until the called script finishes executing. +This guarantees that scripts will execute in the exact same order as the +events that trigger them. If you need to run commands asynchronously, +you have to ensure yourself that they are being run in the background. + +Under Windows (not Cygwin), the scripts should have the extension '.bat' +or '.cmd'. '/etc/tinc/NETNAME/tinc-up' This is the most important script. If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device. It should be used to set up the corresponding network interface, but can also be used to - start other things. Under Windows you can use the Network - Connections control panel instead of creating this script. + start other things. + + Under Windows you can use the Network Connections control panel + instead of creating this script. '/etc/tinc/NETNAME/tinc-down' This script is started right before the tinc daemon quits. @@ -2029,7 +2100,7 @@ bugreport: ping or traceroute).  -File: tinc.info, Node: Controlling tinc, Next: Technical information, Prev: Running tinc, Up: Top +File: tinc.info, Node: Controlling tinc, Next: Invitations, Prev: Running tinc, Up: Top 6 Controlling tinc ****************** @@ -2071,6 +2142,9 @@ File: tinc.info, Node: tinc runtime options, Next: tinc environment variables, daemon. If unspecified, the default is '/var/run/tinc.NETNAME.pid'. +'--force' + Force some commands to work despite warnings. + '--help' Display a short reminder of runtime options and commands, then terminate. @@ -2112,7 +2186,8 @@ File: tinc.info, Node: tinc commands, Next: tinc examples, Prev: tinc environ 'add VARIABLE VALUE' As above, but without removing any previously existing - configuration variables. + configuration variables. If the variable already exists with the + given value, nothing happens. 'del VARIABLE [VALUE]' Remove configuration variables with the same name and VALUE. If no @@ -2130,15 +2205,15 @@ File: tinc.info, Node: tinc commands, Next: tinc examples, Prev: tinc environ 'export-all' Export all host configuration files to standard output. -'import [--force]' +'import' Import host configuration file(s) generated by the tinc export command from standard input. Already existing host configuration files are not overwritten unless the option -force is used. -'exchange [--force]' +'exchange' The same as export followed by import. -'exchange-all [--force]' +'exchange-all' The same as export-all followed by import. 'invite NAME' @@ -2202,6 +2277,11 @@ File: tinc.info, Node: tinc commands, Next: tinc examples, Prev: tinc environ Black nodes are either directly or indirectly reachable, but direct reachability has not been tried yet. +'dump invitations' + Dump a list of outstanding invitations. The filename of the + invitation, as well as the name of the node that is being invited + is shown for each invitation. + 'info NODE | SUBNET | ADDRESS' Show information about a particular NODE, SUBNET or ADDRESS. If an ADDRESS is given, any matching subnet will be shown. @@ -2238,10 +2318,39 @@ File: tinc.info, Node: tinc commands, Next: tinc examples, Prev: tinc environ file or piped through a program that can parse it directly, such as tcpdump. -'network' +'network [NETNAME]' If NETNAME is given, switch to that network. Otherwise, display a list of all networks for which configuration files exist. +'fsck' + This will check the configuration files for possible problems, such + as unsafe file permissions, missing executable bit on script, + unknown and obsolete configuration variables, wrong public and/or + private keys, and so on. + + When problems are found, this will be printed on a line with + WARNING or ERROR in front of it. Most problems must be corrected + by the user itself, however in some cases (like file permissions + and missing public keys), tinc will ask if it should fix the + problem. + +'sign [FILENAME]' + Sign a file with the local node's private key. If no FILENAME is + given, the file is read from standard input. The signed file is + written to standard output. + +'verify NAME [FILENAME]' + + Check the signature of a file against a node's public key. The + NAME of the node must be given, or can be "." to check against the + local node's public key, or "*" to allow a signature from any node + whose public key is known. If no FILENAME is given, the file is + read from standard input. If the verification is succesful, a copy + of the input with the signature removed is written to standard + output, and the exit code will be zero. If the verification + failed, nothing will be written to standard output, and the exit + code will be non-zero. +  File: tinc.info, Node: tinc examples, Next: tinc top, Prev: tinc commands, Up: Controlling tinc @@ -2325,9 +2434,170 @@ can be changed using the following keys: Quit.  -File: tinc.info, Node: Technical information, Next: Platform specific information, Prev: Controlling tinc, Up: Top +File: tinc.info, Node: Invitations, Next: Technical information, Prev: Controlling tinc, Up: Top -7 Technical information +7 Invitations +************* + +Invitations are an easy way to add new nodes to an existing VPN. +Invitations can be created on an existing node using the 'tinc invite' +command, which generates a relatively short URL which can be given to +someone else, who uses the 'tinc join' command to automatically set up +tinc so it can connect to the inviting node. The next sections describe +how invitations actually work, and how to further automate the +invitations. + +* Menu: + +* How invitations work:: +* Invitation file format:: +* Writing an invitation-created script:: + + +File: tinc.info, Node: How invitations work, Next: Invitation file format, Up: Invitations + +7.1 How invitations work +======================== + +When an invitation is created on a node (which from now on we will call +the server) using the 'tinc invite' command, an invitation file is +created that contains all the information necessary for the invitee +(which we will call the client) to create its configuration files. The +invitation file is stays on the server, but a URL is generated that has +enough information for the client to contact the server and to retrieve +the invitation file. The whole URL is around 80 characters long and +looks like this: + + server.example.org:12345/cW1NhLHS-1WPFlcFio8ztYHvewTTKYZp8BjEKg3vbMtDz7w4 + +It is composed of four parts: + + hostname : port / keyhash cookie + +The hostname and port tell the client how to reach the tinc daemon on +the server. The part after the slash looks like one blob, but is +composed of two parts. The keyhash is the hash of the public key of the +server. The cookie is a shared secret that identifies the client to the +server. + +When the client connects to the server in order to join the VPN, the +client and server will exchange temporary public keys. The client +verifies that the hash of the server's public key matches the keyhash +from the invitation URL. If not, it will immediately exit with an error. +Otherwise, an ECDH exchange will happen so the client and server can +communicate privately with each other. The client will then present the +cookie to the server. The server uses this to look up the corresponding +invitation file it generated earlier. If it exists, it will send the +invitation file to the client. The client will also create a permanent +public key, and send it to the server. After the exchange is completed, +the connection is broken. The server creates a host config file for the +client containing the client's permanent public key, and the client +creates tinc.conf, host config files and possibly a tinc-up script based +on the information in the invitation file. + +It is important that the invitation URL is kept secret until it is used; +if another person gets a copy of the invitation URL before the real +client runs the 'tinc join' command, then that other person can try to +join the VPN. + + +File: tinc.info, Node: Invitation file format, Next: Writing an invitation-created script, Prev: How invitations work, Up: Invitations + +7.2 Invitation file format +========================== + +The contents of an invitation file that is generated by the 'tinc +invite' command looks like this: + + Name = client + Netname = vpn + ConnectTo = server + #-------------------------------------# + Name = server + Ed25519PublicKey = augbnwegoij123587... + Address = server.example.com + +The file is basically a concatenation of several host config blocks. +Each host config block starts with 'Name = ...'. Lines that look like +'#---#' are not important, it just makes it easier for humans to read +the file. + +The first host config block is always the one representing the invitee. +So the first Name statement determines the name that the invitee will +get. From the first block, the 'tinc.conf' and 'hosts/client' files +will be generated; the 'tinc join' command on the client will +automatically separate statements based on whether they should be in +'tinc.conf' or in a host config file. Some statements are special and +are treated differently: + +Netname = + This is a hint to the invitee which netname to use for the VPN. It + is used if the invitee did not already specify a netname, and if + there is no pre-existing configuration with the same netname. + +Ifconfig = + This is a hint for generating a 'tinc-up' script. If an address is + specified, a command will be added to 'tinc-up' so the VPN + interface will be configured to have the given address. If it is + the word "dhcp", a command will be added to start a DHCP client on + the VPN interface. If it is the word dhcpv6, it will be a DHCPv6 + client. If it is "slaac", then it will add commands to enable IPv6 + stateless address autoconfiguration. It is also possible to + specify a MAC address, in which case a command will be added to set + the MAC address of the VPN interface. + + The exact commands added to the 'tinc-up' script depends on the + operating system the client is using. Multiple Ifconfig statements + can be specified, however one should only use one Ifconfig + statement per address family. + +Route = [] + This is a hint for generating a 'tinc-up' script. Route statements + are similar to Ifconfig statements, but add routes instead of + addresses. These only allow IPv4 and IPv6 routes. If no gateway + address is specified, the route is directed to the VPN interface. + In general, a gateway is only necessary when running tinc in switch + mode. + +Subsequent host config blocks are copied verbatim into their respective +files in 'hosts/'. The invitation file generated by 'tinc invite' will +normally only contain two blocks; one for the client and one for the +server. + + +File: tinc.info, Node: Writing an invitation-created script, Prev: Invitation file format, Up: Invitations + +7.3 Writing an invitation-created script +======================================== + +When an invitation is generated, the "invitation-created" script is +called (if it exists) right after the invitation file is written, but +before the URL has been written to stdout. This allows one to change +the invitation file automatically before the invitation URL is passed to +the invitee. Here is an example shell script that aproximately +recreates the default invitation file: + + #!/bin/sh + + cat >$INVITATION_FILE <>$INVITATION_FILE + +You can add more ConnectTo statements, and change 'tinc export' to 'tinc +export-all' for example. But you can also use the script to +automatically hand out a Subnet to the invitee. Note that the script +doesn't have to be a shell script, you can use any language, it just has +to be executable. + + +File: tinc.info, Node: Technical information, Next: Platform specific information, Prev: Invitations, Up: Top + +8 Technical information *********************** * Menu: @@ -2339,7 +2609,7 @@ File: tinc.info, Node: Technical information, Next: Platform specific informat  File: tinc.info, Node: The connection, Next: The meta-protocol, Up: Technical information -7.1 The connection +8.1 The connection ================== Tinc is a daemon that takes VPN data and transmit that to another host @@ -2353,7 +2623,7 @@ computer over the existing Internet infrastructure.  File: tinc.info, Node: The UDP tunnel, Next: The meta-connection, Up: The connection -7.1.1 The UDP tunnel +8.1.1 The UDP tunnel -------------------- The data itself is read from a character device file, the so-called @@ -2412,7 +2682,7 @@ Solaris.  File: tinc.info, Node: The meta-connection, Prev: The UDP tunnel, Up: The connection -7.1.2 The meta-connection +8.1.2 The meta-connection ------------------------- Having only a UDP connection available is not enough. Though suitable @@ -2444,7 +2714,7 @@ re-sending packets.  File: tinc.info, Node: The meta-protocol, Next: Security, Prev: The connection, Up: Technical information -7.2 The meta-protocol +8.2 The meta-protocol ===================== The meta protocol is used to tie all tinc daemons together, and exchange @@ -2549,7 +2819,7 @@ This basically covers what is sent over the meta connection by tinc.  File: tinc.info, Node: Security, Prev: The meta-protocol, Up: Technical information -7.3 Security +8.3 Security ============ Tinc got its name from "TINC," short for _There Is No Cabal_; the @@ -2582,7 +2852,7 @@ option set to yes, otherwise the legacy protocol will be used.  File: tinc.info, Node: Legacy authentication protocol, Next: Simple Peer-to-Peer Security, Up: Security -7.3.1 Legacy authentication protocol +8.3.1 Legacy authentication protocol ------------------------------------ daemon message @@ -2679,7 +2949,7 @@ provide perfect forward secrecy.  File: tinc.info, Node: Simple Peer-to-Peer Security, Next: Encryption of network packets, Prev: Legacy authentication protocol, Up: Security -7.3.2 Simple Peer-to-Peer Security +8.3.2 Simple Peer-to-Peer Security ---------------------------------- The SPTPS protocol is designed to address the weaknesses in the legacy @@ -2837,7 +3107,7 @@ counter.  File: tinc.info, Node: Encryption of network packets, Next: Security issues, Prev: Simple Peer-to-Peer Security, Up: Security -7.3.3 Encryption of network packets +8.3.3 Encryption of network packets ----------------------------------- A data packet can only be sent if the encryption key is known to both @@ -2867,7 +3137,7 @@ intercept. The encryption algorithm and message authentication algorithm can be changed in the configuration. The length of the message authentication codes is also adjustable. The length of the key for the encryption algorithm is always the default length used by -OpenSSL. +LibreSSL/OpenSSL. The SPTPS protocol is described in *note Simple Peer-to-Peer Security::. For comparison, this is how SPTPS UDP packets look: @@ -2887,15 +3157,15 @@ digest, this cannot be changed.  File: tinc.info, Node: Security issues, Prev: Encryption of network packets, Up: Security -7.3.4 Security issues +8.3.4 Security issues --------------------- In August 2000, we discovered the existence of a security hole in all versions of tinc up to and including 1.0pre2. This had to do with the way we exchanged keys. Since then, we have been working on a new authentication scheme to make tinc as secure as possible. The current -version uses the OpenSSL library and uses strong authentication with RSA -keys. +version uses the LibreSSL or OpenSSL library and uses strong +authentication with RSA keys. On the 29th of December 2001, Jerome Etienne posted a security analysis of tinc 1.0pre4. Due to a lack of sequence numbers and a message @@ -2923,7 +3193,7 @@ tinc or give us feedback, you are stronly encouraged to do so.  File: tinc.info, Node: Platform specific information, Next: About us, Prev: Technical information, Up: Top -8 Platform specific information +9 Platform specific information ******************************* * Menu: @@ -2934,7 +3204,7 @@ File: tinc.info, Node: Platform specific information, Next: About us, Prev: T  File: tinc.info, Node: Interface configuration, Next: Routes, Up: Platform specific information -8.1 Interface configuration +9.1 Interface configuration =========================== When configuring an interface, one normally assigns it an address and a @@ -2984,7 +3254,7 @@ Linux 'ip tuntap add dev' INTERFACE 'mode' TUN|TAP 'user' USERNAME  File: tinc.info, Node: Routes, Prev: Interface configuration, Up: Platform specific information -8.2 Routes +9.2 Routes ========== In some cases it might be necessary to add more routes to the virtual @@ -3020,8 +3290,8 @@ Windows 'netsh interface ipv6 add route' NETWORK ADDRESS/PREFIXLENGTH  File: tinc.info, Node: About us, Next: Concept Index, Prev: Platform specific information, Up: Top -9 About us -********** +10 About us +*********** * Menu: @@ -3031,21 +3301,21 @@ File: tinc.info, Node: About us, Next: Concept Index, Prev: Platform specific  File: tinc.info, Node: Contact information, Next: Authors, Up: About us -9.1 Contact information -======================= +10.1 Contact information +======================== -Tinc's website is at , this server is located +Tinc's website is at , this server is located in the Netherlands. We have an IRC channel on the FreeNode and OFTC IRC networks. Connect -to irc.freenode.net (http://www.freenode.net/) or irc.oftc.net -(http://www.oftc.net/) and join channel #tinc. +to irc.freenode.net (https://freenode.net/) or irc.oftc.net +(https://www.oftc.net/) and join channel #tinc.  File: tinc.info, Node: Authors, Prev: Contact information, Up: About us -9.2 Authors -=========== +10.2 Authors +============ Ivo Timmermans (zarq) Guus Sliepen (guus) () @@ -3092,7 +3362,7 @@ Concept Index * CHAL_REPLY: Legacy authentication protocol. (line 6) * CIDR notation: Host configuration variables. - (line 96) + (line 101) * Cipher: Host configuration variables. (line 14) * ClampMSS: Host configuration variables. @@ -3108,17 +3378,17 @@ Concept Index (line 65) * daemon: Running tinc. (line 11) * data-protocol: The meta-connection. (line 18) -* debug: tinc commands. (line 121) +* debug: tinc commands. (line 127) * debug level: Runtime options. (line 17) * debug levels: Debug levels. (line 6) * DecrementTTL: Main configuration variables. (line 76) -* del: tinc commands. (line 26) +* del: tinc commands. (line 27) * DEL_EDGE: The meta-protocol. (line 46) * DEL_SUBNET: The meta-protocol. (line 46) * Device: Main configuration variables. (line 85) -* DEVICE: Scripts. (line 60) +* DEVICE: Scripts. (line 72) * device files: Device files. (line 6) * DeviceStandby: Main configuration variables. (line 92) @@ -3127,111 +3397,117 @@ Concept Index * Digest: Host configuration variables. (line 33) * DirectOnly: Main configuration variables. - (line 164) -* disconnect: tinc commands. (line 136) + (line 169) +* disconnect: tinc commands. (line 142) * dummy: Main configuration variables. (line 106) -* dump: tinc commands. (line 94) +* dump: tinc commands. (line 95) * Ed25519PrivateKeyFile: Main configuration variables. - (line 171) -* edit: tinc commands. (line 31) + (line 176) +* edit: tinc commands. (line 32) * encapsulating: The UDP tunnel. (line 30) * encryption: Encryption of network packets. (line 6) -* environment variables: Scripts. (line 48) +* environment variables: Scripts. (line 60) * example: Example configuration. (line 6) -* exchange: tinc commands. (line 47) -* exchange-all: tinc commands. (line 50) +* exchange: tinc commands. (line 48) +* exchange-all: tinc commands. (line 51) * exec: Main configuration variables. - (line 352) + (line 357) * ExperimentalProtocol: Main configuration variables. - (line 175) -* export: tinc commands. (line 35) -* export-all: tinc commands. (line 39) + (line 180) +* export: tinc commands. (line 36) +* export-all: tinc commands. (line 40) * Forwarding: Main configuration variables. - (line 182) + (line 187) * frame type: The UDP tunnel. (line 6) -* generate-ed25519-keys: tinc commands. (line 85) -* generate-keys: tinc commands. (line 80) -* generate-rsa-keys: tinc commands. (line 88) +* fsck: tinc commands. (line 160) +* generate-ed25519-keys: tinc commands. (line 86) +* generate-keys: tinc commands. (line 81) +* generate-rsa-keys: tinc commands. (line 89) * get: tinc commands. (line 11) -* graph: tinc commands. (line 107) +* graph: tinc commands. (line 108) * Hostnames: Main configuration variables. - (line 202) + (line 207) * http: Main configuration variables. - (line 349) + (line 354) * hub: Main configuration variables. - (line 270) + (line 275) * ID: Legacy authentication protocol. (line 6) -* import: tinc commands. (line 42) +* Ifconfig: Invitation file format. + (line 35) +* import: tinc commands. (line 43) * IndirectData: Host configuration variables. (line 40) -* info: tinc commands. (line 114) +* info: tinc commands. (line 120) * init: tinc commands. (line 6) * Interface: Main configuration variables. - (line 213) -* INTERFACE: Scripts. (line 63) -* INVITATION_FILE: Scripts. (line 86) -* INVITATION_URL: Scripts. (line 90) -* invite: tinc commands. (line 53) + (line 218) +* INTERFACE: Scripts. (line 75) +* INVITATION_FILE: Scripts. (line 98) +* INVITATION_URL: Scripts. (line 102) +* invite: tinc commands. (line 54) * IRC: Contact information. (line 9) -* join: tinc commands. (line 58) +* join: tinc commands. (line 59) * KeyExpire: Main configuration variables. - (line 275) + (line 280) * KEY_CHANGED: The meta-protocol. (line 63) * legacy authentication protocol: Legacy authentication protocol. (line 6) * libcurses: libcurses. (line 6) * libraries: Libraries. (line 6) * libreadline: libreadline. (line 6) -* license: OpenSSL. (line 35) +* LibreSSL: LibreSSL/OpenSSL. (line 6) +* license: LibreSSL/OpenSSL. (line 38) * ListenAddress: Main configuration variables. - (line 221) + (line 226) * LocalDiscovery: Main configuration variables. - (line 233) + (line 238) * LocalDiscoveryAddress: Main configuration variables. - (line 244) -* log: tinc commands. (line 124) + (line 249) +* log: tinc commands. (line 130) * lzo: lzo. (line 6) * MACExpire: Main configuration variables. - (line 281) + (line 286) * MACLength: Host configuration variables. (line 45) * MaxConnectionBurst: Main configuration variables. - (line 286) + (line 291) * meta-protocol: The meta-connection. (line 18) * META_KEY: Legacy authentication protocol. (line 6) * Mode: Main configuration variables. - (line 248) + (line 253) +* MTUInfoInterval: Host configuration variables. + (line 60) * multicast: Main configuration variables. (line 118) * multiple networks: Multiple networks. (line 6) * Name: Main configuration variables. - (line 292) -* NAME: Scripts. (line 57) + (line 297) +* NAME: Scripts. (line 69) * netmask: Network interfaces. (line 39) * netname: Multiple networks. (line 6) -* NETNAME: Scripts. (line 54) +* NETNAME: Scripts. (line 66) * NETNAME <1>: tinc environment variables. (line 6) +* network: tinc commands. (line 156) * Network Administrators Guide: Configuration introduction. (line 15) -* network [NETNAME]: tinc commands. (line 150) -* NODE: Scripts. (line 67) -* OpenSSL: OpenSSL. (line 6) +* NODE: Scripts. (line 79) +* OpenSSL: LibreSSL/OpenSSL. (line 6) * options: Runtime options. (line 9) -* pcap: tinc commands. (line 144) +* pcap: tinc commands. (line 150) * PEM format: Host configuration variables. - (line 72) -* pid: tinc commands. (line 77) + (line 77) +* pid: tinc commands. (line 78) * PING: The meta-protocol. (line 88) * PingInterval: Main configuration variables. - (line 303) + (line 308) * PingTimeout: Main configuration variables. - (line 307) + (line 312) * platforms: Supported platforms. (line 6) * PMTU: Host configuration variables. (line 52) @@ -3239,39 +3515,41 @@ Concept Index (line 55) * PONG: The meta-protocol. (line 88) * Port: Host configuration variables. - (line 60) + (line 65) * port numbers: Other files. (line 17) * PriorityInheritance: Main configuration variables. - (line 313) + (line 318) * private: Virtual Private Networks. (line 10) * PrivateKey: Main configuration variables. - (line 318) + (line 323) * PrivateKeyFile: Main configuration variables. - (line 324) -* ProcessPriority: Main configuration variables. (line 329) -* Proxy: Main configuration variables. +* ProcessPriority: Main configuration variables. (line 334) +* Proxy: Main configuration variables. + (line 339) * PublicKey: Host configuration variables. - (line 64) + (line 69) * PublicKeyFile: Host configuration variables. - (line 67) -* purge: tinc commands. (line 118) + (line 72) +* purge: tinc commands. (line 124) * raw_socket: Main configuration variables. (line 111) * release: Supported platforms. (line 14) -* reload: tinc commands. (line 72) -* REMOTEADDRESS: Scripts. (line 72) -* REMOTEPORT: Scripts. (line 75) +* reload: tinc commands. (line 73) +* REMOTEADDRESS: Scripts. (line 84) +* REMOTEPORT: Scripts. (line 87) * ReplayWindow: Main configuration variables. - (line 357) + (line 362) * requirements: Libraries. (line 6) * REQ_KEY: The meta-protocol. (line 63) -* restart: tinc commands. (line 69) -* retry: tinc commands. (line 129) +* restart: tinc commands. (line 70) +* retry: tinc commands. (line 135) +* Route: Invitation file format. + (line 51) * router: Main configuration variables. - (line 251) + (line 256) * runtime options: Runtime options. (line 9) * scalability: tinc. (line 19) * scripts: Scripts. (line 6) @@ -3279,54 +3557,74 @@ Concept Index (line 18) * set: tinc commands. (line 16) * shell: Controlling tinc. (line 11) +* sign: tinc commands. (line 172) * signals: Signals. (line 6) * socks4: Main configuration variables. - (line 338) -* socks5: Main configuration variables. (line 343) +* socks5: Main configuration variables. + (line 348) * SPTPS: Simple Peer-to-Peer Security. (line 6) -* start: tinc commands. (line 63) -* stop: tinc commands. (line 66) +* start: tinc commands. (line 64) +* stop: tinc commands. (line 67) * StrictSubnets: Main configuration variables. - (line 368) + (line 373) * Subnet: Host configuration variables. - (line 79) -* SUBNET: Scripts. (line 79) + (line 84) +* SUBNET: Scripts. (line 91) * SVPN: Security. (line 11) * switch: Main configuration variables. - (line 259) + (line 264) * TCP: The meta-connection. (line 10) * TCPonly: Host configuration variables. - (line 108) + (line 113) * tinc: Introduction. (line 6) * TINC: Security. (line 6) -* tinc-down: Scripts. (line 18) -* tinc-up: Scripts. (line 10) +* tinc-down: Scripts. (line 30) +* tinc-up: Scripts. (line 20) * tinc-up <1>: Network interfaces. (line 19) * tincd: tinc. (line 14) -* top: tinc commands. (line 139) +* top: tinc commands. (line 145) * top <1>: tinc top. (line 6) * traditional VPNs: tinc. (line 19) * tunifhead: Main configuration variables. (line 153) * TunnelServer: Main configuration variables. - (line 375) + (line 380) * tunnohead: Main configuration variables. (line 147) * UDP: The UDP tunnel. (line 30) * UDP <1>: Encryption of network packets. (line 11) -* UDPRcvBuf: Main configuration variables. - (line 382) -* UDPSndBuf: Main configuration variables. +* UDPDiscoveryInterval: Main configuration variables. + (line 400) +* UDPDiscoveryKeepaliveInterval: Main configuration variables. + (line 394) +* UDPDiscoveryTimeout: Main configuration variables. + (line 404) +* UDPDiscovey: Main configuration variables. (line 387) +* UDPInfoInterval: Main configuration variables. + (line 409) +* UDPRcvBuf: Main configuration variables. + (line 413) +* UDPSndBuf: Main configuration variables. + (line 419) * UML: Main configuration variables. (line 129) * Universal tun/tap: Configuration of Linux kernels. (line 6) +* UPnP: Main configuration variables. + (line 425) +* UPnPDiscoverWait: Main configuration variables. + (line 436) +* UPnPRefreshPeriod: Main configuration variables. + (line 440) +* utun: Main configuration variables. + (line 160) * VDE: Main configuration variables. (line 134) +* verify: tinc commands. (line 177) * virtual: Virtual Private Networks. (line 18) * virtual network device: The UDP tunnel. (line 6) @@ -3335,81 +3633,85 @@ Concept Index * vpnd: tinc. (line 6) * website: Contact information. (line 6) * Weight: Host configuration variables. - (line 115) -* WEIGHT: Scripts. (line 82) + (line 120) +* WEIGHT: Scripts. (line 94) * zlib: zlib. (line 6)  Tag Table: -Node: Top808 -Node: Introduction1128 -Node: Virtual Private Networks1932 -Node: tinc3644 -Node: Supported platforms5156 -Node: Preparations5852 -Node: Configuring the kernel6108 -Node: Configuration of Linux kernels6517 -Node: Configuration of FreeBSD kernels7366 -Node: Configuration of OpenBSD kernels7831 -Node: Configuration of NetBSD kernels8439 -Node: Configuration of Solaris kernels8841 -Node: Configuration of Darwin (MacOS/X) kernels9502 -Node: Configuration of Windows10191 -Node: Libraries10704 -Node: OpenSSL11140 -Node: zlib13412 -Node: lzo14430 -Node: libcurses15420 -Node: libreadline16330 -Node: Installation17267 -Node: Building and installing tinc18276 -Node: Darwin (MacOS/X) build environment18932 -Node: Cygwin (Windows) build environment19496 -Node: MinGW (Windows) build environment20080 -Node: System files20598 -Node: Device files20863 -Node: Other files21276 -Node: Configuration21889 -Node: Configuration introduction22176 -Node: Multiple networks23697 -Node: How connections work25065 -Node: Configuration files27626 -Node: Main configuration variables29258 -Node: Host configuration variables47397 -Node: Scripts53256 -Node: How to configure56657 -Node: Network interfaces61141 -Node: Example configuration63520 -Node: Running tinc68619 -Node: Runtime options69206 -Node: Signals72066 -Node: Debug levels72915 -Node: Solving problems73851 -Node: Error messages75277 -Node: Sending bug reports79594 -Node: Controlling tinc80541 -Node: tinc runtime options81287 -Node: tinc environment variables81974 -Node: tinc commands82303 -Node: tinc examples87567 -Node: tinc top88129 -Node: Technical information89714 -Node: The connection89949 -Node: The UDP tunnel90261 -Node: The meta-connection93306 -Node: The meta-protocol94764 -Node: Security99747 -Node: Legacy authentication protocol101084 -Node: Simple Peer-to-Peer Security105701 -Node: Encryption of network packets111346 -Node: Security issues113975 -Node: Platform specific information115710 -Node: Interface configuration115938 -Node: Routes118379 -Node: About us120290 -Node: Contact information120465 -Node: Authors120867 -Node: Concept Index121269 +Node: Top821 +Node: Introduction1157 +Node: Virtual Private Networks1961 +Node: tinc3673 +Node: Supported platforms5185 +Node: Preparations5882 +Node: Configuring the kernel6138 +Node: Configuration of Linux kernels6547 +Node: Configuration of FreeBSD kernels7396 +Node: Configuration of OpenBSD kernels7861 +Node: Configuration of NetBSD kernels8218 +Node: Configuration of Solaris kernels8620 +Node: Configuration of Darwin (MacOS/X) kernels9282 +Node: Configuration of Windows10095 +Node: Libraries10634 +Node: LibreSSL/OpenSSL11091 +Node: zlib13617 +Node: lzo14639 +Node: libcurses15630 +Node: libreadline16540 +Node: Installation17477 +Node: Building and installing tinc18381 +Node: Darwin (MacOS/X) build environment19037 +Node: Cygwin (Windows) build environment19596 +Node: MinGW (Windows) build environment20181 +Node: System files20769 +Node: Device files21034 +Node: Other files21447 +Node: Configuration22060 +Node: Configuration introduction22347 +Node: Multiple networks23868 +Node: How connections work25235 +Node: Configuration files27796 +Node: Main configuration variables29428 +Node: Host configuration variables50169 +Node: Scripts56239 +Node: How to configure60139 +Node: Network interfaces64623 +Node: Example configuration67002 +Node: Running tinc72101 +Node: Runtime options72688 +Node: Signals75548 +Node: Debug levels76397 +Node: Solving problems77333 +Node: Error messages78759 +Node: Sending bug reports83076 +Node: Controlling tinc84023 +Node: tinc runtime options84759 +Node: tinc environment variables85508 +Node: tinc commands85837 +Node: tinc examples92695 +Node: tinc top93257 +Node: Invitations94842 +Node: How invitations work95505 +Node: Invitation file format97798 +Node: Writing an invitation-created script100723 +Node: Technical information101785 +Node: The connection102015 +Node: The UDP tunnel102327 +Node: The meta-connection105372 +Node: The meta-protocol106830 +Node: Security111813 +Node: Legacy authentication protocol113150 +Node: Simple Peer-to-Peer Security117767 +Node: Encryption of network packets123412 +Node: Security issues126050 +Node: Platform specific information127797 +Node: Interface configuration128025 +Node: Routes130466 +Node: About us132377 +Node: Contact information132554 +Node: Authors132957 +Node: Concept Index133361  End Tag Table diff --git a/doc/tinc.texi b/doc/tinc.texi index 2cb55a7..cb50e74 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -15,7 +15,7 @@ This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon. -Copyright @copyright{} 1998-2014 Ivo Timmermans, +Copyright @copyright{} 1998-2016 Ivo Timmermans, Guus Sliepen and Wessel Dankers . @@ -43,7 +43,7 @@ permission notice identical to this one. @vskip 0pt plus 1filll This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon. -Copyright @copyright{} 1998-2014 Ivo Timmermans, +Copyright @copyright{} 1998-2016 Ivo Timmermans, Guus Sliepen and Wessel Dankers . @@ -70,6 +70,7 @@ permission notice identical to this one. * Configuration:: * Running tinc:: * Controlling tinc:: +* Invitations:: * Technical information:: * Platform specific information:: * About us:: @@ -191,7 +192,7 @@ packets. @cindex release For an up to date list of supported platforms, please check the list on our website: -@uref{http://www.tinc-vpn.org/platforms/}. +@uref{https://www.tinc-vpn.org/platforms/}. @c @c @@ -273,12 +274,7 @@ The tap driver can be loaded with @code{kldload if_tap}, or by adding @code{if_t @node Configuration of OpenBSD kernels @subsection Configuration of OpenBSD kernels -For OpenBSD version 2.9 and higher, -the tun driver is included in the default kernel configuration. -There is also a kernel patch from @uref{http://diehard.n-r-g.com/stuff/openbsd/} -which adds a tap device to OpenBSD which should work with tinc, -but with recent versions of OpenBSD, -a tun device can act as a tap device by setting the link0 option with ifconfig. +Recent versions of OpenBSD come with both tun and tap devices enabled in the default kernel configuration. @c ================================================================== @@ -298,7 +294,7 @@ Tunneling IPv6 may not work on NetBSD's tun device. For Solaris 8 (SunOS 5.8) and higher, the tun driver may or may not be included in the default kernel configuration. If it isn't, the source can be downloaded from @uref{http://vtun.sourceforge.net/tun/}. -For x86 and sparc64 architectures, precompiled versions can be found at @uref{http://www.monkey.org/~dugsong/fragroute/}. +For x86 and sparc64 architectures, precompiled versions can be found at @uref{https://www.monkey.org/~dugsong/fragroute/}. If the @file{net/if_tun.h} header file is missing, install it from the source package. @@ -307,15 +303,14 @@ If the @file{net/if_tun.h} header file is missing, install it from the source pa @subsection Configuration of Darwin (MacOS/X) kernels Tinc on Darwin relies on a tunnel driver for its data acquisition from the kernel. -Tinc supports either the driver from @uref{http://tuntaposx.sourceforge.net/}, +OS X version 10.6.8 and later have a built-in tun driver called "utun". +Tinc also supports the driver from @uref{http://tuntaposx.sourceforge.net/}, which supports both tun and tap style devices, -and also the driver from from @uref{http://chrisp.de/en/projects/tunnel.html}. -The former driver is recommended. -The tunnel driver must be loaded before starting tinc with the following command: -@example -kmodload tunnel -@end example +By default, tinc expects the tuntaposx driver to be installed. +To use the utun driver, set add @code{Device = utunX} to @file{tinc.conf}, +where X is the desired number for the utun interface. +You can also omit the number, in which case the first free number will be chosen. @c ================================================================== @@ -323,7 +318,7 @@ kmodload tunnel @subsection Configuration of Windows You will need to install the latest TAP-Win32 driver from OpenVPN. -You can download it from @uref{http://openvpn.sourceforge.net}. +You can download it from @uref{https://openvpn.net/index.php/open-source/downloads.html}. Using the Network Connections control panel, configure the TAP-Win32 network interface in the same way as you would do from the tinc-up script, as explained in the rest of the documentation. @@ -335,13 +330,13 @@ as explained in the rest of the documentation. @cindex requirements @cindex libraries -Before you can configure or build tinc, you need to have the OpenSSL, zlib, +Before you can configure or build tinc, you need to have the LibreSSL or OpenSSL, zlib, lzo, curses and readline libraries installed on your system. If you try to configure tinc without having them installed, configure will give you an error message, and stop. @menu -* OpenSSL:: +* LibreSSL/OpenSSL:: * zlib:: * lzo:: * libcurses:: @@ -350,12 +345,13 @@ message, and stop. @c ================================================================== -@node OpenSSL -@subsection OpenSSL +@node LibreSSL/OpenSSL +@subsection LibreSSL/OpenSSL +@cindex LibreSSL @cindex OpenSSL For all cryptography-related functions, tinc uses the functions provided -by the OpenSSL library. +by the LibreSSL or the OpenSSL library. If this library is not installed, you wil get an error when configuring tinc for build. Support for running tinc with other cryptographic libraries @@ -365,21 +361,23 @@ You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions of this package. -If you have to install OpenSSL manually, you can get the source code -from @url{http://www.openssl.org/}. Instructions on how to configure, -build and install this package are included within the package. Please -make sure you build development and runtime libraries (which is the +If your operating system comes neither with LibreSSL or OpenSSL, you have to +install one manually. It is recommended that you get the latest version of +LibreSSL from @url{http://www.libressl.org/}. Instructions on how to +configure, build and install this package are included within the package. +Please make sure you build development and runtime libraries (which is the default). -If you installed the OpenSSL libraries from source, it may be necessary +If you installed the LibreSSL or OpenSSL libraries from source, it may be necessary to let configure know where they are, by passing configure one of the ---with-openssl-* parameters. +--with-openssl-* parameters. Note that you even have to use --with-openssl-* if you +are using LibreSSL. @example ---with-openssl=DIR OpenSSL library and headers prefix ---with-openssl-include=DIR OpenSSL headers directory +--with-openssl=DIR LibreSSL/OpenSSL library and headers prefix +--with-openssl-include=DIR LibreSSL/OpenSSL headers directory (Default is OPENSSL_DIR/include) ---with-openssl-lib=DIR OpenSSL library directory +--with-openssl-lib=DIR LibreSSL/OpenSSL library directory (Default is OPENSSL_DIR/lib) @end example @@ -390,7 +388,7 @@ to let configure know where they are, by passing configure one of the The complete source code of tinc is covered by the GNU GPL version 2. Since the license under which OpenSSL is distributed is not directly compatible with the terms of the GNU GPL -@uref{http://www.openssl.org/support/faq.html#LEGAL2}, we +@uref{https://www.openssl.org/support/faq.html#LEGAL2}, we include an exemption to the GPL (see also the file COPYING.README) to allow everyone to create a statically or dynamically linked executable: @@ -406,8 +404,8 @@ we also present the following exemption: @quotation Hereby I grant a special exception to the tinc VPN project -(http://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library -(http://www.openssl.org). +(https://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library +(https://www.openssl.org). Markus F.X.J. Oberhumer @end quotation @@ -432,7 +430,7 @@ available. Make sure you install the development AND runtime versions of this package. If you have to install zlib manually, you can get the source code -from @url{http://www.gzip.org/zlib/}. Instructions on how to configure, +from @url{http://www.zlib.net/}. Instructions on how to configure, build and install this package are included within the package. Please make sure you build development and runtime libraries (which is the default). @@ -456,7 +454,7 @@ available. Make sure you install the development AND runtime versions of this package. If you have to install lzo manually, you can get the source code -from @url{http://www.oberhumer.com/opensource/lzo/}. Instructions on how to configure, +from @url{https://www.oberhumer.com/opensource/lzo/}. Instructions on how to configure, build and install this package are included within the package. Please make sure you build development and runtime libraries (which is the default). @@ -527,9 +525,7 @@ system startup scripts and sample configurations. If you cannot use one of the precompiled packages, or you want to compile tinc for yourself, you can use the source. The source is distributed under the GNU General Public License (GPL). Download the source from the -@uref{http://www.tinc-vpn.org/download/, download page}, which has -the checksums of these files listed; you may wish to check these with -md5sum before continuing. +@uref{https://www.tinc-vpn.org/download/, download page}. Tinc comes in a convenient autoconf/automake package, which you can just treat the same as any other package. Which is just untar it, type @@ -566,19 +562,18 @@ The documentation that comes along with your distribution will tell you how to d @node Darwin (MacOS/X) build environment @subsection Darwin (MacOS/X) build environment -In order to build tinc on Darwin, you need to install the MacOS/X Developer Tools -from @uref{http://developer.apple.com/tools/macosxtools.html} and -a recent version of Fink from @uref{http://www.finkproject.org/}. +In order to build tinc on Darwin, you need to install Xcode from @uref{https://developer.apple.com/xcode/}. +It might also help to install a recent version of Fink from @uref{http://www.finkproject.org/}. -After installation use fink to download and install the following packages: -autoconf25, automake, dlcompat, m4, openssl, zlib and lzo. +You need to download and install LibreSSL (or OpenSSL) and LZO, +either directly from their websites (see @ref{Libraries}) or using Fink. @c ================================================================== @node Cygwin (Windows) build environment @subsection Cygwin (Windows) build environment If Cygwin hasn't already been installed, install it directly from -@uref{http://www.cygwin.com/}. +@uref{https://www.cygwin.com/}. When tinc is compiled in a Cygwin environment, it can only be run in this environment, but all programs, including those started outside the Cygwin environment, will be able to use the VPN. @@ -589,6 +584,7 @@ It will also support all features. @subsection MinGW (Windows) build environment You will need to install the MinGW environment from @uref{http://www.mingw.org}. +You also need to download and install LibreSSL (or OpenSSL) and LZO. When tinc is compiled using MinGW it runs natively under Windows, it is not necessary to keep MinGW installed. @@ -735,7 +731,7 @@ You will also notice that log messages it appears in syslog as coming from @file and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name. However, it is not strictly necessary that you call tinc with the -n -option. If you don not use it, the network name will just be empty, and +option. If you do not use it, the network name will just be empty, and tinc will look for files in @file{@value{sysconfdir}/tinc/} instead of @file{@value{sysconfdir}/tinc/@var{netname}/}; the configuration file will then be @file{@value{sysconfdir}/tinc/tinc.conf}, @@ -999,6 +995,12 @@ to start with a four byte header containing the address family, followed by an IP header. This mode should support both IPv4 and IPv6 packets. +@cindex utun +@item utun (OS X) +Set type to utun. +This is only supported on OS X version 10.6.8 and higher, but doesn't require the tuntaposx module. +This mode should support both IPv4 and IPv6 packets. + @item tap (BSD and Linux) Set type to tap. Tinc will expect packets read from the virtual network device @@ -1081,8 +1083,8 @@ This will allow direct communication using LAN addresses, even if both peers are 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. +Currently, local discovery is implemented by sending some packets to the local address of the node during UDP discovery. +This will not work with old nodes that don't transmit their local address. @cindex LocalDiscoveryAddress @item LocalDiscoveryAddress <@var{address}> @@ -1139,7 +1141,7 @@ until the burst has passed. @cindex Name @item Name = <@var{name}> [required] This is a symbolic name for this connection. -The name should consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _), and is case sensitive. +The name must consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _), and is case sensitive. If Name starts with a $, then the contents of the environment variable that follows will be used. In that case, invalid characters will be converted to underscores. @@ -1207,10 +1209,10 @@ The environment variables @env{NAME}, @env{NODE}, @env{REMOTEADDRES} and @env{RE @end table @cindex ReplayWindow -@item ReplayWindow = (16) +@item ReplayWindow = (32) This is the size of the replay tracking window for each remote node, in bytes. The window is a bitfield which tracks 1 packet per bit, so for example -the default setting of 16 will track up to 128 packets in the window. In high +the default setting of 32 will track up to 256 packets in the window. In high bandwidth scenarios, setting this to a higher value can reduce packet loss from the interaction of replay tracking with underlying real packet loss and/or reordering. Setting this to zero will disable replay tracking completely and @@ -1232,15 +1234,60 @@ and will only allow connections with nodes for which host config files are prese @file{@value{sysconfdir}/tinc/@var{netname}/hosts/} directory. Setting this options also implicitly sets StrictSubnets. +@cindex UDPDiscovey +@item UDPDiscovery = (yes) +When this option is enabled tinc will try to establish UDP connectivity to nodes, +using TCP while it determines if a node is reachable over UDP. If it is disabled, +tinc always assumes a node is reachable over UDP. +Note that tinc will never use UDP with nodes that have TCPOnly enabled. + +@cindex UDPDiscoveryKeepaliveInterval +@item UDPDiscoveryKeepaliveInterval = (9) +The minimum amount of time between sending UDP ping datagrams to check UDP connectivity once it has been established. +Note that these pings are large, since they are used to verify link MTU as well. + +@cindex UDPDiscoveryInterval +@item UDPDiscoveryInterval = (2) +The minimum amount of time between sending UDP ping datagrams to try to establish UDP connectivity. + +@cindex UDPDiscoveryTimeout +@item UDPDiscoveryTimeout = (30) +If tinc doesn't receive any UDP ping replies over the specified interval, +it will assume UDP communication is broken and will fall back to TCP. + +@cindex UDPInfoInterval +@item UDPInfoInterval = (5) +The minimum amount of time between sending periodic updates about UDP addresses, which are mostly useful for UDP hole punching. + @cindex UDPRcvBuf -@item UDPRcvBuf = (OS default) +@item UDPRcvBuf = (1048576) Sets the socket receive buffer size for the UDP socket, in bytes. -If unset, the default buffer size will be used by the operating system. +If set to zero, the default buffer size will be used by the operating system. +Note: this setting can have a significant impact on performance, especially raw throughput. @cindex UDPSndBuf -@item UDPSndBuf = Pq OS default +@item UDPSndBuf = (1048576) Sets the socket send buffer size for the UDP socket, in bytes. -If unset, the default buffer size will be used by the operating system. +If set to zero, the default buffer size will be used by the operating system. +Note: this setting can have a significant impact on performance, especially raw throughput. + +@cindex UPnP +@item UPnP = (no) +If this option is enabled then tinc will search for UPnP-IGD devices on the local network. +It will then create and maintain port mappings for tinc's listening TCP and UDP ports. +If set to "udponly", tinc will only create a mapping for its UDP (data) port, not for its TCP (metaconnection) port. +Note that tinc must have been built with miniupnpc support for this feature to be available. +Furthermore, be advised that enabling this can have security implications, because the miniupnpc library that +tinc uses might not be well-hardened with regard to malicious UPnP replies. + +@cindex UPnPDiscoverWait +@item UPnPDiscoverWait = (5) +The amount of time to wait for replies when probing the local network for UPnP devices. + +@cindex UPnPRefreshPeriod +@item UPnPRefreshPeriod = (5) +How often tinc will re-add the port mapping, in case it gets reset on the UPnP device. +This also controls the duration of the port mapping itself, which will be set to twice that duration. @end table @@ -1262,7 +1309,7 @@ tried until a working connection has been established. @cindex Cipher @item Cipher = <@var{cipher}> (blowfish) The symmetric cipher algorithm used to encrypt UDP packets using the legacy protocol. -Any cipher supported by OpenSSL is recognized. +Any cipher supported by LibreSSL or OpenSSL is recognized. Furthermore, specifying "none" will turn off packet encryption. It is best to use only those ciphers which support CBC mode. This option has no effect for connections using the SPTPS protocol, which always use AES-256-CTR. @@ -1282,7 +1329,7 @@ Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib), @cindex Digest @item Digest = <@var{digest}> (sha1) The digest algorithm used to authenticate UDP packets using the legacy protocol. -Any digest supported by OpenSSL is recognized. +Any digest supported by LibreSSL or OpenSSL is recognized. Furthermore, specifying "none" will turn off packet authentication. This option has no effect for connections using the SPTPS protocol, which always use HMAC-SHA-256. @@ -1308,6 +1355,10 @@ This option controls the initial path MTU to this node. When this option is enabled, tinc will try to discover the path MTU to this node. After the path MTU has been discovered, it will be enforced on the VPN. +@cindex MTUInfoInterval +@item MTUInfoInterval = (5) +The minimum amount of time between sending periodic updates about relay path MTU. Useful for quickly determining MTU to indirect nodes. + @cindex Port @item Port = <@var{port}> (655) This is the port this tinc daemon listens on. @@ -1353,7 +1404,7 @@ MAC addresses are notated like 0:1a:2b:3c:4d:5e. Prefixlength is the number of bits set to 1 in the netmask part; for example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes /22. This conforms to standard CIDR notation as described in -@uref{http://www.ietf.org/rfc/rfc1519.txt, RFC1519} +@uref{https://www.ietf.org/rfc/rfc1519.txt, RFC1519} A Subnet can be given a weight to indicate its priority over identical Subnets owned by different nodes. The default weight is 10. Lower values indicate @@ -1384,6 +1435,14 @@ connection when broadcasting or forwarding packets. @cindex scripts Apart from reading the server and host configuration files, tinc can also run scripts at certain moments. +Below is a list of filenames of scripts and a description of when they are run. +A script is only run if it exists and if it is executable. + +Scripts are run synchronously; +this means that tinc will temporarily stop processing packets until the called script finishes executing. +This guarantees that scripts will execute in the exact same order as the events that trigger them. +If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background. + Under Windows (not Cygwin), the scripts should have the extension @file{.bat} or @file{.cmd}. @table @file @@ -1394,6 +1453,7 @@ If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device. It should be used to set up the corresponding network interface, but can also be used to start other things. + Under Windows you can use the Network Connections control panel instead of creating this script. @cindex tinc-down @@ -2226,6 +2286,9 @@ Use the cookie from @var{filename} to authenticate with a running tinc daemon. If unspecified, the default is @file{@value{localstatedir}/run/tinc.@var{netname}.pid}. +@item --force +Force some commands to work despite warnings. + @item --help Display a short reminder of runtime options and commands, then terminate. @@ -2272,6 +2335,7 @@ To set a variable for a specific host, use the notation @var{host}.@var{variable @cindex add @item add @var{variable} @var{value} As above, but without removing any previously existing configuration variables. +If the variable already exists with the given value, nothing happens. @cindex del @item del @var{variable} [@var{value}] @@ -2292,16 +2356,16 @@ Export the host configuration file of the local node to standard output. Export all host configuration files to standard output. @cindex import -@item import [--force] +@item import Import host configuration file(s) generated by the tinc export command from standard input. Already existing host configuration files are not overwritten unless the option --force is used. @cindex exchange -@item exchange [--force] +@item exchange The same as export followed by import. @cindex exchange-all -@item exchange-all [--force] +@item exchange-all The same as export-all followed by import. @cindex invite @@ -2373,6 +2437,10 @@ 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 dump invitations +Dump a list of outstanding invitations. +The filename of the invitation, as well as the name of the node that is being invited is shown for each invitation. + @cindex info @item info @var{node} | @var{subnet} | @var{address} Show information about a particular @var{node}, @var{subnet} or @var{address}. @@ -2415,11 +2483,38 @@ Dump VPN traffic going through the local tinc node in pcap-savefile format to st from where it can be redirected to a file or piped through a program that can parse it directly, such as tcpdump. -@cindex network [@var{netname}] -@item network +@cindex network +@item network [@var{netname}] If @var{netname} is given, switch to that network. Otherwise, display a list of all networks for which configuration files exist. +@cindex fsck +@item fsck +This will check the configuration files for possible problems, +such as unsafe file permissions, missing executable bit on script, +unknown and obsolete configuration variables, wrong public and/or private keys, and so on. + +When problems are found, this will be printed on a line with WARNING or ERROR in front of it. +Most problems must be corrected by the user itself, however in some cases (like file permissions and missing public keys), +tinc will ask if it should fix the problem. + +@cindex sign +@item sign [@var{filename}] +Sign a file with the local node's private key. +If no @var{filename} is given, the file is read from standard input. +The signed file is written to standard output. + +@cindex verify +@item verify @var{name} [@var{filename}] + +Check the signature of a file against a node's public key. +The @var{name} of the node must be given, +or can be "." to check against the local node's public key, +or "*" to allow a signature from any node whose public key is known. +If no @var{filename} is given, the file is read from standard input. +If the verification is succesful, a copy of the input with the signature removed is written to standard output, and the exit code will be zero. +If the verification failed, nothing will be written to standard output, and the exit code will be non-zero. + @end table @c ================================================================== @@ -2506,6 +2601,159 @@ Quit. @end table +@c ================================================================== +@node Invitations +@chapter Invitations + +Invitations are an easy way to add new nodes to an existing VPN. Invitations +can be created on an existing node using the @code{tinc invite} command, which +generates a relatively short URL which can be given to someone else, who uses +the @code{tinc join} command to automatically set up tinc so it can connect to +the inviting node. The next sections describe how invitations actually work, +and how to further automate the invitations. + +@menu +* How invitations work:: +* Invitation file format:: +* Writing an invitation-created script:: +@end menu + + +@c ================================================================== +@node How invitations work +@section How invitations work + +When an invitation is created on a node (which from now on we will call the +server) using the @code{tinc invite} command, an invitation file is created +that contains all the information necessary for the invitee (which we will call +the client) to create its configuration files. The invitation file is stays on +the server, but a URL is generated that has enough information for the client +to contact the server and to retrieve the invitation file. The whole URL is +around 80 characters long and looks like this: + +@example +server.example.org:12345/cW1NhLHS-1WPFlcFio8ztYHvewTTKYZp8BjEKg3vbMtDz7w4 +@end example + +It is composed of four parts: + +@example +hostname : port / keyhash cookie +@end example + +The hostname and port tell the client how to reach the tinc daemon on the server. +The part after the slash looks like one blob, but is composed of two parts. +The keyhash is the hash of the public key of the server. +The cookie is a shared secret that identifies the client to the server. + +When the client connects to the server in order to join the VPN, the client and +server will exchange temporary public keys. The client verifies that the hash +of the server's public key matches the keyhash from the invitation URL. If +not, it will immediately exit with an error. Otherwise, an ECDH exchange will +happen so the client and server can communicate privately with each other. The +client will then present the cookie to the server. The server uses this to +look up the corresponding invitation file it generated earlier. If it exists, +it will send the invitation file to the client. The client will also create a +permanent public key, and send it to the server. After the exchange is +completed, the connection is broken. The server creates a host config file for +the client containing the client's permanent public key, and the client creates +tinc.conf, host config files and possibly a tinc-up script based on the +information in the invitation file. + +It is important that the invitation URL is kept secret until it is used; if +another person gets a copy of the invitation URL before the real client runs +the @code{tinc join} command, then that other person can try to join the VPN. + + +@c ================================================================== +@node Invitation file format +@section Invitation file format + +The contents of an invitation file that is generated by the @code{tinc invite} +command looks like this: + +@example +Name = client +Netname = vpn +ConnectTo = server +#-------------------------------------# +Name = server +Ed25519PublicKey = augbnwegoij123587... +Address = server.example.com +@end example + +The file is basically a concatenation of several host config blocks. Each host +config block starts with @code{Name = ...}. Lines that look like @code{#---#} +are not important, it just makes it easier for humans to read the file. + +The first host config block is always the one representing the invitee. So the +first Name statement determines the name that the invitee will get. From the +first block, the @file{tinc.conf} and @file{hosts/client} files will be +generated; the @code{tinc join} command on the client will automatically +separate statements based on whether they should be in @file{tinc.conf} or in a +host config file. Some statements are special and are treated differently: + +@table @asis +@item Netname = <@var{netname}> +This is a hint to the invitee which netname to use for the VPN. It is used if +the invitee did not already specify a netname, and if there is no pre-existing +configuration with the same netname. + +@cindex Ifconfig +@item Ifconfig = <@var{address}[/@var{netmask}] | dhcp | dhcp6 | slaac> +This is a hint for generating a @file{tinc-up} script. +If an address is specified, a command will be added to @file{tinc-up} so the VPN interface will be configured to have the given address. +If it is the word "dhcp", a command will be added to start a DHCP client on the VPN interface. +If it is the word dhcpv6, it will be a DHCPv6 client. +If it is "slaac", then it will add commands to enable IPv6 stateless address autoconfiguration. +It is also possible to specify a MAC address, in which case a command will be added to set the MAC address of the VPN interface. + +The exact commands added to the @file{tinc-up} script depends on the operating system the client is using. +Multiple Ifconfig statements can be specified, however one should only use one Ifconfig statement per address family. + +@cindex Route +@item Route = <@var{address}[/@var{netmask}]> [<@var{gateway}>] +This is a hint for generating a @file{tinc-up} script. +Route statements are similar to Ifconfig statements, but add routes instead of addresses. +These only allow IPv4 and IPv6 routes. +If no gateway address is specified, the route is directed to the VPN interface. +In general, a gateway is only necessary when running tinc in switch mode. +@end table + +Subsequent host config blocks are copied verbatim into their respective files +in @file{hosts/}. The invitation file generated by @code{tinc invite} will +normally only contain two blocks; one for the client and one for the server. + + +@c ================================================================== +@node Writing an invitation-created script +@section Writing an invitation-created script + +When an invitation is generated, the "invitation-created" script is called (if +it exists) right after the invitation file is written, but before the URL has +been written to stdout. This allows one to change the invitation file +automatically before the invitation URL is passed to the invitee. Here is an +example shell script that aproximately recreates the default invitation file: + +@example +#!/bin/sh + +cat >$INVITATION_FILE <>$INVITATION_FILE +@end example + +You can add more ConnectTo statements, and change `tinc export` to `tinc +export-all` for example. But you can also use the script to automatically hand +out a Subnet to the invitee. Note that the script doesn't have to be a shell script, +you can use any language, it just has to be executable. + + @c ================================================================== @node Technical information @chapter Technical information @@ -3076,7 +3324,7 @@ eavesdroppers cannot get and cannot change any information at all from the packets they can intercept. The encryption algorithm and message authentication algorithm can be changed in the configuration. The length of the message authentication codes is also adjustable. The length of the key for the -encryption algorithm is always the default length used by OpenSSL. +encryption algorithm is always the default length used by LibreSSL/OpenSSL. The SPTPS protocol is described in @ref{Simple Peer-to-Peer Security}. For comparison, this is how SPTPS UDP packets look: @@ -3103,7 +3351,7 @@ this cannot be changed. In August 2000, we discovered the existence of a security hole in all versions of tinc up to and including 1.0pre2. This had to do with the way we exchanged keys. Since then, we have been working on a new authentication scheme to make -tinc as secure as possible. The current version uses the OpenSSL library and +tinc as secure as possible. The current version uses the LibreSSL or OpenSSL library and uses strong authentication with RSA keys. On the 29th of December 2001, Jerome Etienne posted a security analysis of tinc @@ -3278,14 +3526,14 @@ Adding routes to IPv6 subnets: @section Contact information @cindex website -Tinc's website is at @url{http://www.tinc-vpn.org/}, +Tinc's website is at @url{https://www.tinc-vpn.org/}, this server is located in the Netherlands. @cindex IRC We have an IRC channel on the FreeNode and OFTC IRC networks. Connect to -@uref{http://www.freenode.net/, irc.freenode.net} +@uref{https://freenode.net/, irc.freenode.net} or -@uref{http://www.oftc.net/, irc.oftc.net} +@uref{https://www.oftc.net/, irc.oftc.net} and join channel #tinc. diff --git a/doc/tincd.8.in b/doc/tincd.8.in index 3c5886b..22c54a7 100644 --- a/doc/tincd.8.in +++ b/doc/tincd.8.in @@ -8,7 +8,7 @@ .Nd tinc VPN daemon .Sh SYNOPSIS .Nm -.Op Fl cdDKnoLRU +.Op Fl cdDKnsoLRU .Op Fl -config Ns = Ns Ar DIR .Op Fl -no-detach .Op Fl -debug Ns Op = Ns Ar LEVEL @@ -16,6 +16,7 @@ .Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE .Op Fl -mlock .Op Fl -logfile Ns Op = Ns Ar FILE +.Op Fl -syslog .Op Fl -bypass-security .Op Fl -chroot .Op Fl -user Ns = Ns Ar USER @@ -88,6 +89,8 @@ If .Ar FILE is omitted, the default is .Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log. +.It Fl s, -syslog +When this option is is set, tinc uses syslog instead of stderr in --no-detach mode. .It Fl -pidfile Ns = Ns Ar FILENAME Store a cookie in .Ar FILENAME @@ -188,7 +191,7 @@ A lot, especially security auditing. .Sh SEE ALSO .Xr tinc 8 , .Xr tinc.conf 5 , -.Pa http://www.tinc-vpn.org/ , +.Pa https://www.tinc-vpn.org/ , .Pa http://www.cabal.org/ . .Pp The full documentation for tinc is maintained as a Texinfo manual. diff --git a/gui/Makefile.in b/gui/Makefile.in index 772b4ae..2924e05 100644 --- a/gui/Makefile.in +++ b/gui/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,18 +89,18 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = gui -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(dist_bin_SCRIPTS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -144,6 +154,7 @@ am__can_run_installinfo = \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -178,6 +189,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -235,10 +247,12 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ @@ -260,7 +274,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gui/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu gui/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -483,6 +496,8 @@ uninstall-am: uninstall-dist_binSCRIPTS pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_binSCRIPTS +.PRECIOUS: Makefile + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/gui/tinc-gui b/gui/tinc-gui index 0a6370a..65e8b14 100755 --- a/gui/tinc-gui +++ b/gui/tinc-gui @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # tinc-gui -- GUI for controlling a running tincd # Copyright (C) 2009-2014 Guus Sliepen @@ -20,19 +20,19 @@ import string import socket -import wx -import sys import os import platform import time +from argparse import ArgumentParser + +import wx from wx.lib.mixins.listctrl import ColumnSorterMixin from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin if platform.system() == 'Windows': - import _winreg + import _winreg # Classes to interface with a running tinc daemon - REQ_STOP = 0 REQ_RELOAD = 1 REQ_RESTART = 2 @@ -51,272 +51,247 @@ ID = 0 ACK = 4 CONTROL = 18 -class Node: - def parse(self, args): - self.name = args[0] - self.address = args[1] - self.port = args[3] - self.cipher = int(args[4]) - self.digest = int(args[5]) - self.maclength = int(args[6]) - self.compression = int(args[7]) - self.options = int(args[8], 0x10) - self.status = int(args[9], 0x10) - self.nexthop = args[10] - self.via = args[11] - self.distance = int(args[12]) - self.pmtu = int(args[13]) - self.minmtu = int(args[14]) - self.maxmtu = int(args[15]) - self.last_state_change = float(args[16]) - self.subnets = {} +class Node(object): + def __init__(self, args): + self.name = args[0] + self.id = args[1] -class Edge: - def parse(self, args): - self.fr = args[0] - self.to = args[1] - self.address = args[2] - self.port = args[4] - self.options = int(args[-2], 16) - self.weight = int(args[-1]) + self.address = args[2] + self.port = args[4] -class Subnet: - def parse(self, args): - if args[0].find('#') >= 0: - (address, self.weight) = args[0].split('#', 1) - else: - self.weight = 10 - address = args[0] + self.cipher = int(args[5]) + self.digest = int(args[6]) + self.maclength = int(args[7]) - if address.find('/') >= 0: - (self.address, self.prefixlen) = address.split('/', 1) - else: - self.address = address - self.prefixlen = '48' + self.compression = int(args[8]) + self.options = int(args[9], 0x10) + self.status = int(args[10], 0x10) - self.owner = args[1] + self.nexthop = args[11] + self.via = args[12] + self.distance = int(args[13]) + self.pmtu = int(args[14]) + self.minmtu = int(args[15]) + self.maxmtu = int(args[16]) -class Connection: - def parse(self, args): - self.name = args[0] - self.address = args[1] - self.port = args[3] - self.options = int(args[4], 0x10) - self.socket = int(args[5]) - self.status = int(args[6], 0x10) - self.weight = 123 + self.last_state_change = float(args[17]) -class VPN: - confdir = '/etc/tinc' - piddir = '/var/run/' + self.subnets = {} - def connect(self): - # read the pidfile - f = open(self.pidfile) - info = string.split(f.readline()) - f.close() - # check if there is a UNIX socket as well - if self.pidfile.endswith(".pid"): - unixfile = self.pidfile.replace(".pid", ".socket"); - else: - unixfile = self.pidfile + ".socket"; +class Edge(object): + def __init__(self, args): + self.source = args[0] + self.sink = args[1] - if os.path.exists(unixfile): - # use it if it exists - print(unixfile + " exists!"); - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s.connect(unixfile) - else: - # otherwise connect via TCP - print(unixfile + " does not exist."); - if ':' in info[2]: - af = socket.AF_INET6 - else: - af = socket.AF_INET - s = socket.socket(af, socket.SOCK_STREAM) - s.connect((info[2], int(info[4]))) + self.address = args[2] + self.port = args[4] - self.sf = s.makefile() - s.close() - hello = string.split(self.sf.readline()) - self.name = hello[1] - self.sf.write('0 ^' + info[1] + ' 17\r\n') - self.sf.flush() - resp = string.split(self.sf.readline()) - self.port = info[4] - self.nodes = {} - self.edges = {} - self.subnets = {} - self.connections = {} - self.refresh() + self.options = int(args[-2], 16) + self.weight = int(args[-1]) - def refresh(self): - self.sf.write('18 3\r\n18 4\r\n18 5\r\n18 6\r\n') - self.sf.flush() - for node in self.nodes.values(): - node.visited = False - for edge in self.edges.values(): - edge.visited = False - for subnet in self.subnets.values(): - subnet.visited = False - for connections in self.connections.values(): - connections.visited = False +class Subnet(object): + def __init__(self, args): + if args[0].find('#') >= 0: + address, self.weight = args[0].split('#', 1) + else: + self.weight = 10 + address = args[0] - while True: - resp = string.split(self.sf.readline()) - if len(resp) < 2: - break - if resp[0] != '18': - break - if resp[1] == '3': - if len(resp) < 19: - continue - node = self.nodes.get(resp[2]) or Node() - node.parse(resp[2:]) - node.visited = True - self.nodes[resp[2]] = node - elif resp[1] == '4': - if len(resp) < 9: - continue - edge = self.nodes.get((resp[2], resp[3])) or Edge() - edge.parse(resp[2:]) - edge.visited = True - self.edges[(resp[2], resp[3])] = edge - elif resp[1] == '5': - if len(resp) < 4: - continue - subnet = self.subnets.get((resp[2], resp[3])) or Subnet() - subnet.parse(resp[2:]) - subnet.visited = True - self.subnets[(resp[2], resp[3])] = subnet - if subnet.owner == "(broadcast)": - continue - self.nodes[subnet.owner].subnets[resp[2]] = subnet - elif resp[1] == '6': - if len(resp) < 9: - break - connection = self.connections.get((resp[2], resp[3], resp[5])) or Connection() - connection.parse(resp[2:]) - connection.visited = True - self.connections[(resp[2], resp[3], resp[5])] = connection - else: - break + if address.find('/') >= 0: + self.address, self.prefixlen = address.split('/', 1) + else: + self.address = address + self.prefixlen = '48' - for key, subnet in self.subnets.items(): - if not subnet.visited: - del self.subnets[key] + self.owner = args[1] - for key, edge in self.edges.items(): - if not edge.visited: - del self.edges[key] - for key, node in self.nodes.items(): - if not node.visited: - del self.nodes[key] - else: - for key, subnet in node.subnets.items(): - if not subnet.visited: - del node.subnets[key] +class Connection(object): + def __init__(self, args): + self.name = args[0] - for key, connection in self.connections.items(): - if not connection.visited: - del self.connections[key] + self.address = args[1] + self.port = args[3] - def close(self): - self.sf.close() + self.options = int(args[4], 0x10) + self.socket = int(args[5]) + self.status = int(args[6], 0x10) - def disconnect(self, name): - self.sf.write('18 12 ' + name + '\r\n') - self.sf.flush() - resp = string.split(self.sf.readline()) + self.weight = 'n/a' - def debug(self, level = -1): - self.sf.write('18 9 ' + str(level) + '\r\n') - self.sf.flush() - resp = string.split(self.sf.readline()) - return int(resp[2]) - def __init__(self, netname = None, pidfile = None): - if platform.system() == 'Windows': - sam = _winreg.KEY_READ - if platform.machine().endswith('64'): - sam = sam | _winreg.KEY_WOW64_64KEY - try: - reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - try: - key = _winreg.OpenKey(reg, "SOFTWARE\\tinc", 0, sam) - except WindowsError: - key = _winreg.OpenKey(reg, "SOFTWARE\\Wow6432Node\\tinc", 0, sam) - VPN.confdir = _winreg.QueryValue(key, None) - except WindowsError: - pass +class VPN(object): + def __init__(self, netname=None, pidfile=None, confdir='/etc/tinc', piddir='/run'): + if platform.system() == 'Windows': + sam = _winreg.KEY_READ + if platform.machine().endswith('64'): + sam = sam | _winreg.KEY_WOW64_64KEY + try: + reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + try: + key = _winreg.OpenKey(reg, "SOFTWARE\\tinc", 0, sam) + except WindowsError: + key = _winreg.OpenKey(reg, "SOFTWARE\\Wow6432Node\\tinc", 0, sam) + confdir = _winreg.QueryValue(key, None) + except WindowsError: + pass - if netname: - self.netname = netname - self.confbase = os.path.join(VPN.confdir, netname) - else: - self.confbase = VPN.confdir + if netname: + self.netname = netname + self.confbase = os.path.join(confdir, netname) + else: + self.confbase = confdir - self.tincconf = os.path.join(self.confbase, 'tinc.conf') + self.tincconf = os.path.join(self.confbase, 'tinc.conf') - if pidfile != None: - self.pidfile = pidfile - else: - if platform.system() == 'Windows': - self.pidfile = os.path.join(self.confbase, 'pid') - else: - if netname: - self.pidfile = os.path.join(VPN.piddir, 'tinc.' + netname + '.pid') - else: - self.pidfile = os.path.join(VPN.piddir, 'tinc.pid') + if pidfile is not None: + self.pidfile = pidfile + else: + if platform.system() == 'Windows': + self.pidfile = os.path.join(self.confbase, 'pid') + else: + if netname: + self.pidfile = os.path.join(piddir, 'tinc.' + netname + '.pid') + else: + self.pidfile = os.path.join(piddir, 'tinc.pid') -# GUI starts here + self.sf = None + self.name = None + self.port = None + self.nodes = {} + self.edges = {} + self.subnets = {} + self.connections = {} -argv0 = sys.argv[0] -del sys.argv[0] -netname = None -pidfile = None + def connect(self): + # read the pidfile + f = open(self.pidfile) + info = string.split(f.readline()) + f.close() -def usage(exitcode = 0): - print('Usage: ' + argv0 + ' [options]') - print('\nValid options are:') - print(' -n, --net=NETNAME Connect to net NETNAME.') - print(' --pidfile=FILENAME Read control cookie from FILENAME.') - print(' --help Display this help and exit.') - print('\nReport bugs to tinc@tinc-vpn.org.') - sys.exit(exitcode) + # check if there is a UNIX socket as well + if self.pidfile.endswith('.pid'): + unixfile = self.pidfile.replace('.pid', '.socket'); + else: + unixfile = self.pidfile + '.socket'; -while sys.argv: - if sys.argv[0] in ('-n', '--net'): - del sys.argv[0] - netname = sys.argv[0] - elif sys.argv[0] in ('--pidfile'): - del sys.argv[0] - pidfile = sys.argv[0] - elif sys.argv[0] in ('--help'): - usage(0) - else: - print(argv0 + ': unrecognized option \'' + sys.argv[0] + '\'') - usage(1) + if os.path.exists(unixfile): + # use it if it exists + print(unixfile + " exists!"); + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(unixfile) + else: + # otherwise connect via TCP + print(unixfile + " does not exist."); + if ':' in info[2]: + af = socket.AF_INET6 + else: + af = socket.AF_INET + s = socket.socket(af, socket.SOCK_STREAM) + s.connect((info[2], int(info[4]))) - del sys.argv[0] + self.sf = s.makefile() + s.close() + hello = string.split(self.sf.readline()) + self.name = hello[1] + self.sf.write('0 ^' + info[1] + ' 17\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + self.port = info[4] + self.refresh() -if netname == None: - netname = os.getenv("NETNAME") + def refresh(self): + for request in (REQ_DUMP_NODES, REQ_DUMP_EDGES, REQ_DUMP_SUBNETS, REQ_DUMP_CONNECTIONS): + self.sf.write('{} {}\r\n'.format(CONTROL, request)) + self.sf.flush() -if netname == ".": - netname = None + for node in self.nodes.values(): + node.visited = False + for edge in self.edges.values(): + edge.visited = False + for subnet in self.subnets.values(): + subnet.visited = False + for connections in self.connections.values(): + connections.visited = False + + while True: + resp = string.split(self.sf.readline()) + if len(resp) < 2: + break + if resp[0] != '18': + break + if resp[1] == '3': + if len(resp) < 19: + continue + node = self.nodes.get(resp[2]) or Node(resp[2:]) + node.visited = True + self.nodes[resp[2]] = node + elif resp[1] == '4': + if len(resp) < 9: + continue + edge = self.nodes.get((resp[2], resp[3])) or Edge(resp[2:]) + edge.visited = True + self.edges[(resp[2], resp[3])] = edge + elif resp[1] == '5': + if len(resp) < 4: + continue + subnet = self.subnets.get((resp[2], resp[3])) or Subnet(resp[2:]) + subnet.visited = True + self.subnets[(resp[2], resp[3])] = subnet + if subnet.owner == "(broadcast)": + continue + self.nodes[subnet.owner].subnets[resp[2]] = subnet + elif resp[1] == '6': + if len(resp) < 9: + break + connection = self.connections.get((resp[2], resp[3], resp[5])) or Connection(resp[2:]) + connection.visited = True + self.connections[(resp[2], resp[3], resp[5])] = connection + else: + break + + for key, subnet in self.subnets.items(): + if not subnet.visited: + del self.subnets[key] + + for key, edge in self.edges.items(): + if not edge.visited: + del self.edges[key] + + for key, node in self.nodes.items(): + if not node.visited: + del self.nodes[key] + else: + for key, subnet in node.subnets.items(): + if not subnet.visited: + del node.subnets[key] + + for key, connection in self.connections.items(): + if not connection.visited: + del self.connections[key] + + def close(self): + self.sf.close() + + def disconnect(self, name): + self.sf.write('18 12 ' + name + '\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + + def debug(self, level=-1): + self.sf.write('18 9 ' + str(level) + '\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + return int(resp[2]) -vpn = VPN(netname, pidfile) -vpn.connect() class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin): def __init__(self, parent, style): wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES) - ListCtrlAutoWidthMixin.__init__(self) + ListCtrlAutoWidthMixin.__init__(self) ColumnSorterMixin.__init__(self, 16) def GetListCtrl(self): @@ -324,299 +299,336 @@ class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin): class SettingsPage(wx.Panel): - def OnDebugLevel(self, event): - vpn.debug(self.debug.GetValue()) + def on_debug_level(self, event): + vpn.debug(self.debug.GetValue()) - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) - grid = wx.FlexGridSizer(cols = 2) - grid.AddGrowableCol(1, 1) + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + grid = wx.FlexGridSizer(cols=2) + grid.AddGrowableCol(1, 1) - namelabel = wx.StaticText(self, -1, 'Name:') - self.name = wx.TextCtrl(self, -1, vpn.name) - grid.Add(namelabel) - grid.Add(self.name, 1, wx.EXPAND) + namelabel = wx.StaticText(self, -1, 'Name:') + self.name = wx.TextCtrl(self, -1, vpn.name) + grid.Add(namelabel) + grid.Add(self.name, 1, wx.EXPAND) - portlabel = wx.StaticText(self, -1, 'Port:') - self.port = wx.TextCtrl(self, -1, vpn.port) - grid.Add(portlabel) - grid.Add(self.port) + portlabel = wx.StaticText(self, -1, 'Port:') + self.port = wx.TextCtrl(self, -1, vpn.port) + grid.Add(portlabel) + grid.Add(self.port) - debuglabel = wx.StaticText(self, -1, 'Debug level:') - self.debug = wx.SpinCtrl(self, min = 0, max = 5, initial = vpn.debug()) - self.debug.Bind(wx.EVT_SPINCTRL, self.OnDebugLevel) - grid.Add(debuglabel) - grid.Add(self.debug) + debuglabel = wx.StaticText(self, -1, 'Debug level:') + self.debug = wx.SpinCtrl(self, min=0, max=5, initial=vpn.debug()) + self.debug.Bind(wx.EVT_SPINCTRL, self.on_debug_level) + grid.Add(debuglabel) + grid.Add(self.debug) - modelabel = wx.StaticText(self, -1, 'Mode:') - self.mode = wx.ComboBox(self, -1, style = wx.CB_READONLY, value = 'Router', choices = ['Router', 'Switch', 'Hub']) - grid.Add(modelabel) - grid.Add(self.mode) + modelabel = wx.StaticText(self, -1, 'Mode:') + self.mode = wx.ComboBox(self, -1, style=wx.CB_READONLY, value='Router', choices=['Router', 'Switch', 'Hub']) + grid.Add(modelabel) + grid.Add(self.mode) + + self.SetSizer(grid) - self.SetSizer(grid) class ConnectionsPage(wx.Panel): - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) - self.list = SuperListCtrl(self, id) - self.list.InsertColumn(0, 'Name') - self.list.InsertColumn(1, 'Address') - self.list.InsertColumn(2, 'Port') - self.list.InsertColumn(3, 'Options') - self.list.InsertColumn(4, 'Weight') + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + self.list = SuperListCtrl(self, id) + self.list.InsertColumn(0, 'Name') + self.list.InsertColumn(1, 'Address') + self.list.InsertColumn(2, 'Port') + self.list.InsertColumn(3, 'Options') + self.list.InsertColumn(4, 'Weight') - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add(self.list, 1, wx.EXPAND) - self.SetSizer(hbox) - self.refresh() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(self.list, 1, wx.EXPAND) + self.SetSizer(hbox) + self.refresh() - class ContextMenu(wx.Menu): - def __init__(self, item): - wx.Menu.__init__(self) + class ContextMenu(wx.Menu): + def __init__(self, item): + wx.Menu.__init__(self) - self.item = item + self.item = item - disconnect = wx.MenuItem(self, -1, 'Disconnect') - self.AppendItem(disconnect) - self.Bind(wx.EVT_MENU, self.OnDisconnect, id=disconnect.GetId()) + disconnect = wx.MenuItem(self, -1, 'Disconnect') + self.AppendItem(disconnect) + self.Bind(wx.EVT_MENU, self.on_disconnect, id=disconnect.GetId()) - def OnDisconnect(self, event): - vpn.disconnect(self.item[0]) + def on_disconnect(self, event): + vpn.disconnect(self.item[0]) - def OnContext(self, event): - i = event.GetIndex() - self.PopupMenu(self.ContextMenu(self.list.itemDataMap[event.GetIndex()]), event.GetPosition()) + def on_context(self, event): + idx = event.GetIndex() + self.PopupMenu(self.ContextMenu(self.list.itemDataMap[event.GetIndex()]), event.GetPosition()) - def refresh(self): - sortstate = self.list.GetSortState() - self.list.itemDataMap = {} - i = 0 + def refresh(self): + sortstate = self.list.GetSortState() + self.list.itemDataMap = {} + i = 0 - for key, connection in vpn.connections.items(): - if self.list.GetItemCount() <= i: - self.list.InsertStringItem(i, connection.name) - else: - self.list.SetStringItem(i, 0, connection.name) - self.list.SetStringItem(i, 1, connection.address) - self.list.SetStringItem(i, 2, connection.port) - self.list.SetStringItem(i, 3, str(connection.options)) - self.list.SetStringItem(i, 4, str(connection.weight)) - self.list.itemDataMap[i] = (connection.name, connection.address, connection.port, connection.options, connection.weight) - self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContext) - self.list.SetItemData(i, i) - i += 1 + for key, connection in vpn.connections.items(): + if self.list.GetItemCount() <= i: + self.list.InsertStringItem(i, connection.name) + else: + self.list.SetStringItem(i, 0, connection.name) + self.list.SetStringItem(i, 1, connection.address) + self.list.SetStringItem(i, 2, connection.port) + self.list.SetStringItem(i, 3, str(connection.options)) + self.list.SetStringItem(i, 4, str(connection.weight)) + self.list.itemDataMap[i] = (connection.name, connection.address, connection.port, connection.options, + connection.weight) + self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_context) + self.list.SetItemData(i, i) + i += 1 - while self.list.GetItemCount() > i: - self.list.DeleteItem(self.list.GetItemCount() - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) + + self.list.SortListItems(sortstate[0], sortstate[1]) - self.list.SortListItems(sortstate[0], sortstate[1]) class NodesPage(wx.Panel): - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) - self.list = SuperListCtrl(self, id) - self.list.InsertColumn( 0, 'Name') - self.list.InsertColumn( 1, 'Address') - self.list.InsertColumn( 2, 'Port') - self.list.InsertColumn( 3, 'Cipher') - self.list.InsertColumn( 4, 'Digest') - self.list.InsertColumn( 5, 'MACLength') - self.list.InsertColumn( 6, 'Compression') - self.list.InsertColumn( 7, 'Options') - self.list.InsertColumn( 8, 'Status') - self.list.InsertColumn( 9, 'Nexthop') - self.list.InsertColumn(10, 'Via') - self.list.InsertColumn(11, 'Distance') - self.list.InsertColumn(12, 'PMTU') - self.list.InsertColumn(13, 'Min MTU') - self.list.InsertColumn(14, 'Max MTU') - self.list.InsertColumn(15, 'Since') + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + self.list = SuperListCtrl(self, id) + self.list.InsertColumn(0, 'Name') + self.list.InsertColumn(1, 'Address') + self.list.InsertColumn(2, 'Port') + self.list.InsertColumn(3, 'Cipher') + self.list.InsertColumn(4, 'Digest') + self.list.InsertColumn(5, 'MACLength') + self.list.InsertColumn(6, 'Compression') + self.list.InsertColumn(7, 'Options') + self.list.InsertColumn(8, 'Status') + self.list.InsertColumn(9, 'Nexthop') + self.list.InsertColumn(10, 'Via') + self.list.InsertColumn(11, 'Distance') + self.list.InsertColumn(12, 'PMTU') + self.list.InsertColumn(13, 'Min MTU') + self.list.InsertColumn(14, 'Max MTU') + self.list.InsertColumn(15, 'Since') - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add(self.list, 1, wx.EXPAND) - self.SetSizer(hbox) - self.refresh() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(self.list, 1, wx.EXPAND) + self.SetSizer(hbox) + self.refresh() - def refresh(self): - sortstate = self.list.GetSortState() - self.list.itemDataMap = {} - i = 0 + def refresh(self): + sortstate = self.list.GetSortState() + self.list.itemDataMap = {} + i = 0 - for key, node in vpn.nodes.items(): - if self.list.GetItemCount() <= i: - self.list.InsertStringItem(i, node.name) - else: - self.list.SetStringItem(i, 0, node.name) - self.list.SetStringItem(i, 1, node.address) - self.list.SetStringItem(i, 2, node.port) - self.list.SetStringItem(i, 3, str(node.cipher)) - self.list.SetStringItem(i, 4, str(node.digest)) - self.list.SetStringItem(i, 5, str(node.maclength)) - self.list.SetStringItem(i, 6, str(node.compression)) - self.list.SetStringItem(i, 7, format(node.options, "x")) - self.list.SetStringItem(i, 8, format(node.status, "04x")) - self.list.SetStringItem(i, 9, node.nexthop) - self.list.SetStringItem(i, 10, node.via) - self.list.SetStringItem(i, 11, str(node.distance)) - self.list.SetStringItem(i, 12, str(node.pmtu)) - self.list.SetStringItem(i, 13, str(node.minmtu)) - self.list.SetStringItem(i, 14, str(node.maxmtu)) - if node.last_state_change: - since = time.strftime("%Y-%m-%d %H:%M", time.localtime(node.last_state_change)) - else: - since = "never" - self.list.SetStringItem(i, 15, since) - self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu, since) - self.list.SetItemData(i, i) - i += 1 + for key, node in vpn.nodes.items(): + if self.list.GetItemCount() <= i: + self.list.InsertStringItem(i, node.name) + else: + self.list.SetStringItem(i, 0, node.name) + self.list.SetStringItem(i, 1, node.address) + self.list.SetStringItem(i, 2, node.port) + self.list.SetStringItem(i, 3, str(node.cipher)) + self.list.SetStringItem(i, 4, str(node.digest)) + self.list.SetStringItem(i, 5, str(node.maclength)) + self.list.SetStringItem(i, 6, str(node.compression)) + self.list.SetStringItem(i, 7, format(node.options, "x")) + self.list.SetStringItem(i, 8, format(node.status, "04x")) + self.list.SetStringItem(i, 9, node.nexthop) + self.list.SetStringItem(i, 10, node.via) + self.list.SetStringItem(i, 11, str(node.distance)) + self.list.SetStringItem(i, 12, str(node.pmtu)) + self.list.SetStringItem(i, 13, str(node.minmtu)) + self.list.SetStringItem(i, 14, str(node.maxmtu)) + if node.last_state_change: + since = time.strftime("%Y-%m-%d %H:%M", time.localtime(node.last_state_change)) + else: + since = "never" + self.list.SetStringItem(i, 15, since) + self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, + node.compression, node.options, node.status, node.nexthop, node.via, + node.distance, node.pmtu, node.minmtu, node.maxmtu, since) + self.list.SetItemData(i, i) + i += 1 - while self.list.GetItemCount() > i: - self.list.DeleteItem(self.list.GetItemCount() - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) + + self.list.SortListItems(sortstate[0], sortstate[1]) - self.list.SortListItems(sortstate[0], sortstate[1]) class EdgesPage(wx.Panel): - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) - self.list = SuperListCtrl(self, id) - self.list.InsertColumn(0, 'From') - self.list.InsertColumn(1, 'To') - self.list.InsertColumn(2, 'Address') - self.list.InsertColumn(3, 'Port') - self.list.InsertColumn(4, 'Options') - self.list.InsertColumn(5, 'Weight') + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + self.list = SuperListCtrl(self, id) + self.list.InsertColumn(0, 'From') + self.list.InsertColumn(1, 'To') + self.list.InsertColumn(2, 'Address') + self.list.InsertColumn(3, 'Port') + self.list.InsertColumn(4, 'Options') + self.list.InsertColumn(5, 'Weight') - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add(self.list, 1, wx.EXPAND) - self.SetSizer(hbox) - self.refresh() + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(self.list, 1, wx.EXPAND) + self.SetSizer(hbox) + self.refresh() - def refresh(self): - sortstate = self.list.GetSortState() - self.list.itemDataMap = {} - i = 0 + def refresh(self): + sortstate = self.list.GetSortState() + self.list.itemDataMap = {} + i = 0 - for key, edge in vpn.edges.items(): - if self.list.GetItemCount() <= i: - self.list.InsertStringItem(i, edge.fr) - else: - self.list.SetStringItem(i, 0, edge.fr) - self.list.SetStringItem(i, 1, edge.to) - self.list.SetStringItem(i, 2, edge.address) - self.list.SetStringItem(i, 3, edge.port) - self.list.SetStringItem(i, 4, format(edge.options, "x")) - self.list.SetStringItem(i, 5, str(edge.weight)) - self.list.itemDataMap[i] = (edge.fr, edge.to, edge.address, edge.port, edge.options, edge.weight) - self.list.SetItemData(i, i) - i += 1 + for key, edge in vpn.edges.items(): + if self.list.GetItemCount() <= i: + self.list.InsertStringItem(i, edge.source) + else: + self.list.SetStringItem(i, 0, edge.source) + self.list.SetStringItem(i, 1, edge.sink) + self.list.SetStringItem(i, 2, edge.address) + self.list.SetStringItem(i, 3, edge.port) + self.list.SetStringItem(i, 4, format(edge.options, "x")) + self.list.SetStringItem(i, 5, str(edge.weight)) + self.list.itemDataMap[i] = (edge.source, edge.sink, edge.address, edge.port, edge.options, edge.weight) + self.list.SetItemData(i, i) + i += 1 - while self.list.GetItemCount() > i: - self.list.DeleteItem(self.list.GetItemCount() - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) + + self.list.SortListItems(sortstate[0], sortstate[1]) - self.list.SortListItems(sortstate[0], sortstate[1]) class SubnetsPage(wx.Panel): - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) - self.list = SuperListCtrl(self, id) - self.list.InsertColumn(0, 'Subnet', wx.LIST_FORMAT_RIGHT) - self.list.InsertColumn(1, 'Weight', wx.LIST_FORMAT_RIGHT) - self.list.InsertColumn(2, 'Owner') - hbox = wx.BoxSizer(wx.HORIZONTAL) - hbox.Add(self.list, 1, wx.EXPAND) - self.SetSizer(hbox) - self.refresh() + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + self.list = SuperListCtrl(self, id) + self.list.InsertColumn(0, 'Subnet', wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(1, 'Weight', wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(2, 'Owner') + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(self.list, 1, wx.EXPAND) + self.SetSizer(hbox) + self.refresh() - def refresh(self): - sortstate = self.list.GetSortState() - self.list.itemDataMap = {} - i = 0 + def refresh(self): + sortstate = self.list.GetSortState() + self.list.itemDataMap = {} + i = 0 - for key, subnet in vpn.subnets.items(): - if self.list.GetItemCount() <= i: - self.list.InsertStringItem(i, subnet.address + '/' + subnet.prefixlen) - else: - self.list.SetStringItem(i, 0, subnet.address + '/' + subnet.prefixlen) - self.list.SetStringItem(i, 1, str(subnet.weight)) - self.list.SetStringItem(i, 2, subnet.owner) - self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner) - self.list.SetItemData(i, i) - i += 1 + for key, subnet in vpn.subnets.items(): + if self.list.GetItemCount() <= i: + self.list.InsertStringItem(i, subnet.address + '/' + subnet.prefixlen) + else: + self.list.SetStringItem(i, 0, subnet.address + '/' + subnet.prefixlen) + self.list.SetStringItem(i, 1, str(subnet.weight)) + self.list.SetStringItem(i, 2, subnet.owner) + self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner) + self.list.SetItemData(i, i) + i += 1 - while self.list.GetItemCount() > i: - self.list.DeleteItem(self.list.GetItemCount() - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) + + self.list.SortListItems(sortstate[0], sortstate[1]) - self.list.SortListItems(sortstate[0], sortstate[1]) class StatusPage(wx.Panel): - def __init__(self, parent, id): - wx.Panel.__init__(self, parent, id) + def __init__(self, parent, id): + wx.Panel.__init__(self, parent, id) + class GraphPage(wx.Window): - def __init__(self, parent, id): - wx.Window.__init__(self, parent, id) + def __init__(self, parent, id): + wx.Window.__init__(self, parent, id) + class NetPage(wx.Notebook): - def __init__(self, parent, id): - wx.Notebook.__init__(self, parent) - self.settings = SettingsPage(self, id) - self.connections = ConnectionsPage(self, id) - self.nodes = NodesPage(self, id) - self.edges = EdgesPage(self, id) - self.subnets = SubnetsPage(self, id) - self.graph = GraphPage(self, id) - self.status = StatusPage(self, id) + def __init__(self, parent, id): + wx.Notebook.__init__(self, parent) + self.settings = SettingsPage(self, id) + self.connections = ConnectionsPage(self, id) + self.nodes = NodesPage(self, id) + self.edges = EdgesPage(self, id) + self.subnets = SubnetsPage(self, id) + self.graph = GraphPage(self, id) + self.status = StatusPage(self, id) + + self.AddPage(self.settings, 'Settings') + # self.AddPage(self.status, 'Status') + self.AddPage(self.connections, 'Connections') + self.AddPage(self.nodes, 'Nodes') + self.AddPage(self.edges, 'Edges') + self.AddPage(self.subnets, 'Subnets') + + # self.AddPage(self.graph, 'Graph') - self.AddPage(self.settings, 'Settings') - #self.AddPage(self.status, 'Status') - self.AddPage(self.connections, 'Connections') - self.AddPage(self.nodes, 'Nodes') - self.AddPage(self.edges, 'Edges') - self.AddPage(self.subnets, 'Subnets') - #self.AddPage(self.graph, 'Graph') - class MainWindow(wx.Frame): - def OnQuit(self, event): - app.ExitMainLoop() + def __init__(self, parent, id, title): + wx.Frame.__init__(self, parent, id, title) - def OnTimer(self, event): - vpn.refresh() - self.np.nodes.refresh() - self.np.subnets.refresh() - self.np.edges.refresh() - self.np.connections.refresh() + menubar = wx.MenuBar() - def __init__(self, parent, id, title): - wx.Frame.__init__(self, parent, id, title) + menu = wx.Menu() + menu.Append(1, '&Quit\tCtrl-X', 'Quit tinc GUI') + menubar.Append(menu, '&File') - menubar = wx.MenuBar() - file = wx.Menu() - file.Append(1, '&Quit\tCtrl-X', 'Quit tinc GUI') - menubar.Append(file, '&File') + # nb = wx.Notebook(self, -1) + # nb.SetPadding((0, 0)) + self.np = NetPage(self, -1) + # nb.AddPage(np, 'VPN') - #nb = wx.Notebook(self, -1) - #nb.SetPadding((0, 0)) - self.np = NetPage(self, -1) - #nb.AddPage(np, 'VPN') - - self.timer = wx.Timer(self, -1) - self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) - self.timer.Start(1000) - self.Bind(wx.EVT_MENU, self.OnQuit, id=1) - self.SetMenuBar(menubar) - self.Show() + self.timer = wx.Timer(self, -1) + self.Bind(wx.EVT_TIMER, self.on_timer, self.timer) + self.timer.Start(1000) + self.Bind(wx.EVT_MENU, self.on_quit, id=1) + self.SetMenuBar(menubar) + self.Show() -app = wx.App() -mw = MainWindow(None, -1, 'Tinc GUI') + def on_quit(self, event): + app.ExitMainLoop() -#def OnTaskBarIcon(event): -# mw.Raise() -# -#icon = wx.Icon("tincgui.ico", wx.BITMAP_TYPE_PNG) -#taskbaricon = wx.TaskBarIcon() -#taskbaricon.SetIcon(icon, 'Tinc GUI') -#wx.EVT_TASKBAR_RIGHT_UP(taskbaricon, OnTaskBarIcon) + def on_timer(self, event): + vpn.refresh() + self.np.nodes.refresh() + self.np.subnets.refresh() + self.np.edges.refresh() + self.np.connections.refresh() -app.MainLoop() -vpn.close() + +def main(netname, pidfile): + global vpn, app + + if netname is None: + netname = os.getenv('NETNAME') + + vpn = VPN(netname, pidfile) + vpn.connect() + + app = wx.App() + mw = MainWindow(None, -1, 'Tinc GUI') + + """ + def OnTaskBarIcon(event): + mw.Raise() + """ + + """ + icon = wx.Icon("tincgui.ico", wx.BITMAP_TYPE_PNG) + taskbaricon = wx.TaskBarIcon() + taskbaricon.SetIcon(icon, 'Tinc GUI') + wx.EVT_TASKBAR_RIGHT_UP(taskbaricon, OnTaskBarIcon) + """ + + app.MainLoop() + vpn.close() + + +if __name__ == '__main__': + argparser = ArgumentParser(epilog='Report bugs to tinc@tinc-vpn.org.') + + argparser.add_argument('-n', '--net', metavar='NETNAME', dest='netname', help='Connect to net NETNAME') + argparser.add_argument('-p', '--pidfile', help='Path to the pid file (containing the controlcookie)') + + options = argparser.parse_args() + + main(options.netname, options.pidfile) diff --git a/install-sh b/install-sh index 377bb86..59990a1 100755 --- a/install-sh +++ b/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-11-20.07; # UTC +scriptversion=2014-09-12.12; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC # This script is compatible with the BSD install script, but was written # from scratch. +tab=' ' nl=' ' -IFS=" "" $nl" +IFS=" $tab$nl" -# set DOITPROG to echo to test this script +# Set DOITPROG to "echo" to test this script. -# Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi +doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. @@ -68,17 +64,6 @@ mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - posix_mkdir= # Desired mode of installed file. @@ -97,7 +82,7 @@ dir_arg= dst_arg= copy_on_change=false -no_target_directory= +is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE @@ -137,46 +122,57 @@ while test $# -ne 0; do -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift;; + shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift;; + shift;; -s) stripcmd=$stripprog;; - -t) dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; - -T) no_target_directory=true;; + -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; - --) shift - break;; + --) shift + break;; - -*) echo "$0: invalid option: $1" >&2 - exit 1;; + -*) echo "$0: invalid option: $1" >&2 + exit 1;; *) break;; esac shift done +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. @@ -207,6 +203,15 @@ if test $# -eq 0; then exit 0 fi +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 @@ -223,16 +228,16 @@ if test -z "$dir_arg"; then *[0-7]) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw='% 200' + u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw=,u+rw + u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac @@ -269,41 +274,15 @@ do # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - + dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi @@ -314,74 +293,81 @@ do if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + # $RANDOM is not portable (e.g. dash); use it when possible to + # lower collision chance + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; + # As "mkdir -p" follows symlinks and we work in /tmp possibly; so + # create the $tmpdir first (and fail if unsuccessful) to make sure + # that nobody tries to guess the $tmpdir name. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac;; esac if $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else @@ -391,53 +377,51 @@ do # directory the slow way, step by step, checking for races as we go. case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; esac - eval "$initialize_posix_glob" - oIFS=$IFS IFS=/ - $posix_glob set -f + set -f set fnord $dstdir shift - $posix_glob set +f + set +f IFS=$oIFS prefixes= for d do - test X"$d" = X && continue + test X"$d" = X && continue - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ done if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi fi fi @@ -472,15 +456,12 @@ do # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - + set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then @@ -493,24 +474,24 @@ do # to itself, or perhaps because mv is so ancient that it does not # support -f. { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 diff --git a/m4/Makefile.am b/m4/Makefile.am deleted file mode 100644 index 0f58aef..0000000 --- a/m4/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -## Process this file with automake to produce Makefile.in -*-Makefile-*- - -EXTRA_DIST = README *.m4 - diff --git a/m4/README b/m4/README deleted file mode 100644 index df032df..0000000 --- a/m4/README +++ /dev/null @@ -1,8 +0,0 @@ -These files are used by a program called aclocal (part of the GNU automake -package). aclocal uses these files to create aclocal.m4 which is in turn -used by autoconf to create the configure script at the the top level in -this distribution. - -The Makefile.am file in this directory is automatically generated -from the template file, Makefile.am.in. The generation will fail -if you don't have all the right tools. diff --git a/m4/attribute.m4 b/m4/attribute.m4 index 6a8f555..9d673e9 100644 --- a/m4/attribute.m4 +++ b/m4/attribute.m4 @@ -9,8 +9,8 @@ AC_DEFUN([tinc_ATTRIBUTE], CFLAGS="$CFLAGS -Wall -Werror" AC_COMPILE_IFELSE( [AC_LANG_SOURCE( - [void test(void) __attribute__ (($1)); - void test(void) { return; } + [void *test(void) __attribute__ (($1)); + void *test(void) { return (void *)0; } ], )], [tinc_cv_attribute_$1=yes], diff --git a/m4/miniupnpc.m4 b/m4/miniupnpc.m4 new file mode 100644 index 0000000..c2aca29 --- /dev/null +++ b/m4/miniupnpc.m4 @@ -0,0 +1,40 @@ +dnl Check to find the miniupnpc headers/libraries + +AC_DEFUN([tinc_MINIUPNPC], +[ + AC_ARG_ENABLE([miniupnpc], + AS_HELP_STRING([--enable-miniupnpc], [enable miniupnpc support])) + AS_IF([test "x$enable_miniupnpc" = "xyes"], [ + AC_DEFINE(HAVE_MINIUPNPC, 1, [have miniupnpc support]) + AC_ARG_WITH(miniupnpc, + AS_HELP_STRING([--with-miniupnpc=DIR], [miniupnpc base directory, or:]), + [miniupnpc="$withval" + CPPFLAGS="$CPPFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib"] + ) + + AC_ARG_WITH(miniupnpc-include, + AS_HELP_STRING([--with-miniupnpc-include=DIR], [miniupnpc headers directory]), + [miniupnpc_include="$withval" + CPPFLAGS="$CPPFLAGS -I$withval"] + ) + + AC_ARG_WITH(miniupnpc-lib, + AS_HELP_STRING([--with-miniupnpc-lib=DIR], [miniupnpc library directory]), + [miniupnpc_lib="$withval" + LDFLAGS="$LDFLAGS -L$withval"] + ) + + AC_CHECK_HEADERS(miniupnpc/miniupnpc.h, + [], + [AC_MSG_ERROR("miniupnpc header files not found."); break] + ) + + AC_CHECK_LIB(miniupnpc, upnpDiscover, + [MINIUPNPC_LIBS="$LIBS -lminiupnpc"], + [AC_MSG_ERROR("miniupnpc libraries not found.")] + ) + ]) + + AC_SUBST(MINIUPNPC_LIBS) +]) diff --git a/m4/openssl.m4 b/m4/openssl.m4 index 738c68c..26cbcbe 100644 --- a/m4/openssl.m4 +++ b/m4/openssl.m4 @@ -1,4 +1,4 @@ -dnl Check to find the OpenSSL headers/libraries +dnl Check to find the LibreSSL/OpenSSL headers/libraries AC_DEFUN([tinc_OPENSSL], [ @@ -10,47 +10,47 @@ AC_DEFUN([tinc_OPENSSL], [], [AC_CHECK_LIB(dl, dlopen, [LIBS="$LIBS -ldl"], - [AC_MSG_ERROR([OpenSSL depends on libdl.]); break] + [AC_MSG_ERROR([LibreSSL/OpenSSL depends on libdl.]); break] )] ) ;; esac AC_ARG_WITH(openssl, - AS_HELP_STRING([--with-openssl=DIR], [OpenSSL base directory, or:]), + AS_HELP_STRING([--with-openssl=DIR], [LibreSSL/OpenSSL base directory, or:]), [openssl="$withval" CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib"] ) AC_ARG_WITH(openssl-include, - AS_HELP_STRING([--with-openssl-include=DIR], [OpenSSL headers directory (without trailing /openssl)]), + AS_HELP_STRING([--with-openssl-include=DIR], [LibreSSL/OpenSSL headers directory (without trailing /openssl)]), [openssl_include="$withval" CPPFLAGS="$CPPFLAGS -I$withval"] ) AC_ARG_WITH(openssl-lib, - AS_HELP_STRING([--with-openssl-lib=DIR], [OpenSSL library directory]), + AS_HELP_STRING([--with-openssl-lib=DIR], [LibreSSL/OpenSSL library directory]), [openssl_lib="$withval" LDFLAGS="$LDFLAGS -L$withval"] ) AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h], [], - [AC_MSG_ERROR([OpenSSL header files not found.]); break] + [AC_MSG_ERROR([LibreSSL/OpenSSL header files not found.]); break] ) AC_CHECK_LIB(crypto, EVP_EncryptInit_ex, [LIBS="-lcrypto $LIBS"], - [AC_MSG_ERROR([OpenSSL libraries not found.])] + [AC_MSG_ERROR([LibreSSL/OpenSSL libraries not found.])] ) AC_CHECK_FUNCS([RAND_status EVP_EncryptInit_ex], , - [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break], + [AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break], ) AC_CHECK_DECLS([OpenSSL_add_all_algorithms], , - [AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break], + [AC_MSG_ERROR([Missing LibreSSL/OpenSSL functionality, make sure you have installed the latest version.]); break], [#include ] ) ]) diff --git a/missing b/missing index db98974..f62bbae 100755 --- a/missing +++ b/missing @@ -3,7 +3,7 @@ scriptversion=2013-10-28.13; # UTC -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify diff --git a/src/Makefile.am b/src/Makefile.am index cd84f3a..200c71f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,16 +2,25 @@ sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair -## Make sure version.c is always rebuilt -.PHONY: version.c -version.c: +CLEANFILES = version_git.h + +.PHONY: version-stamp +version-stamp: + +version_git.h: version-stamp + $(AM_V_GEN)echo >$@ + @-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||: +${srcdir}/version.c: version_git.h + +## Now a hack to appease some versions of BSD make that don't understand that "./foo" is the same as "foo". +if BSD +version.c: ${srcdir}/version.c +endif if LINUX sbin_PROGRAMS += sptps_speed endif -DEFAULT_INCLUDES = - ed25519_SOURCES = \ ed25519/add_scalar.c \ ed25519/ed25519.h \ @@ -49,11 +58,6 @@ tincd_SOURCES = \ edge.c edge.h \ ethernet.h \ event.c event.h \ - fake-gai-errnos.h \ - fake-getaddrinfo.c fake-getaddrinfo.h \ - fake-getnameinfo.c fake-getnameinfo.h \ - getopt.c getopt.h \ - getopt1.c \ graph.c graph.h \ hash.c hash.h \ have.h \ @@ -92,13 +96,15 @@ tincd_SOURCES = \ utils.c utils.h \ xalloc.h \ version.c version.h \ + ed25519/ecdh.c \ + ed25519/ecdsa.c \ $(ed25519_SOURCES) \ $(chacha_poly1305_SOURCES) tinc_SOURCES = \ dropin.c dropin.h \ - getopt.c getopt.h \ - getopt1.c \ + fsck.c fsck.h \ + ifconfig.c ifconfig.h \ info.c info.h \ invitation.c invitation.h \ list.c list.h \ @@ -111,6 +117,9 @@ tinc_SOURCES = \ top.c top.h \ utils.c utils.h \ version.c version.h \ + ed25519/ecdh.c \ + ed25519/ecdsa.c \ + ed25519/ecdsagen.c \ $(ed25519_SOURCES) \ $(chacha_poly1305_SOURCES) @@ -119,12 +128,15 @@ sptps_test_SOURCES = \ sptps.c sptps.h \ sptps_test.c \ utils.c utils.h \ + ed25519/ecdh.c \ + ed25519/ecdsa.c \ $(ed25519_SOURCES) \ $(chacha_poly1305_SOURCES) sptps_keypair_SOURCES = \ sptps_keypair.c \ utils.c utils.h \ + ed25519/ecdsagen.c \ $(ed25519_SOURCES) sptps_speed_SOURCES = \ @@ -132,11 +144,29 @@ sptps_speed_SOURCES = \ sptps.c sptps.h \ sptps_speed.c \ utils.c utils.h \ + ed25519/ecdh.c \ + ed25519/ecdsa.c \ + ed25519/ecdsagen.c \ $(ed25519_SOURCES) \ $(chacha_poly1305_SOURCES) ## Conditionally compile device drivers - + +if !GETOPT +tincd_SOURCES += \ + getopt.c getopt.h \ + getopt1.c +tinc_SOURCES += \ + getopt.c getopt.h \ + getopt1.c +sptps_test_SOURCES += \ + getopt.c getopt.h \ + getopt1.c +sptps_keypair_SOURCES += \ + getopt.c getopt.h \ + getopt1.c +endif + if LINUX tincd_SOURCES += linux/device.c endif @@ -173,54 +203,37 @@ tincd_SOURCES += \ openssl/cipher.c \ openssl/crypto.c \ openssl/digest.c openssl/digest.h \ - ed25519/ecdh.c \ - ed25519/ecdsa.c \ openssl/prf.c \ openssl/rsa.c tinc_SOURCES += \ openssl/cipher.c \ openssl/crypto.c \ openssl/digest.c openssl/digest.h \ - ed25519/ecdh.c \ - ed25519/ecdsa.c \ - ed25519/ecdsagen.c \ openssl/prf.c \ openssl/rsa.c \ openssl/rsagen.c sptps_test_SOURCES += \ openssl/crypto.c \ openssl/digest.c openssl/digest.h \ - ed25519/ecdh.c \ - ed25519/ecdsa.c \ openssl/prf.c sptps_keypair_SOURCES += \ - openssl/crypto.c \ - ed25519/ecdsagen.c + openssl/crypto.c sptps_speed_SOURCES += \ openssl/crypto.c \ openssl/digest.c openssl/digest.h \ - ed25519/ecdh.c \ - ed25519/ecdsa.c \ - ed25519/ecdsagen.c \ openssl/prf.c -endif - +else if GCRYPT tincd_SOURCES += \ gcrypt/cipher.c \ gcrypt/crypto.c \ gcrypt/digest.c gcrypt/digest.h \ - gcrypt/ecdh.c \ - gcrypt/ecdsa.c \ gcrypt/prf.c \ gcrypt/rsa.c tinc_SOURCES += \ gcrypt/cipher.c \ gcrypt/crypto.c \ gcrypt/digest.c gcrypt/digest.h \ - gcrypt/ecdh.c \ - gcrypt/ecdsa.c \ - gcrypt/ecdsagen.c \ gcrypt/prf.c \ gcrypt/rsa.c \ gcrypt/rsagen.c @@ -228,18 +241,44 @@ sptps_test_SOURCES += \ gcrypt/cipher.c \ gcrypt/crypto.c \ gcrypt/digest.c gcrypt/digest.h \ - gcrypt/ecdh.c \ - gcrypt/ecdsa.c \ gcrypt/prf.c +sptps_keypair_SOURCES += \ + openssl/crypto.c +sptps_speed_SOURCES += \ + openssl/crypto.c \ + openssl/digest.c openssl/digest.h \ + openssl/prf.c +else +tincd_SOURCES += \ + nolegacy/crypto.c \ + nolegacy/prf.c +tinc_SOURCES += \ + nolegacy/crypto.c \ + nolegacy/prf.c +sptps_test_SOURCES += \ + nolegacy/crypto.c \ + nolegacy/prf.c +sptps_keypair_SOURCES += \ + nolegacy/crypto.c +sptps_speed_SOURCES += \ + nolegacy/crypto.c \ + nolegacy/prf.c +endif +endif + +if MINIUPNPC +tincd_SOURCES += upnp.h upnp.c +tincd_LDADD = $(MINIUPNPC_LIBS) +tincd_LDFLAGS = -pthread endif tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) sptps_speed_LDADD = -lrt -LIBS = @LIBS@ +LIBS = @LIBS@ -lm if TUNEMU LIBS += -lpcap endif -AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" +AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote. diff --git a/src/Makefile.in b/src/Makefile.in index bb7213a..da3ca9f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -81,95 +91,120 @@ host_triplet = @host@ sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT) \ sptps_keypair$(EXEEXT) $(am__EXEEXT_1) @LINUX_TRUE@am__append_1 = sptps_speed -@LINUX_TRUE@am__append_2 = linux/device.c -@BSD_TRUE@am__append_3 = bsd/device.c -@BSD_TRUE@@TUNEMU_TRUE@am__append_4 = bsd/tunemu.c bsd/tunemu.h -@SOLARIS_TRUE@am__append_5 = solaris/device.c -@MINGW_TRUE@am__append_6 = mingw/device.c mingw/common.h -@CYGWIN_TRUE@am__append_7 = cygwin/device.c -@UML_TRUE@am__append_8 = uml_device.c -@VDE_TRUE@am__append_9 = vde_device.c -@OPENSSL_TRUE@am__append_10 = \ +@GETOPT_FALSE@am__append_2 = \ +@GETOPT_FALSE@ getopt.c getopt.h \ +@GETOPT_FALSE@ getopt1.c + +@GETOPT_FALSE@am__append_3 = \ +@GETOPT_FALSE@ getopt.c getopt.h \ +@GETOPT_FALSE@ getopt1.c + +@GETOPT_FALSE@am__append_4 = \ +@GETOPT_FALSE@ getopt.c getopt.h \ +@GETOPT_FALSE@ getopt1.c + +@GETOPT_FALSE@am__append_5 = \ +@GETOPT_FALSE@ getopt.c getopt.h \ +@GETOPT_FALSE@ getopt1.c + +@LINUX_TRUE@am__append_6 = linux/device.c +@BSD_TRUE@am__append_7 = bsd/device.c +@BSD_TRUE@@TUNEMU_TRUE@am__append_8 = bsd/tunemu.c bsd/tunemu.h +@SOLARIS_TRUE@am__append_9 = solaris/device.c +@MINGW_TRUE@am__append_10 = mingw/device.c mingw/common.h +@CYGWIN_TRUE@am__append_11 = cygwin/device.c +@UML_TRUE@am__append_12 = uml_device.c +@VDE_TRUE@am__append_13 = vde_device.c +@OPENSSL_TRUE@am__append_14 = \ @OPENSSL_TRUE@ openssl/cipher.c \ @OPENSSL_TRUE@ openssl/crypto.c \ @OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \ -@OPENSSL_TRUE@ ed25519/ecdh.c \ -@OPENSSL_TRUE@ ed25519/ecdsa.c \ @OPENSSL_TRUE@ openssl/prf.c \ @OPENSSL_TRUE@ openssl/rsa.c -@OPENSSL_TRUE@am__append_11 = \ +@OPENSSL_TRUE@am__append_15 = \ @OPENSSL_TRUE@ openssl/cipher.c \ @OPENSSL_TRUE@ openssl/crypto.c \ @OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \ -@OPENSSL_TRUE@ ed25519/ecdh.c \ -@OPENSSL_TRUE@ ed25519/ecdsa.c \ -@OPENSSL_TRUE@ ed25519/ecdsagen.c \ @OPENSSL_TRUE@ openssl/prf.c \ @OPENSSL_TRUE@ openssl/rsa.c \ @OPENSSL_TRUE@ openssl/rsagen.c -@OPENSSL_TRUE@am__append_12 = \ +@OPENSSL_TRUE@am__append_16 = \ @OPENSSL_TRUE@ openssl/crypto.c \ @OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \ -@OPENSSL_TRUE@ ed25519/ecdh.c \ -@OPENSSL_TRUE@ ed25519/ecdsa.c \ @OPENSSL_TRUE@ openssl/prf.c -@OPENSSL_TRUE@am__append_13 = \ -@OPENSSL_TRUE@ openssl/crypto.c \ -@OPENSSL_TRUE@ ed25519/ecdsagen.c +@OPENSSL_TRUE@am__append_17 = \ +@OPENSSL_TRUE@ openssl/crypto.c -@OPENSSL_TRUE@am__append_14 = \ +@OPENSSL_TRUE@am__append_18 = \ @OPENSSL_TRUE@ openssl/crypto.c \ @OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \ -@OPENSSL_TRUE@ ed25519/ecdh.c \ -@OPENSSL_TRUE@ ed25519/ecdsa.c \ -@OPENSSL_TRUE@ ed25519/ecdsagen.c \ @OPENSSL_TRUE@ openssl/prf.c -@GCRYPT_TRUE@am__append_15 = \ -@GCRYPT_TRUE@ gcrypt/cipher.c \ -@GCRYPT_TRUE@ gcrypt/crypto.c \ -@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \ -@GCRYPT_TRUE@ gcrypt/ecdh.c \ -@GCRYPT_TRUE@ gcrypt/ecdsa.c \ -@GCRYPT_TRUE@ gcrypt/prf.c \ -@GCRYPT_TRUE@ gcrypt/rsa.c +@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_19 = \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.c -@GCRYPT_TRUE@am__append_16 = \ -@GCRYPT_TRUE@ gcrypt/cipher.c \ -@GCRYPT_TRUE@ gcrypt/crypto.c \ -@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \ -@GCRYPT_TRUE@ gcrypt/ecdh.c \ -@GCRYPT_TRUE@ gcrypt/ecdsa.c \ -@GCRYPT_TRUE@ gcrypt/ecdsagen.c \ -@GCRYPT_TRUE@ gcrypt/prf.c \ -@GCRYPT_TRUE@ gcrypt/rsa.c \ -@GCRYPT_TRUE@ gcrypt/rsagen.c +@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_20 = \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsagen.c -@GCRYPT_TRUE@am__append_17 = \ -@GCRYPT_TRUE@ gcrypt/cipher.c \ -@GCRYPT_TRUE@ gcrypt/crypto.c \ -@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \ -@GCRYPT_TRUE@ gcrypt/ecdh.c \ -@GCRYPT_TRUE@ gcrypt/ecdsa.c \ -@GCRYPT_TRUE@ gcrypt/prf.c +@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_21 = \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c -@TUNEMU_TRUE@am__append_18 = -lpcap +@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_22 = \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/crypto.c + +@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_23 = \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/crypto.c \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/digest.c openssl/digest.h \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/prf.c + +@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_24 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c + +@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_25 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c + +@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_26 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c + +@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_27 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c + +@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_28 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c + +@MINIUPNPC_TRUE@am__append_29 = upnp.h upnp.c +@TUNEMU_TRUE@am__append_30 = -lpcap subdir = src -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -178,78 +213,91 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__sptps_keypair_SOURCES_DIST = sptps_keypair.c utils.c utils.h \ - ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \ - ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \ - ed25519/key_exchange.c ed25519/keypair.c \ + ed25519/ecdsagen.c ed25519/add_scalar.c ed25519/ed25519.h \ + ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \ + ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \ ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \ ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ - ed25519/verify.c openssl/crypto.c ed25519/ecdsagen.c + ed25519/verify.c getopt.c getopt.h getopt1.c openssl/crypto.c \ + nolegacy/crypto.c am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = ed25519/add_scalar.$(OBJEXT) ed25519/fe.$(OBJEXT) \ ed25519/ge.$(OBJEXT) ed25519/key_exchange.$(OBJEXT) \ ed25519/keypair.$(OBJEXT) ed25519/sc.$(OBJEXT) \ ed25519/sha512.$(OBJEXT) ed25519/sign.$(OBJEXT) \ ed25519/verify.$(OBJEXT) -@OPENSSL_TRUE@am__objects_2 = openssl/crypto.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT) +@GETOPT_FALSE@am__objects_2 = getopt.$(OBJEXT) getopt1.$(OBJEXT) +@OPENSSL_TRUE@am__objects_3 = openssl/crypto.$(OBJEXT) +@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_4 = openssl/crypto.$(OBJEXT) +@GCRYPT_FALSE@@OPENSSL_FALSE@am__objects_5 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.$(OBJEXT) am_sptps_keypair_OBJECTS = sptps_keypair.$(OBJEXT) utils.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) + ed25519/ecdsagen.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) sptps_keypair_OBJECTS = $(am_sptps_keypair_OBJECTS) sptps_keypair_LDADD = $(LDADD) am__sptps_speed_SOURCES_DIST = logger.c logger.h sptps.c sptps.h \ - sptps_speed.c utils.c utils.h ed25519/add_scalar.c \ - ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \ - ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \ - ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \ - ed25519/sc.h ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ + sptps_speed.c utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \ + ed25519/ecdsagen.c ed25519/add_scalar.c ed25519/ed25519.h \ + ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \ + ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \ + ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \ + ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ ed25519/verify.c chacha-poly1305/chacha.c \ chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \ chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \ chacha-poly1305/poly1305.h openssl/crypto.c openssl/digest.c \ - openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c \ - ed25519/ecdsagen.c openssl/prf.c -am__objects_3 = chacha-poly1305/chacha.$(OBJEXT) \ + openssl/digest.h openssl/prf.c nolegacy/crypto.c \ + nolegacy/prf.c +am__objects_6 = chacha-poly1305/chacha.$(OBJEXT) \ chacha-poly1305/chacha-poly1305.$(OBJEXT) \ chacha-poly1305/poly1305.$(OBJEXT) -@OPENSSL_TRUE@am__objects_4 = openssl/crypto.$(OBJEXT) \ -@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT) openssl/prf.$(OBJEXT) +@OPENSSL_TRUE@am__objects_7 = openssl/crypto.$(OBJEXT) \ +@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT) +@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_8 = openssl/crypto.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/digest.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/prf.$(OBJEXT) +@GCRYPT_FALSE@@OPENSSL_FALSE@am__objects_9 = \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.$(OBJEXT) \ +@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.$(OBJEXT) am_sptps_speed_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \ - sptps_speed.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \ - $(am__objects_3) $(am__objects_4) + sptps_speed.$(OBJEXT) utils.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ + ed25519/ecdsa.$(OBJEXT) ed25519/ecdsagen.$(OBJEXT) \ + $(am__objects_1) $(am__objects_6) $(am__objects_7) \ + $(am__objects_8) $(am__objects_9) sptps_speed_OBJECTS = $(am_sptps_speed_OBJECTS) sptps_speed_DEPENDENCIES = am__sptps_test_SOURCES_DIST = logger.c logger.h sptps.c sptps.h \ - sptps_test.c utils.c utils.h ed25519/add_scalar.c \ - ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \ - ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \ - ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \ - ed25519/sc.h ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ + sptps_test.c utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \ + ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \ + ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \ + ed25519/key_exchange.c ed25519/keypair.c \ + ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \ + ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ ed25519/verify.c chacha-poly1305/chacha.c \ chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \ chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \ - chacha-poly1305/poly1305.h openssl/crypto.c openssl/digest.c \ - openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c openssl/prf.c \ - gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \ - gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c gcrypt/prf.c -@OPENSSL_TRUE@am__objects_5 = openssl/crypto.$(OBJEXT) \ -@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT) -@GCRYPT_TRUE@am__objects_6 = gcrypt/cipher.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/prf.$(OBJEXT) + chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \ + openssl/crypto.c openssl/digest.c openssl/digest.h \ + openssl/prf.c gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \ + gcrypt/digest.h gcrypt/prf.c nolegacy/crypto.c nolegacy/prf.c +@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_10 = gcrypt/cipher.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT) am_sptps_test_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \ - sptps_test.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \ - $(am__objects_3) $(am__objects_5) $(am__objects_6) + sptps_test.$(OBJEXT) utils.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ + ed25519/ecdsa.$(OBJEXT) $(am__objects_1) $(am__objects_6) \ + $(am__objects_2) $(am__objects_7) $(am__objects_10) \ + $(am__objects_9) sptps_test_OBJECTS = $(am_sptps_test_OBJECTS) sptps_test_LDADD = $(LDADD) -am__tinc_SOURCES_DIST = dropin.c dropin.h getopt.c getopt.h getopt1.c \ - info.c info.h invitation.c invitation.h list.c list.h names.c \ - names.h netutl.c netutl.h script.c script.h sptps.c sptps.h \ - subnet_parse.c subnet.h tincctl.c tincctl.h top.c top.h \ - utils.c utils.h version.c version.h ed25519/add_scalar.c \ +am__tinc_SOURCES_DIST = dropin.c dropin.h fsck.c fsck.h ifconfig.c \ + ifconfig.h info.c info.h invitation.c invitation.h list.c \ + list.h names.c names.h netutl.c netutl.h script.c script.h \ + sptps.c sptps.h subnet_parse.c subnet.h tincctl.c tincctl.h \ + top.c top.h utils.c utils.h version.c version.h ed25519/ecdh.c \ + ed25519/ecdsa.c ed25519/ecdsagen.c ed25519/add_scalar.c \ ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \ ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \ ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \ @@ -257,30 +305,31 @@ am__tinc_SOURCES_DIST = dropin.c dropin.h getopt.c getopt.h getopt1.c \ ed25519/verify.c chacha-poly1305/chacha.c \ chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \ chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \ - chacha-poly1305/poly1305.h openssl/cipher.c openssl/crypto.c \ - openssl/digest.c openssl/digest.h ed25519/ecdh.c \ - ed25519/ecdsa.c ed25519/ecdsagen.c openssl/prf.c openssl/rsa.c \ - openssl/rsagen.c gcrypt/cipher.c gcrypt/crypto.c \ - gcrypt/digest.c gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c \ - gcrypt/ecdsagen.c gcrypt/prf.c gcrypt/rsa.c gcrypt/rsagen.c -@OPENSSL_TRUE@am__objects_7 = openssl/cipher.$(OBJEXT) \ + chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \ + openssl/cipher.c openssl/crypto.c openssl/digest.c \ + openssl/digest.h openssl/prf.c openssl/rsa.c openssl/rsagen.c \ + gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \ + gcrypt/digest.h gcrypt/prf.c gcrypt/rsa.c gcrypt/rsagen.c \ + nolegacy/crypto.c nolegacy/prf.c +@OPENSSL_TRUE@am__objects_11 = openssl/cipher.$(OBJEXT) \ @OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \ -@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT) openssl/prf.$(OBJEXT) \ +@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT) \ @OPENSSL_TRUE@ openssl/rsa.$(OBJEXT) openssl/rsagen.$(OBJEXT) -@GCRYPT_TRUE@am__objects_8 = gcrypt/cipher.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/ecdsagen.$(OBJEXT) gcrypt/prf.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/rsa.$(OBJEXT) gcrypt/rsagen.$(OBJEXT) -am_tinc_OBJECTS = dropin.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_12 = gcrypt/cipher.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsagen.$(OBJEXT) +am_tinc_OBJECTS = dropin.$(OBJEXT) fsck.$(OBJEXT) ifconfig.$(OBJEXT) \ info.$(OBJEXT) invitation.$(OBJEXT) list.$(OBJEXT) \ names.$(OBJEXT) netutl.$(OBJEXT) script.$(OBJEXT) \ sptps.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \ top.$(OBJEXT) utils.$(OBJEXT) version.$(OBJEXT) \ - $(am__objects_1) $(am__objects_3) $(am__objects_7) \ - $(am__objects_8) + ed25519/ecdh.$(OBJEXT) ed25519/ecdsa.$(OBJEXT) \ + ed25519/ecdsagen.$(OBJEXT) $(am__objects_1) $(am__objects_6) \ + $(am__objects_2) $(am__objects_11) $(am__objects_12) \ + $(am__objects_9) tinc_OBJECTS = $(am_tinc_OBJECTS) am__DEPENDENCIES_1 = tinc_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) @@ -288,73 +337,74 @@ am__tincd_SOURCES_DIST = buffer.c buffer.h cipher.h conf.c conf.h \ connection.c connection.h control.c control.h control_common.h \ crypto.h device.h digest.h dropin.c dropin.h dummy_device.c \ ecdh.h ecdsa.h ecdsagen.h edge.c edge.h ethernet.h event.c \ - event.h fake-gai-errnos.h fake-getaddrinfo.c \ - fake-getaddrinfo.h fake-getnameinfo.c fake-getnameinfo.h \ - getopt.c getopt.h getopt1.c graph.c graph.h hash.c hash.h \ - have.h ipv4.h ipv6.h list.c list.h logger.c logger.h meta.c \ - meta.h multicast_device.c names.c names.h net.c net.h \ - net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \ - node.h prf.h process.c process.h protocol.c protocol.h \ - protocol_auth.c protocol_edge.c protocol_key.c protocol_misc.c \ + event.h graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h \ + list.c list.h logger.c logger.h meta.c meta.h \ + multicast_device.c names.c names.h net.c net.h net_packet.c \ + net_setup.c net_socket.c netutl.c netutl.h node.c node.h prf.h \ + process.c process.h protocol.c protocol.h protocol_auth.c \ + protocol_edge.c protocol_key.c protocol_misc.c \ protocol_subnet.c raw_socket_device.c route.c route.h rsa.h \ rsagen.h script.c script.h splay_tree.c splay_tree.h sptps.c \ sptps.h subnet.c subnet.h subnet_parse.c system.h tincd.c \ - utils.c utils.h xalloc.h version.c version.h \ - ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \ - ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \ - ed25519/key_exchange.c ed25519/keypair.c \ + utils.c utils.h xalloc.h version.c version.h ed25519/ecdh.c \ + ed25519/ecdsa.c ed25519/add_scalar.c ed25519/ed25519.h \ + ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \ + ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \ ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \ ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \ ed25519/verify.c chacha-poly1305/chacha.c \ chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \ chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \ - chacha-poly1305/poly1305.h linux/device.c bsd/device.c \ - bsd/tunemu.c bsd/tunemu.h solaris/device.c mingw/device.c \ - mingw/common.h cygwin/device.c uml_device.c vde_device.c \ - openssl/cipher.c openssl/crypto.c openssl/digest.c \ - openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c openssl/prf.c \ - openssl/rsa.c gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \ - gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c gcrypt/prf.c \ - gcrypt/rsa.c -@LINUX_TRUE@am__objects_9 = linux/device.$(OBJEXT) -@BSD_TRUE@am__objects_10 = bsd/device.$(OBJEXT) -@BSD_TRUE@@TUNEMU_TRUE@am__objects_11 = bsd/tunemu.$(OBJEXT) -@SOLARIS_TRUE@am__objects_12 = solaris/device.$(OBJEXT) -@MINGW_TRUE@am__objects_13 = mingw/device.$(OBJEXT) -@CYGWIN_TRUE@am__objects_14 = cygwin/device.$(OBJEXT) -@UML_TRUE@am__objects_15 = uml_device.$(OBJEXT) -@VDE_TRUE@am__objects_16 = vde_device.$(OBJEXT) -@OPENSSL_TRUE@am__objects_17 = openssl/cipher.$(OBJEXT) \ + chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \ + linux/device.c bsd/device.c bsd/tunemu.c bsd/tunemu.h \ + solaris/device.c mingw/device.c mingw/common.h cygwin/device.c \ + uml_device.c vde_device.c openssl/cipher.c openssl/crypto.c \ + openssl/digest.c openssl/digest.h openssl/prf.c openssl/rsa.c \ + gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \ + gcrypt/digest.h gcrypt/prf.c gcrypt/rsa.c nolegacy/crypto.c \ + nolegacy/prf.c upnp.h upnp.c +@LINUX_TRUE@am__objects_13 = linux/device.$(OBJEXT) +@BSD_TRUE@am__objects_14 = bsd/device.$(OBJEXT) +@BSD_TRUE@@TUNEMU_TRUE@am__objects_15 = bsd/tunemu.$(OBJEXT) +@SOLARIS_TRUE@am__objects_16 = solaris/device.$(OBJEXT) +@MINGW_TRUE@am__objects_17 = mingw/device.$(OBJEXT) +@CYGWIN_TRUE@am__objects_18 = cygwin/device.$(OBJEXT) +@UML_TRUE@am__objects_19 = uml_device.$(OBJEXT) +@VDE_TRUE@am__objects_20 = vde_device.$(OBJEXT) +@OPENSSL_TRUE@am__objects_21 = openssl/cipher.$(OBJEXT) \ @OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \ -@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ -@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT) \ +@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT) \ @OPENSSL_TRUE@ openssl/rsa.$(OBJEXT) -@GCRYPT_TRUE@am__objects_18 = gcrypt/cipher.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \ -@GCRYPT_TRUE@ gcrypt/prf.$(OBJEXT) gcrypt/rsa.$(OBJEXT) +@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_22 = gcrypt/cipher.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT) \ +@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.$(OBJEXT) +@MINIUPNPC_TRUE@am__objects_23 = upnp.$(OBJEXT) am_tincd_OBJECTS = buffer.$(OBJEXT) conf.$(OBJEXT) \ connection.$(OBJEXT) control.$(OBJEXT) dropin.$(OBJEXT) \ dummy_device.$(OBJEXT) edge.$(OBJEXT) event.$(OBJEXT) \ - fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \ - getopt.$(OBJEXT) getopt1.$(OBJEXT) graph.$(OBJEXT) \ - hash.$(OBJEXT) list.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) \ - multicast_device.$(OBJEXT) names.$(OBJEXT) net.$(OBJEXT) \ - net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \ - netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \ - protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \ + graph.$(OBJEXT) hash.$(OBJEXT) list.$(OBJEXT) logger.$(OBJEXT) \ + meta.$(OBJEXT) multicast_device.$(OBJEXT) names.$(OBJEXT) \ + net.$(OBJEXT) net_packet.$(OBJEXT) net_setup.$(OBJEXT) \ + net_socket.$(OBJEXT) netutl.$(OBJEXT) node.$(OBJEXT) \ + process.$(OBJEXT) protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \ protocol_edge.$(OBJEXT) protocol_key.$(OBJEXT) \ protocol_misc.$(OBJEXT) protocol_subnet.$(OBJEXT) \ raw_socket_device.$(OBJEXT) route.$(OBJEXT) script.$(OBJEXT) \ splay_tree.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \ subnet_parse.$(OBJEXT) tincd.$(OBJEXT) utils.$(OBJEXT) \ - version.$(OBJEXT) $(am__objects_1) $(am__objects_3) \ - $(am__objects_9) $(am__objects_10) $(am__objects_11) \ - $(am__objects_12) $(am__objects_13) $(am__objects_14) \ + version.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \ + ed25519/ecdsa.$(OBJEXT) $(am__objects_1) $(am__objects_6) \ + $(am__objects_2) $(am__objects_13) $(am__objects_14) \ $(am__objects_15) $(am__objects_16) $(am__objects_17) \ - $(am__objects_18) + $(am__objects_18) $(am__objects_19) $(am__objects_20) \ + $(am__objects_21) $(am__objects_22) $(am__objects_9) \ + $(am__objects_23) tincd_OBJECTS = $(am_tincd_OBJECTS) -tincd_LDADD = $(LDADD) +@MINIUPNPC_TRUE@tincd_DEPENDENCIES = $(am__DEPENDENCIES_1) +tincd_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(tincd_LDFLAGS) \ + $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -367,6 +417,7 @@ AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = +DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -411,6 +462,7 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -441,10 +493,11 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ $(am__append_18) +LIBS = @LIBS@ -lm $(am__append_30) LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -502,15 +555,17 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -DEFAULT_INCLUDES = +CLEANFILES = version_git.h ed25519_SOURCES = \ ed25519/add_scalar.c \ ed25519/ed25519.h \ @@ -534,39 +589,47 @@ tincd_SOURCES = buffer.c buffer.h cipher.h conf.c conf.h connection.c \ connection.h control.c control.h control_common.h crypto.h \ device.h digest.h dropin.c dropin.h dummy_device.c ecdh.h \ ecdsa.h ecdsagen.h edge.c edge.h ethernet.h event.c event.h \ - fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \ - fake-getnameinfo.c fake-getnameinfo.h getopt.c getopt.h \ - getopt1.c graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h \ - list.c list.h logger.c logger.h meta.c meta.h \ - multicast_device.c names.c names.h net.c net.h net_packet.c \ - net_setup.c net_socket.c netutl.c netutl.h node.c node.h prf.h \ - process.c process.h protocol.c protocol.h protocol_auth.c \ + graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h list.c \ + list.h logger.c logger.h meta.c meta.h multicast_device.c \ + names.c names.h net.c net.h net_packet.c net_setup.c \ + net_socket.c netutl.c netutl.h node.c node.h prf.h process.c \ + process.h protocol.c protocol.h protocol_auth.c \ protocol_edge.c protocol_key.c protocol_misc.c \ protocol_subnet.c raw_socket_device.c route.c route.h rsa.h \ rsagen.h script.c script.h splay_tree.c splay_tree.h sptps.c \ sptps.h subnet.c subnet.h subnet_parse.c system.h tincd.c \ - utils.c utils.h xalloc.h version.c version.h \ - $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) \ - $(am__append_6) $(am__append_7) $(am__append_8) \ - $(am__append_9) $(am__append_10) $(am__append_15) -tinc_SOURCES = dropin.c dropin.h getopt.c getopt.h getopt1.c info.c \ - info.h invitation.c invitation.h list.c list.h names.c names.h \ - netutl.c netutl.h script.c script.h sptps.c sptps.h \ + utils.c utils.h xalloc.h version.c version.h ed25519/ecdh.c \ + ed25519/ecdsa.c $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \ + $(am__append_2) $(am__append_6) $(am__append_7) \ + $(am__append_8) $(am__append_9) $(am__append_10) \ + $(am__append_11) $(am__append_12) $(am__append_13) \ + $(am__append_14) $(am__append_19) $(am__append_24) \ + $(am__append_29) +tinc_SOURCES = dropin.c dropin.h fsck.c fsck.h ifconfig.c ifconfig.h \ + info.c info.h invitation.c invitation.h list.c list.h names.c \ + names.h netutl.c netutl.h script.c script.h sptps.c sptps.h \ subnet_parse.c subnet.h tincctl.c tincctl.h top.c top.h \ - utils.c utils.h version.c version.h $(ed25519_SOURCES) \ - $(chacha_poly1305_SOURCES) $(am__append_11) $(am__append_16) + utils.c utils.h version.c version.h ed25519/ecdh.c \ + ed25519/ecdsa.c ed25519/ecdsagen.c $(ed25519_SOURCES) \ + $(chacha_poly1305_SOURCES) $(am__append_3) $(am__append_15) \ + $(am__append_20) $(am__append_25) sptps_test_SOURCES = logger.c logger.h sptps.c sptps.h sptps_test.c \ - utils.c utils.h $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \ - $(am__append_12) $(am__append_17) + utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \ + $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) $(am__append_4) \ + $(am__append_16) $(am__append_21) $(am__append_26) sptps_keypair_SOURCES = sptps_keypair.c utils.c utils.h \ - $(ed25519_SOURCES) $(am__append_13) + ed25519/ecdsagen.c $(ed25519_SOURCES) $(am__append_5) \ + $(am__append_17) $(am__append_22) $(am__append_27) sptps_speed_SOURCES = logger.c logger.h sptps.c sptps.h sptps_speed.c \ - utils.c utils.h $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \ - $(am__append_14) + utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \ + ed25519/ecdsagen.c $(ed25519_SOURCES) \ + $(chacha_poly1305_SOURCES) $(am__append_18) $(am__append_23) \ + $(am__append_28) +@MINIUPNPC_TRUE@tincd_LDADD = $(MINIUPNPC_LIBS) +@MINIUPNPC_TRUE@tincd_LDFLAGS = -pthread tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) sptps_speed_LDADD = -lrt -AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" +AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote. all: all-am .SUFFIXES: @@ -583,7 +646,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -665,6 +727,8 @@ ed25519/$(am__dirstamp): ed25519/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ed25519/$(DEPDIR) @: > ed25519/$(DEPDIR)/$(am__dirstamp) +ed25519/ecdsagen.$(OBJEXT): ed25519/$(am__dirstamp) \ + ed25519/$(DEPDIR)/$(am__dirstamp) ed25519/add_scalar.$(OBJEXT): ed25519/$(am__dirstamp) \ ed25519/$(DEPDIR)/$(am__dirstamp) ed25519/fe.$(OBJEXT): ed25519/$(am__dirstamp) \ @@ -691,12 +755,22 @@ openssl/$(DEPDIR)/$(am__dirstamp): @: > openssl/$(DEPDIR)/$(am__dirstamp) openssl/crypto.$(OBJEXT): openssl/$(am__dirstamp) \ openssl/$(DEPDIR)/$(am__dirstamp) -ed25519/ecdsagen.$(OBJEXT): ed25519/$(am__dirstamp) \ - ed25519/$(DEPDIR)/$(am__dirstamp) +nolegacy/$(am__dirstamp): + @$(MKDIR_P) nolegacy + @: > nolegacy/$(am__dirstamp) +nolegacy/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) nolegacy/$(DEPDIR) + @: > nolegacy/$(DEPDIR)/$(am__dirstamp) +nolegacy/crypto.$(OBJEXT): nolegacy/$(am__dirstamp) \ + nolegacy/$(DEPDIR)/$(am__dirstamp) sptps_keypair$(EXEEXT): $(sptps_keypair_OBJECTS) $(sptps_keypair_DEPENDENCIES) $(EXTRA_sptps_keypair_DEPENDENCIES) @rm -f sptps_keypair$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sptps_keypair_OBJECTS) $(sptps_keypair_LDADD) $(LIBS) +ed25519/ecdh.$(OBJEXT): ed25519/$(am__dirstamp) \ + ed25519/$(DEPDIR)/$(am__dirstamp) +ed25519/ecdsa.$(OBJEXT): ed25519/$(am__dirstamp) \ + ed25519/$(DEPDIR)/$(am__dirstamp) chacha-poly1305/$(am__dirstamp): @$(MKDIR_P) chacha-poly1305 @: > chacha-poly1305/$(am__dirstamp) @@ -712,12 +786,10 @@ chacha-poly1305/poly1305.$(OBJEXT): chacha-poly1305/$(am__dirstamp) \ chacha-poly1305/$(DEPDIR)/$(am__dirstamp) openssl/digest.$(OBJEXT): openssl/$(am__dirstamp) \ openssl/$(DEPDIR)/$(am__dirstamp) -ed25519/ecdh.$(OBJEXT): ed25519/$(am__dirstamp) \ - ed25519/$(DEPDIR)/$(am__dirstamp) -ed25519/ecdsa.$(OBJEXT): ed25519/$(am__dirstamp) \ - ed25519/$(DEPDIR)/$(am__dirstamp) openssl/prf.$(OBJEXT): openssl/$(am__dirstamp) \ openssl/$(DEPDIR)/$(am__dirstamp) +nolegacy/prf.$(OBJEXT): nolegacy/$(am__dirstamp) \ + nolegacy/$(DEPDIR)/$(am__dirstamp) sptps_speed$(EXEEXT): $(sptps_speed_OBJECTS) $(sptps_speed_DEPENDENCIES) $(EXTRA_sptps_speed_DEPENDENCIES) @rm -f sptps_speed$(EXEEXT) @@ -734,10 +806,6 @@ gcrypt/crypto.$(OBJEXT): gcrypt/$(am__dirstamp) \ gcrypt/$(DEPDIR)/$(am__dirstamp) gcrypt/digest.$(OBJEXT): gcrypt/$(am__dirstamp) \ gcrypt/$(DEPDIR)/$(am__dirstamp) -gcrypt/ecdh.$(OBJEXT): gcrypt/$(am__dirstamp) \ - gcrypt/$(DEPDIR)/$(am__dirstamp) -gcrypt/ecdsa.$(OBJEXT): gcrypt/$(am__dirstamp) \ - gcrypt/$(DEPDIR)/$(am__dirstamp) gcrypt/prf.$(OBJEXT): gcrypt/$(am__dirstamp) \ gcrypt/$(DEPDIR)/$(am__dirstamp) @@ -750,8 +818,6 @@ openssl/rsa.$(OBJEXT): openssl/$(am__dirstamp) \ openssl/$(DEPDIR)/$(am__dirstamp) openssl/rsagen.$(OBJEXT): openssl/$(am__dirstamp) \ openssl/$(DEPDIR)/$(am__dirstamp) -gcrypt/ecdsagen.$(OBJEXT): gcrypt/$(am__dirstamp) \ - gcrypt/$(DEPDIR)/$(am__dirstamp) gcrypt/rsa.$(OBJEXT): gcrypt/$(am__dirstamp) \ gcrypt/$(DEPDIR)/$(am__dirstamp) gcrypt/rsagen.$(OBJEXT): gcrypt/$(am__dirstamp) \ @@ -805,7 +871,7 @@ cygwin/device.$(OBJEXT): cygwin/$(am__dirstamp) \ tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES) @rm -f tincd$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS) + $(AM_V_CCLD)$(tincd_LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -816,6 +882,7 @@ mostlyclean-compile: -rm -f gcrypt/*.$(OBJEXT) -rm -f linux/*.$(OBJEXT) -rm -f mingw/*.$(OBJEXT) + -rm -f nolegacy/*.$(OBJEXT) -rm -f openssl/*.$(OBJEXT) -rm -f solaris/*.$(OBJEXT) @@ -830,12 +897,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edge.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getaddrinfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getnameinfo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsck.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)/graph.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifconfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invitation.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ @@ -870,6 +937,7 @@ distclean-compile: @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)/uml_device.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upnp.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ @@ -894,14 +962,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/cipher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/digest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdh.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdsa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdsagen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/prf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/rsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/rsagen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@linux/$(DEPDIR)/device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mingw/$(DEPDIR)/device.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@nolegacy/$(DEPDIR)/crypto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@nolegacy/$(DEPDIR)/prf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/cipher.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/crypto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/digest.Po@am__quote@ @@ -1037,6 +1104,7 @@ install-strip: mostlyclean-generic: clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -1055,6 +1123,8 @@ distclean-generic: -rm -f linux/$(am__dirstamp) -rm -f mingw/$(DEPDIR)/$(am__dirstamp) -rm -f mingw/$(am__dirstamp) + -rm -f nolegacy/$(DEPDIR)/$(am__dirstamp) + -rm -f nolegacy/$(am__dirstamp) -rm -f openssl/$(DEPDIR)/$(am__dirstamp) -rm -f openssl/$(am__dirstamp) -rm -f solaris/$(DEPDIR)/$(am__dirstamp) @@ -1068,7 +1138,7 @@ clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR) + -rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) nolegacy/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -1114,7 +1184,7 @@ install-ps-am: installcheck-am: installcheck-sbinPROGRAMS maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR) + -rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) nolegacy/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -1148,9 +1218,18 @@ uninstall-am: uninstall-sbinPROGRAMS mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS +.PRECIOUS: Makefile -.PHONY: version.c -version.c: + +.PHONY: version-stamp +version-stamp: + +version_git.h: version-stamp + $(AM_V_GEN)echo >$@ + @-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||: +${srcdir}/version.c: version_git.h + +@BSD_TRUE@version.c: ${srcdir}/version.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/bsd/device.c b/src/bsd/device.c index d1a993b..0d41c96 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -1,7 +1,7 @@ /* device.c -- Interaction BSD tun/tap device Copyright (C) 2001-2005 Ivo Timmermans, - 2001-2014 Guus Sliepen + 2001-2016 Guus Sliepen 2009 Grzegorz Dymarek This program is free software; you can redistribute it and/or modify @@ -34,13 +34,15 @@ #include "bsd/tunemu.h" #endif -#define DEFAULT_TUN_DEVICE "/dev/tun0" -#if defined(HAVE_DARWIN) || defined(HAVE_FREEBSD) || defined(HAVE_NETBSD) -#define DEFAULT_TAP_DEVICE "/dev/tap0" -#else -#define DEFAULT_TAP_DEVICE "/dev/tun0" +#ifdef HAVE_NET_IF_UTUN_H +#include +#include +#include #endif +#define DEFAULT_TUN_DEVICE "/dev/tun0" +#define DEFAULT_TAP_DEVICE "/dev/tap0" + typedef enum device_type { DEVICE_TYPE_TUN, DEVICE_TYPE_TUNIFHEAD, @@ -48,6 +50,7 @@ typedef enum device_type { #ifdef ENABLE_TUNEMU DEVICE_TYPE_TUNEMU, #endif + DEVICE_TYPE_UTUN, } device_type_t; int device_fd = -1; @@ -62,9 +65,64 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD; static device_type_t device_type = DEVICE_TYPE_TUN; #endif +#ifdef HAVE_NET_IF_UTUN_H +static bool setup_utun(void) { + device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if(device_fd == -1) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno)); + return false; + } + + struct ctl_info info = {}; + strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof info.ctl_name); + + if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) { + logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno)); + return false; + } + + int unit = -1; + char *p = strstr(device, "utun"), *e = NULL; + if(p) { + unit = strtol(p + 4, &e, 10); + if(!e) + unit = -1; + } + + struct sockaddr_ctl sc = { + .sc_id = info.ctl_id, + .sc_len = sizeof sc, + .sc_family = AF_SYSTEM, + .ss_sysaddr = AF_SYS_CONTROL, + .sc_unit = unit + 1, + }; + + if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno)); + return false; + } + + char name[64] = ""; + socklen_t len = sizeof name; + if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) { + iface = xstrdup(device); + } else { + iface = xstrdup(name); + } + + device_info = "OS X utun device"; + + logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info); + + return true; +} +#endif + static bool setup_device(void) { get_config_string(lookup_config(config_tree, "Device"), &device); + // Find out if it's supposed to be a tun or a tap device + char *type; if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(!strcasecmp(type, "tun")) @@ -72,6 +130,10 @@ static bool setup_device(void) { #ifdef ENABLE_TUNEMU else if(!strcasecmp(type, "tunemu")) device_type = DEVICE_TYPE_TUNEMU; +#endif +#ifdef HAVE_NET_IF_UTUN_H + else if(!strcasecmp(type, "utun")) + device_type = DEVICE_TYPE_UTUN; #endif else if(!strcasecmp(type, "tunnohead")) device_type = DEVICE_TYPE_TUN; @@ -84,10 +146,22 @@ static bool setup_device(void) { return false; } } else { +#ifdef HAVE_NET_IF_UTUN_H + if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0)) + device_type = DEVICE_TYPE_UTUN; + else +#endif if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER) device_type = DEVICE_TYPE_TAP; } + if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) { + logger(DEBUG_ALWAYS, LOG_ERR, "Only tap devices support switch mode!"); + return false; + } + + // Find out which device file to open + if(!device) { if(device_type == DEVICE_TYPE_TAP) device = xstrdup(DEFAULT_TAP_DEVICE); @@ -95,17 +169,7 @@ static bool setup_device(void) { device = xstrdup(DEFAULT_TUN_DEVICE); } - if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) - iface = NULL; -#ifndef TAPGIFNAME - if (iface) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring specified interface name '%s' as device rename is not supported on this platform", iface); - free(iface); - iface = NULL; - } -#endif - if (!iface) - iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); + // Open the device switch(device_type) { #ifdef ENABLE_TUNEMU @@ -114,6 +178,10 @@ static bool setup_device(void) { device_fd = tunemu_open(dynamic_name); } break; +#endif +#ifdef HAVE_NET_IF_UTUN_H + case DEVICE_TYPE_UTUN: + return setup_utun(); #endif default: device_fd = open(device, O_RDWR | O_NONBLOCK); @@ -128,6 +196,27 @@ static bool setup_device(void) { fcntl(device_fd, F_SETFD, FD_CLOEXEC); #endif + // Guess what the corresponding interface is called + + char *realname; + +#if defined(HAVE_FDEVNAME) + realname = fdevname(device_fd) ? : device; +#elif defined(HAVE_DEVNAME) + struct stat buf; + if(!fstat(device_fd, &buf)) + realname = devname(buf.st_rdev, S_IFCHR) ? : device; +#else + realname = device; +#endif + + if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) + iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname); + else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) + logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly."); + + // Configure the device as best as we can + switch(device_type) { default: device_type = DEVICE_TYPE_TUN; @@ -192,6 +281,11 @@ static bool setup_device(void) { #endif } +#ifdef SIOCGIFADDR + if(overwrite_mac) + ioctl(device_fd, SIOCGIFADDR, mymac.x); +#endif + logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info); return true; @@ -253,31 +347,29 @@ static bool read_packet(vpn_packet_t *packet) { packet->len = inlen + 14; break; + case DEVICE_TYPE_UTUN: case DEVICE_TYPE_TUNIFHEAD: { - u_int32_t type; - struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}}; - - if((inlen = readv(device_fd, vector, 2)) <= 0) { + if((inlen = read(device_fd, packet->data + 10, MTU - 10)) <= 0) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } - switch (ntohl(type)) { - case AF_INET: + switch (packet->data[14] >> 4) { + case 4: DATA(packet)[12] = 0x08; DATA(packet)[13] = 0x00; break; - case AF_INET6: + case 6: DATA(packet)[12] = 0x86; DATA(packet)[13] = 0xDD; break; default: logger(DEBUG_TRAFFIC, LOG_ERR, - "Unknown address family %x while reading packet from %s %s", - ntohl(type), device_info, device); + "Unknown IP version %d while reading packet from %s %s", + packet->data[14] >> 4, device_info, device); return false; } @@ -319,12 +411,10 @@ static bool write_packet(vpn_packet_t *packet) { } break; + case DEVICE_TYPE_UTUN: case DEVICE_TYPE_TUNIFHEAD: { - u_int32_t type; - struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}}; - int af; - - af = (DATA(packet)[12] << 8) + DATA(packet)[13]; + int af = (DATA(packet)[12] << 8) + DATA(packet)[13]; + uint32_t type; switch (af) { case 0x0800: @@ -340,7 +430,9 @@ static bool write_packet(vpn_packet_t *packet) { return false; } - if(writev(device_fd, vector, 2) < 0) { + memcpy(packet->data + 10, &type, sizeof type); + + if(write(device_fd, packet->data + 10, packet->len - 10) < 0) { logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); return false; diff --git a/src/cipher.h b/src/cipher.h index 47cd1cd..3f98c18 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -24,6 +24,8 @@ #define CIPHER_MAX_IV_SIZE 16 #define CIPHER_MAX_KEY_SIZE 32 +#ifndef DISABLE_LEGACY + typedef struct cipher cipher_t; extern cipher_t *cipher_open_by_name(const char *) __attribute__ ((__malloc__)); @@ -31,6 +33,7 @@ extern cipher_t *cipher_open_by_nid(int) __attribute__ ((__malloc__)); extern cipher_t *cipher_open_blowfish_ofb(void) __attribute__ ((__malloc__)); extern void cipher_close(cipher_t *); extern size_t cipher_keylength(const cipher_t *); +extern size_t cipher_blocksize(const cipher_t *); extern void cipher_get_key(const cipher_t *, void *); extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__)); extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__)); @@ -40,3 +43,5 @@ extern int cipher_get_nid(const cipher_t *); extern bool cipher_active(const cipher_t *); #endif + +#endif diff --git a/src/conf.c b/src/conf.c index e0d8e92..7756247 100644 --- a/src/conf.c +++ b/src/conf.c @@ -4,7 +4,7 @@ 1998-2005 Ivo Timmermans 2000 Cris van Pelt 2010-2011 Julien Muchembled - 2000-2013 Guus Sliepen + 2000-2015 Guus Sliepen 2013 Florent Clairambault This program is free software; you can redistribute it and/or modify @@ -298,7 +298,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) { fp = fopen(fname, "r"); if(!fp) { - logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno)); + logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno)); return false; } @@ -368,19 +368,19 @@ void read_config_options(splay_tree_t *config_tree, const char *prefix) { } bool read_server_config(void) { - char *fname; + char fname[PATH_MAX]; bool x; read_config_options(config_tree, NULL); - xasprintf(&fname, "%s" SLASH "tinc.conf", confbase); + snprintf(fname, sizeof fname, "%s" SLASH "tinc.conf", confbase); errno = 0; x = read_config_file(config_tree, fname); // We will try to read the conf files in the "conf.d" dir if (x) { - char * dname; - xasprintf(&dname, "%s" SLASH "conf.d", confbase); + char dname[PATH_MAX]; + snprintf(dname, sizeof dname, "%s" SLASH "conf.d", confbase); DIR *dir = opendir (dname); // If we can find this dir if (dir) { @@ -390,51 +390,44 @@ bool read_server_config(void) { size_t l = strlen(ep->d_name); // And we try to read the ones that end with ".conf" if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) { - free(fname); - xasprintf(&fname, "%s" SLASH "%s", dname, ep->d_name); + snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ep->d_name); x = read_config_file(config_tree, fname); } } closedir (dir); } - free(dname); } if(!x && errno) logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno)); - free(fname); - return x; } bool read_host_config(splay_tree_t *config_tree, const char *name) { - char *fname; + char fname[PATH_MAX]; bool x; read_config_options(config_tree, name); - xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); x = read_config_file(config_tree, fname); - free(fname); return x; } bool append_config_file(const char *name, const char *key, const char *value) { - char *fname; - xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); FILE *fp = fopen(fname, "a"); if(!fp) { - logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno)); - } else { - fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value); - fclose(fp); + logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno)); + return false; } - free(fname); - - return fp != NULL; + fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value); + fclose(fp); + return true; } diff --git a/src/conf.h b/src/conf.h index 4f39b20..2478c58 100644 --- a/src/conf.h +++ b/src/conf.h @@ -21,8 +21,9 @@ #ifndef __TINC_CONF_H__ #define __TINC_CONF_H__ -#include "splay_tree.h" #include "list.h" +#include "splay_tree.h" +#include "subnet.h" typedef struct config_t { char *variable; @@ -31,7 +32,6 @@ typedef struct config_t { int line; } config_t; -#include "subnet.h" extern splay_tree_t *config_tree; diff --git a/src/connection.c b/src/connection.c index 496f674..0e61132 100644 --- a/src/connection.c +++ b/src/connection.c @@ -55,14 +55,16 @@ void free_connection(connection_t *c) { if(!c) return; +#ifndef DISABLE_LEGACY cipher_close(c->incipher); digest_close(c->indigest); cipher_close(c->outcipher); digest_close(c->outdigest); + rsa_free(c->rsa); +#endif sptps_stop(&c->sptps); ecdsa_free(c->ecdsa); - rsa_free(c->rsa); free(c->hischallenge); diff --git a/src/connection.h b/src/connection.h index b74b582..7fa769f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -59,9 +59,9 @@ typedef struct connection_status_t { typedef struct connection_t { char *name; /* name he claims to have */ + char *hostname; /* the hostname of its real ip */ union sockaddr_t address; /* his real (internet) ip */ - char *hostname; /* the hostname of its real ip */ int protocol_major; /* used protocol */ int protocol_minor; /* used protocol */ @@ -75,12 +75,15 @@ typedef struct connection_t { struct node_t *node; /* node associated with the other end */ struct edge_t *edge; /* edge associated with this connection */ +#ifndef DISABLE_LEGACY rsa_t *rsa; /* his public RSA key */ - ecdsa_t *ecdsa; /* his public ECDSA key */ cipher_t *incipher; /* Cipher he will use to send data to us */ cipher_t *outcipher; /* Cipher we will use to send data to him */ digest_t *indigest; digest_t *outdigest; +#endif + + ecdsa_t *ecdsa; /* his public ECDSA key */ sptps_t sptps; int inmaclength; @@ -94,6 +97,7 @@ typedef struct connection_t { struct buffer_t outbuf; io_t io; /* input/output event on this metadata connection */ int tcplen; /* length of incoming TCPpacket */ + int sptpslen; /* length of incoming SPTPS packet */ int allow_request; /* defined if there's only one request possible */ time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */ diff --git a/src/cygwin/device.c b/src/cygwin/device.c index 4c3a60d..d3a4303 100644 --- a/src/cygwin/device.c +++ b/src/cygwin/device.c @@ -19,6 +19,7 @@ */ #include "../system.h" +#include "../net.h" #include #include @@ -27,7 +28,6 @@ #include "../device.h" #include "../logger.h" #include "../names.h" -#include "../net.h" #include "../route.h" #include "../utils.h" #include "../xalloc.h" @@ -59,6 +59,9 @@ static bool setup_device(void) { get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Interface"), &iface); + if(device && iface) + logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); + /* Open registry and look for network adapters */ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { diff --git a/src/digest.h b/src/digest.h index 1e14945..204048a 100644 --- a/src/digest.h +++ b/src/digest.h @@ -22,6 +22,8 @@ #define DIGEST_MAX_SIZE 64 +#ifndef DISABLE_LEGACY + typedef struct digest digest_t; extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__ ((__malloc__)); @@ -37,3 +39,5 @@ extern size_t digest_length(const digest_t *); extern bool digest_active(const digest_t *); #endif + +#endif diff --git a/src/dropin.c b/src/dropin.c index 6d40850..fe3b7ef 100644 --- a/src/dropin.c +++ b/src/dropin.c @@ -1,7 +1,7 @@ /* dropin.c -- a set of drop-in replacements for libc functions Copyright (C) 2000-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -86,40 +86,6 @@ int daemon(int nochdir, int noclose) { } #endif -#ifndef HAVE_GET_CURRENT_DIR_NAME -/* - Replacement for the GNU get_current_dir_name function: - - get_current_dir_name will malloc(3) an array big enough to hold the - current directory name. If the environment variable PWD is set, and - its value is correct, then that value will be returned. -*/ -char *get_current_dir_name(void) { - size_t size; - char *buf; - char *r; - - /* Start with 100 bytes. If this turns out to be insufficient to - contain the working directory, double the size. */ - size = 100; - buf = xmalloc(size); - - errno = 0; /* Success */ - r = getcwd(buf, size); - - /* getcwd returns NULL and sets errno to ERANGE if the bufferspace - is insufficient to contain the entire working directory. */ - while(r == NULL && errno == ERANGE) { - free(buf); - size <<= 1; /* double the size */ - buf = xmalloc(size); - r = getcwd(buf, size); - } - - return buf; -} -#endif - #ifndef HAVE_ASPRINTF int asprintf(char **buf, const char *fmt, ...) { int result; @@ -174,10 +140,9 @@ int gettimeofday(struct timeval *tv, void *tz) { } #endif -#ifndef HAVE_USLEEP -int usleep(long long usec) { - struct timeval tv = {usec / 1000000, (usec / 1000) % 1000}; - select(0, NULL, NULL, NULL, &tv); - return 0; +#ifndef HAVE_NANOSLEEP +int nanosleep(const struct timespec *req, struct timespec *rem) { + struct timeval tv = {req->tv_sec, req->tv_nsec / 1000}; + return select(0, NULL, NULL, NULL, &tv); } #endif diff --git a/src/dropin.h b/src/dropin.h index 5601a31..938f30d 100644 --- a/src/dropin.h +++ b/src/dropin.h @@ -1,7 +1,7 @@ /* dropin.h -- header file for dropin.c Copyright (C) 2000-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,17 +21,10 @@ #ifndef __DROPIN_H__ #define __DROPIN_H__ -#include "fake-getaddrinfo.h" -#include "fake-getnameinfo.h" - #ifndef HAVE_DAEMON extern int daemon(int, int); #endif -#ifndef HAVE_GET_CURRENT_DIR_NAME -extern char *get_current_dir_name(void); -#endif - #ifndef HAVE_ASPRINTF extern int asprintf(char **, const char *, ...); extern int vasprintf(char **, const char *, va_list ap); @@ -41,8 +34,8 @@ extern int vasprintf(char **, const char *, va_list ap); extern int gettimeofday(struct timeval *, void *); #endif -#ifndef HAVE_USLEEP -extern int usleep(long long usec); +#ifndef HAVE_NANOSLEEP +extern int nanosleep(const struct timespec *req, struct timespec *rem); #endif #ifndef timeradd @@ -70,4 +63,8 @@ extern int usleep(long long usec); #endif #endif +#ifndef EAI_SYSTEM +#define EAI_SYSTEM 0 +#endif + #endif /* __DROPIN_H__ */ diff --git a/src/ed25519/ecdsa.c b/src/ed25519/ecdsa.c index bfdabc1..f8aafe4 100644 --- a/src/ed25519/ecdsa.c +++ b/src/ed25519/ecdsa.c @@ -84,11 +84,13 @@ static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) { size_t len = b64decode(line, line, linelen); if(!len) { logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n"); + errno = EINVAL; return false; } if(len > size) { logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n"); + errno = EINVAL; return false; } @@ -98,7 +100,12 @@ static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) { } if(size) { - logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n"); + if(data) { + errno = EINVAL; + logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n"); + } else { + errno = ENOENT; + } return false; } diff --git a/src/ed25519/fe.c b/src/ed25519/fe.c index 448e3e9..1c459f4 100644 --- a/src/ed25519/fe.c +++ b/src/ed25519/fe.c @@ -8,9 +8,9 @@ static uint64_t load_3(const unsigned char *in) { uint64_t result; - result = (uint64_t) in[0]; - result |= ((uint64_t) in[1]) << 8; - result |= ((uint64_t) in[2]) << 16; + result = in[0]; + result |= shlu64(in[1], 8); + result |= shlu64(in[2], 16); return result; } @@ -18,10 +18,10 @@ static uint64_t load_3(const unsigned char *in) { static uint64_t load_4(const unsigned char *in) { uint64_t result; - result = (uint64_t) in[0]; - result |= ((uint64_t) in[1]) << 8; - result |= ((uint64_t) in[2]) << 16; - result |= ((uint64_t) in[3]) << 24; + result = in[0]; + result |= shlu64(in[1], 8); + result |= shlu64(in[2], 16); + result |= shlu64(in[3], 24); return result; } @@ -316,47 +316,47 @@ void fe_frombytes(fe h, const unsigned char *s) { int64_t carry8; int64_t carry9; - carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + carry9 = (h9 + (1L << 24)) >> 25; h0 += carry9 * 19; - h9 -= carry9 << 25; - carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h9 -= shl64(carry9, 25); + carry1 = (h1 + (1L << 24)) >> 25; h2 += carry1; - h1 -= carry1 << 25; - carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h1 -= shl64(carry1, 25); + carry3 = (h3 + (1L << 24)) >> 25; h4 += carry3; - h3 -= carry3 << 25; - carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h3 -= shl64(carry3, 25); + carry5 = (h5 + (1L << 24)) >> 25; h6 += carry5; - h5 -= carry5 << 25; - carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h5 -= shl64(carry5, 25); + carry7 = (h7 + (1L << 24)) >> 25; h8 += carry7; - h7 -= carry7 << 25; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h7 -= shl64(carry7, 25); + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; - carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h0 -= shl64(carry0, 26); + carry2 = (h2 + (1L << 25)) >> 26; h3 += carry2; - h2 -= carry2 << 26; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h2 -= shl64(carry2, 26); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h4 -= shl64(carry4, 26); + carry6 = (h6 + (1L << 25)) >> 26; h7 += carry6; - h6 -= carry6 << 26; - carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h6 -= shl64(carry6, 26); + carry8 = (h8 + (1L << 25)) >> 26; h9 += carry8; - h8 -= carry8 << 26; + h8 -= shl64(carry8, 26); - h[0] = (int32_t) h0; - h[1] = (int32_t) h1; - h[2] = (int32_t) h2; - h[3] = (int32_t) h3; - h[4] = (int32_t) h4; - h[5] = (int32_t) h5; - h[6] = (int32_t) h6; - h[7] = (int32_t) h7; - h[8] = (int32_t) h8; - h[9] = (int32_t) h9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; } @@ -709,48 +709,48 @@ void fe_mul(fe h, const fe f, const fe g) { int64_t carry8; int64_t carry9; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h0 -= shl64(carry0, 26); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; + h4 -= shl64(carry4, 26); - carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + carry1 = (h1 + (1L << 24)) >> 25; h2 += carry1; - h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h1 -= shl64(carry1, 25); + carry5 = (h5 + (1L << 24)) >> 25; h6 += carry5; - h5 -= carry5 << 25; + h5 -= shl64(carry5, 25); - carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + carry2 = (h2 + (1L << 25)) >> 26; h3 += carry2; - h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h2 -= shl64(carry2, 26); + carry6 = (h6 + (1L << 25)) >> 26; h7 += carry6; - h6 -= carry6 << 26; + h6 -= shl64(carry6, 26); - carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + carry3 = (h3 + (1L << 24)) >> 25; h4 += carry3; - h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h3 -= shl64(carry3, 25); + carry7 = (h7 + (1L << 24)) >> 25; h8 += carry7; - h7 -= carry7 << 25; + h7 -= shl64(carry7, 25); - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h4 -= shl64(carry4, 26); + carry8 = (h8 + (1L << 25)) >> 26; h9 += carry8; - h8 -= carry8 << 26; + h8 -= shl64(carry8, 26); - carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + carry9 = (h9 + (1L << 24)) >> 25; h0 += carry9 * 19; - h9 -= carry9 << 25; + h9 -= shl64(carry9, 25); - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; + h0 -= shl64(carry0, 26); h[0] = (int32_t) h0; h[1] = (int32_t) h1; @@ -808,17 +808,17 @@ void fe_mul121666(fe h, fe f) { int64_t carry8; int64_t carry9; - carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; - carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; - carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; - carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; - carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= shl64(carry9, 25); + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= shl64(carry1, 25); + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= shl64(carry3, 25); + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= shl64(carry5, 25); + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= shl64(carry7, 25); - carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; - carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; - carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; - carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; - carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= shl64(carry0, 26); + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= shl64(carry2, 26); + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= shl64(carry4, 26); + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= shl64(carry6, 26); + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= shl64(carry8, 26); h[0] = h0; h[1] = h1; @@ -1078,42 +1078,42 @@ void fe_sq(fe h, const fe f) { int64_t carry7; int64_t carry8; int64_t carry9; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h0 -= shl64(carry0, 26); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h4 -= shl64(carry4, 26); + carry1 = (h1 + (1L << 24)) >> 25; h2 += carry1; - h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h1 -= shl64(carry1, 25); + carry5 = (h5 + (1L << 24)) >> 25; h6 += carry5; - h5 -= carry5 << 25; - carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h5 -= shl64(carry5, 25); + carry2 = (h2 + (1L << 25)) >> 26; h3 += carry2; - h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h2 -= shl64(carry2, 26); + carry6 = (h6 + (1L << 25)) >> 26; h7 += carry6; - h6 -= carry6 << 26; - carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h6 -= shl64(carry6, 26); + carry3 = (h3 + (1L << 24)) >> 25; h4 += carry3; - h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h3 -= shl64(carry3, 25); + carry7 = (h7 + (1L << 24)) >> 25; h8 += carry7; - h7 -= carry7 << 25; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h7 -= shl64(carry7, 25); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h4 -= shl64(carry4, 26); + carry8 = (h8 + (1L << 25)) >> 26; h9 += carry8; - h8 -= carry8 << 26; - carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h8 -= shl64(carry8, 26); + carry9 = (h9 + (1L << 24)) >> 25; h0 += carry9 * 19; - h9 -= carry9 << 25; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h9 -= shl64(carry9, 25); + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; + h0 -= shl64(carry0, 26); h[0] = (int32_t) h0; h[1] = (int32_t) h1; h[2] = (int32_t) h2; @@ -1251,42 +1251,42 @@ void fe_sq2(fe h, const fe f) { h7 += h7; h8 += h8; h9 += h9; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h0 -= shl64(carry0, 26); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h4 -= shl64(carry4, 26); + carry1 = (h1 + (1L << 24)) >> 25; h2 += carry1; - h1 -= carry1 << 25; - carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h1 -= shl64(carry1, 25); + carry5 = (h5 + (1L << 24)) >> 25; h6 += carry5; - h5 -= carry5 << 25; - carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h5 -= shl64(carry5, 25); + carry2 = (h2 + (1L << 25)) >> 26; h3 += carry2; - h2 -= carry2 << 26; - carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h2 -= shl64(carry2, 26); + carry6 = (h6 + (1L << 25)) >> 26; h7 += carry6; - h6 -= carry6 << 26; - carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h6 -= shl64(carry6, 26); + carry3 = (h3 + (1L << 24)) >> 25; h4 += carry3; - h3 -= carry3 << 25; - carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h3 -= shl64(carry3, 25); + carry7 = (h7 + (1L << 24)) >> 25; h8 += carry7; - h7 -= carry7 << 25; - carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h7 -= shl64(carry7, 25); + carry4 = (h4 + (1L << 25)) >> 26; h5 += carry4; - h4 -= carry4 << 26; - carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h4 -= shl64(carry4, 26); + carry8 = (h8 + (1L << 25)) >> 26; h9 += carry8; - h8 -= carry8 << 26; - carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h8 -= shl64(carry8, 26); + carry9 = (h9 + (1L << 24)) >> 25; h0 += carry9 * 19; - h9 -= carry9 << 25; - carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h9 -= shl64(carry9, 25); + carry0 = (h0 + (1L << 25)) >> 26; h1 += carry0; - h0 -= carry0 << 26; + h0 -= shl64(carry0, 26); h[0] = (int32_t) h0; h[1] = (int32_t) h1; h[2] = (int32_t) h2; @@ -1421,33 +1421,33 @@ void fe_tobytes(unsigned char *s, const fe h) { /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ carry0 = h0 >> 26; h1 += carry0; - h0 -= carry0 << 26; + h0 -= shl32(carry0, 26); carry1 = h1 >> 25; h2 += carry1; - h1 -= carry1 << 25; + h1 -= shl32(carry1, 25); carry2 = h2 >> 26; h3 += carry2; - h2 -= carry2 << 26; + h2 -= shl32(carry2, 26); carry3 = h3 >> 25; h4 += carry3; - h3 -= carry3 << 25; + h3 -= shl32(carry3, 25); carry4 = h4 >> 26; h5 += carry4; - h4 -= carry4 << 26; + h4 -= shl32(carry4, 26); carry5 = h5 >> 25; h6 += carry5; - h5 -= carry5 << 25; + h5 -= shl32(carry5, 25); carry6 = h6 >> 26; h7 += carry6; - h6 -= carry6 << 26; + h6 -= shl32(carry6, 26); carry7 = h7 >> 25; h8 += carry7; - h7 -= carry7 << 25; + h7 -= shl32(carry7, 25); carry8 = h8 >> 26; h9 += carry8; - h8 -= carry8 << 26; + h8 -= shl32(carry8, 26); carry9 = h9 >> 25; - h9 -= carry9 << 25; + h9 -= shl32(carry9, 25); /* h10 = carry9 */ /* @@ -1459,32 +1459,32 @@ void fe_tobytes(unsigned char *s, const fe h) { s[0] = (unsigned char) (h0 >> 0); s[1] = (unsigned char) (h0 >> 8); s[2] = (unsigned char) (h0 >> 16); - s[3] = (unsigned char) ((h0 >> 24) | (h1 << 2)); + s[3] = (unsigned char) ((h0 >> 24) | shl32(h1, 2)); s[4] = (unsigned char) (h1 >> 6); s[5] = (unsigned char) (h1 >> 14); - s[6] = (unsigned char) ((h1 >> 22) | (h2 << 3)); + s[6] = (unsigned char) ((h1 >> 22) | shl32(h2, 3)); s[7] = (unsigned char) (h2 >> 5); s[8] = (unsigned char) (h2 >> 13); - s[9] = (unsigned char) ((h2 >> 21) | (h3 << 5)); + s[9] = (unsigned char) ((h2 >> 21) | shl32(h3, 5)); s[10] = (unsigned char) (h3 >> 3); s[11] = (unsigned char) (h3 >> 11); - s[12] = (unsigned char) ((h3 >> 19) | (h4 << 6)); + s[12] = (unsigned char) ((h3 >> 19) | shl32(h4, 6)); s[13] = (unsigned char) (h4 >> 2); s[14] = (unsigned char) (h4 >> 10); s[15] = (unsigned char) (h4 >> 18); s[16] = (unsigned char) (h5 >> 0); s[17] = (unsigned char) (h5 >> 8); s[18] = (unsigned char) (h5 >> 16); - s[19] = (unsigned char) ((h5 >> 24) | (h6 << 1)); + s[19] = (unsigned char) ((h5 >> 24) | shl32(h6, 1)); s[20] = (unsigned char) (h6 >> 7); s[21] = (unsigned char) (h6 >> 15); - s[22] = (unsigned char) ((h6 >> 23) | (h7 << 3)); + s[22] = (unsigned char) ((h6 >> 23) | shl32(h7, 3)); s[23] = (unsigned char) (h7 >> 5); s[24] = (unsigned char) (h7 >> 13); - s[25] = (unsigned char) ((h7 >> 21) | (h8 << 4)); + s[25] = (unsigned char) ((h7 >> 21) | shl32(h8, 4)); s[26] = (unsigned char) (h8 >> 4); s[27] = (unsigned char) (h8 >> 12); - s[28] = (unsigned char) ((h8 >> 20) | (h9 << 6)); + s[28] = (unsigned char) ((h8 >> 20) | shl32(h9, 6)); s[29] = (unsigned char) (h9 >> 2); s[30] = (unsigned char) (h9 >> 10); s[31] = (unsigned char) (h9 >> 18); diff --git a/src/ed25519/fixedint.h b/src/ed25519/fixedint.h index d03e4bd..8abced0 100644 --- a/src/ed25519/fixedint.h +++ b/src/ed25519/fixedint.h @@ -4,6 +4,9 @@ Not a compatible replacement for , do not blindly use it as such. */ +#ifndef __TINC_FIXEDINT_H__ +#define __TINC_FIXEDINT_H__ + #if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED) #include #define FIXEDINT_H_INCLUDED @@ -68,3 +71,21 @@ #define INT64_C(v) v ##I64 #endif #endif + +static inline unsigned char shlu8(unsigned char a, uint32_t b) { + return a << b; +} + +static inline int32_t shl32(uint32_t a, uint32_t b) { + return a << b; +} + +static inline int64_t shl64(uint64_t a, uint32_t b) { + return a << b; +} + +static inline uint64_t shlu64(uint64_t a, uint32_t b) { + return a << b; +} + +#endif diff --git a/src/ed25519/ge.c b/src/ed25519/ge.c index 3c342b1..9488218 100644 --- a/src/ed25519/ge.c +++ b/src/ed25519/ge.c @@ -356,7 +356,7 @@ static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) { static void select(ge_precomp *t, int pos, signed char b) { ge_precomp minust; unsigned char bnegative = negative(b); - unsigned char babs = b - (((-bnegative) & b) << 1); + unsigned char babs = b - shlu8(((-bnegative) & b), 1); fe_1(t->yplusx); fe_1(t->yminusx); fe_0(t->xy2d); @@ -404,7 +404,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { e[i] += carry; carry = e[i] + 8; carry >>= 4; - e[i] -= carry << 4; + e[i] -= shl32(carry, 4); } e[63] += carry; diff --git a/src/ed25519/precomp_data.h b/src/ed25519/precomp_data.h index 776b84f..ce59788 100644 --- a/src/ed25519/precomp_data.h +++ b/src/ed25519/precomp_data.h @@ -1388,4 +1388,4 @@ static ge_precomp base[32][8] = { { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 }, }, }, -}; \ No newline at end of file +}; diff --git a/src/ed25519/sc.c b/src/ed25519/sc.c index ca5bad2..42cfc2d 100644 --- a/src/ed25519/sc.c +++ b/src/ed25519/sc.c @@ -4,9 +4,9 @@ static uint64_t load_3(const unsigned char *in) { uint64_t result; - result = (uint64_t) in[0]; - result |= ((uint64_t) in[1]) << 8; - result |= ((uint64_t) in[2]) << 16; + result = in[0]; + result |= shlu64(in[1], 8); + result |= shlu64(in[2], 16); return result; } @@ -14,10 +14,10 @@ static uint64_t load_3(const unsigned char *in) { static uint64_t load_4(const unsigned char *in) { uint64_t result; - result = (uint64_t) in[0]; - result |= ((uint64_t) in[1]) << 8; - result |= ((uint64_t) in[2]) << 16; - result |= ((uint64_t) in[3]) << 24; + result = in[0]; + result |= shlu64(in[1], 8); + result |= shlu64(in[2], 16); + result |= shlu64(in[3], 24); return result; } @@ -119,37 +119,37 @@ void sc_reduce(unsigned char *s) { s18 = 0; carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; - s12 -= carry12 << 21; + s12 -= shl64(carry12, 21); carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; - s14 -= carry14 << 21; + s14 -= shl64(carry14, 21); carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; - s16 -= carry16 << 21; + s16 -= shl64(carry16, 21); carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; - s13 -= carry13 << 21; + s13 -= shl64(carry13, 21); carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; - s15 -= carry15 << 21; + s15 -= shl64(carry15, 21); s5 += s17 * 666643; s6 += s17 * 470296; s7 += s17 * 654183; @@ -194,40 +194,40 @@ void sc_reduce(unsigned char *s) { s12 = 0; carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; @@ -237,40 +237,40 @@ void sc_reduce(unsigned char *s) { s12 = 0; carry0 = s0 >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry1 = s1 >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry2 = s2 >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry3 = s3 >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry4 = s4 >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry5 = s5 >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry6 = s6 >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry7 = s7 >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry8 = s8 >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry9 = s9 >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry10 = s10 >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry11 = s11 >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; @@ -280,67 +280,67 @@ void sc_reduce(unsigned char *s) { s12 = 0; carry0 = s0 >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry1 = s1 >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry2 = s2 >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry3 = s3 >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry4 = s4 >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry5 = s5 >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry6 = s6 >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry7 = s7 >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry8 = s8 >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry9 = s9 >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry10 = s10 >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); s[0] = (unsigned char) (s0 >> 0); s[1] = (unsigned char) (s0 >> 8); - s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5)); + s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5)); s[3] = (unsigned char) (s1 >> 3); s[4] = (unsigned char) (s1 >> 11); - s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2)); + s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2)); s[6] = (unsigned char) (s2 >> 6); - s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7)); + s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7)); s[8] = (unsigned char) (s3 >> 1); s[9] = (unsigned char) (s3 >> 9); - s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4)); + s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4)); s[11] = (unsigned char) (s4 >> 4); s[12] = (unsigned char) (s4 >> 12); - s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1)); + s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1)); s[14] = (unsigned char) (s5 >> 7); - s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6)); + s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6)); s[16] = (unsigned char) (s6 >> 2); s[17] = (unsigned char) (s6 >> 10); - s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3)); + s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3)); s[19] = (unsigned char) (s7 >> 5); s[20] = (unsigned char) (s7 >> 13); s[21] = (unsigned char) (s8 >> 0); s[22] = (unsigned char) (s8 >> 8); - s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5)); + s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5)); s[24] = (unsigned char) (s9 >> 3); s[25] = (unsigned char) (s9 >> 11); - s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2)); + s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2)); s[27] = (unsigned char) (s10 >> 6); - s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7)); + s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7)); s[29] = (unsigned char) (s11 >> 1); s[30] = (unsigned char) (s11 >> 9); s[31] = (unsigned char) (s11 >> 17); @@ -470,73 +470,73 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, s23 = 0; carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; - s12 -= carry12 << 21; + s12 -= shl64(carry12, 21); carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; - s14 -= carry14 << 21; + s14 -= shl64(carry14, 21); carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; - s16 -= carry16 << 21; + s16 -= shl64(carry16, 21); carry18 = (s18 + (1 << 20)) >> 21; s19 += carry18; - s18 -= carry18 << 21; + s18 -= shl64(carry18, 21); carry20 = (s20 + (1 << 20)) >> 21; s21 += carry20; - s20 -= carry20 << 21; + s20 -= shl64(carry20, 21); carry22 = (s22 + (1 << 20)) >> 21; s23 += carry22; - s22 -= carry22 << 21; + s22 -= shl64(carry22, 21); carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; - s13 -= carry13 << 21; + s13 -= shl64(carry13, 21); carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; - s15 -= carry15 << 21; + s15 -= shl64(carry15, 21); carry17 = (s17 + (1 << 20)) >> 21; s18 += carry17; - s17 -= carry17 << 21; + s17 -= shl64(carry17, 21); carry19 = (s19 + (1 << 20)) >> 21; s20 += carry19; - s19 -= carry19 << 21; + s19 -= shl64(carry19, 21); carry21 = (s21 + (1 << 20)) >> 21; s22 += carry21; - s21 -= carry21 << 21; + s21 -= shl64(carry21, 21); s11 += s23 * 666643; s12 += s23 * 470296; s13 += s23 * 654183; @@ -581,37 +581,37 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, s18 = 0; carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; - s12 -= carry12 << 21; + s12 -= shl64(carry12, 21); carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; - s14 -= carry14 << 21; + s14 -= shl64(carry14, 21); carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; - s16 -= carry16 << 21; + s16 -= shl64(carry16, 21); carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; - s13 -= carry13 << 21; + s13 -= shl64(carry13, 21); carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; - s15 -= carry15 << 21; + s15 -= shl64(carry15, 21); s5 += s17 * 666643; s6 += s17 * 470296; s7 += s17 * 654183; @@ -656,40 +656,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, s12 = 0; carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; @@ -699,40 +699,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, s12 = 0; carry0 = s0 >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry1 = s1 >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry2 = s2 >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry3 = s3 >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry4 = s4 >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry5 = s5 >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry6 = s6 >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry7 = s7 >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry8 = s8 >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry9 = s9 >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry10 = s10 >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); carry11 = s11 >> 21; s12 += carry11; - s11 -= carry11 << 21; + s11 -= shl64(carry11, 21); s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; @@ -742,67 +742,67 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, s12 = 0; carry0 = s0 >> 21; s1 += carry0; - s0 -= carry0 << 21; + s0 -= shl64(carry0, 21); carry1 = s1 >> 21; s2 += carry1; - s1 -= carry1 << 21; + s1 -= shl64(carry1, 21); carry2 = s2 >> 21; s3 += carry2; - s2 -= carry2 << 21; + s2 -= shl64(carry2, 21); carry3 = s3 >> 21; s4 += carry3; - s3 -= carry3 << 21; + s3 -= shl64(carry3, 21); carry4 = s4 >> 21; s5 += carry4; - s4 -= carry4 << 21; + s4 -= shl64(carry4, 21); carry5 = s5 >> 21; s6 += carry5; - s5 -= carry5 << 21; + s5 -= shl64(carry5, 21); carry6 = s6 >> 21; s7 += carry6; - s6 -= carry6 << 21; + s6 -= shl64(carry6, 21); carry7 = s7 >> 21; s8 += carry7; - s7 -= carry7 << 21; + s7 -= shl64(carry7, 21); carry8 = s8 >> 21; s9 += carry8; - s8 -= carry8 << 21; + s8 -= shl64(carry8, 21); carry9 = s9 >> 21; s10 += carry9; - s9 -= carry9 << 21; + s9 -= shl64(carry9, 21); carry10 = s10 >> 21; s11 += carry10; - s10 -= carry10 << 21; + s10 -= shl64(carry10, 21); s[0] = (unsigned char) (s0 >> 0); s[1] = (unsigned char) (s0 >> 8); - s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5)); + s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5)); s[3] = (unsigned char) (s1 >> 3); s[4] = (unsigned char) (s1 >> 11); - s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2)); + s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2)); s[6] = (unsigned char) (s2 >> 6); - s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7)); + s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7)); s[8] = (unsigned char) (s3 >> 1); s[9] = (unsigned char) (s3 >> 9); - s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4)); + s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4)); s[11] = (unsigned char) (s4 >> 4); s[12] = (unsigned char) (s4 >> 12); - s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1)); + s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1)); s[14] = (unsigned char) (s5 >> 7); - s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6)); + s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6)); s[16] = (unsigned char) (s6 >> 2); s[17] = (unsigned char) (s6 >> 10); - s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3)); + s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3)); s[19] = (unsigned char) (s7 >> 5); s[20] = (unsigned char) (s7 >> 13); s[21] = (unsigned char) (s8 >> 0); s[22] = (unsigned char) (s8 >> 8); - s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5)); + s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5)); s[24] = (unsigned char) (s9 >> 3); s[25] = (unsigned char) (s9 >> 11); - s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2)); + s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2)); s[27] = (unsigned char) (s10 >> 6); - s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7)); + s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7)); s[29] = (unsigned char) (s11 >> 1); s[30] = (unsigned char) (s11 >> 9); s[31] = (unsigned char) (s11 >> 17); diff --git a/src/ed25519/sc.h b/src/ed25519/sc.h index 8fa727e..e29e7fa 100644 --- a/src/ed25519/sc.h +++ b/src/ed25519/sc.h @@ -9,4 +9,4 @@ where l = 2^252 + 27742317777372353535851937790883648493. void sc_reduce(unsigned char *s); void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c); -#endif \ No newline at end of file +#endif diff --git a/src/ed25519/sha512.c b/src/ed25519/sha512.c index cb8ae71..e1db1e5 100644 --- a/src/ed25519/sha512.c +++ b/src/ed25519/sha512.c @@ -14,45 +14,45 @@ /* the K array */ static const uint64_t K[80] = { - UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), - UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), - UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), - UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), - UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), - UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), - UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), - UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), - UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), - UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), - UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), - UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), - UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), - UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), - UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), - UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), - UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), - UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), - UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) }; @@ -76,7 +76,7 @@ static const uint64_t K[80] = { #define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) ROR64c(x, n) #define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) @@ -88,7 +88,7 @@ static const uint64_t K[80] = { #endif /* compress 1024-bits */ -static int sha512_compress(sha512_context *md, unsigned char *buf) +static int sha512_compress(sha512_context *md, const unsigned char *buf) { uint64_t S[8], W[80], t0, t1; int i; @@ -106,7 +106,7 @@ static int sha512_compress(sha512_context *md, unsigned char *buf) /* fill W[16..79] */ for (i = 16; i < 80; i++) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } + } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i) \ @@ -168,25 +168,26 @@ int sha512_init(sha512_context * md) { @param inlen The length of the data (octets) @return 0 if successful */ -int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) -{ +int sha512_update(sha512_context *md, const void *vin, size_t inlen) +{ + const unsigned char *in = vin; size_t n; - size_t i; - int err; - if (md == NULL) return 1; - if (in == NULL) return 1; - if (md->curlen > sizeof(md->buf)) { - return 1; - } - while (inlen > 0) { - if (md->curlen == 0 && inlen >= 128) { - if ((err = sha512_compress (md, (unsigned char *)in)) != 0) { - return err; - } - md->length += 128 * 8; - in += 128; - inlen -= 128; - } else { + size_t i; + int err; + if (md == NULL) return 1; + if (in == NULL) return 1; + if (md->curlen > sizeof(md->buf)) { + return 1; + } + while (inlen > 0) { + if (md->curlen == 0 && inlen >= 128) { + if ((err = sha512_compress (md, in)) != 0) { + return err; + } + md->length += 128 * 8; + in += 128; + inlen -= 128; + } else { n = MIN(inlen, (128 - md->curlen)); for (i = 0; i < n; i++) { @@ -194,19 +195,19 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) } - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == 128) { - if ((err = sha512_compress (md, md->buf)) != 0) { - return err; - } - md->length += 8*128; - md->curlen = 0; - } - } - } - return 0; + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == 128) { + if ((err = sha512_compress (md, md->buf)) != 0) { + return err; + } + md->length += 8*128; + md->curlen = 0; + } + } + } + return 0; } /** @@ -215,22 +216,23 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) @param out [out] The destination of the hash (64 bytes) @return 0 if successful */ - int sha512_final(sha512_context * md, unsigned char *out) - { +int sha512_final(sha512_context * md, void *vout) +{ int i; + unsigned char *out = vout; if (md == NULL) return 1; if (out == NULL) return 1; if (md->curlen >= sizeof(md->buf)) { - return 1; - } + return 1; + } /* increase the length of the message */ - md->length += md->curlen * UINT64_C(8); + md->length += md->curlen * UINT64_C(8); /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char)0x80; + md->buf[md->curlen++] = (unsigned char)0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length @@ -244,27 +246,27 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) md->curlen = 0; } - /* pad upto 120 bytes of zeroes + /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ -while (md->curlen < 120) { - md->buf[md->curlen++] = (unsigned char)0; -} + while (md->curlen < 120) { + md->buf[md->curlen++] = (unsigned char)0; + } /* store length */ -STORE64H(md->length, md->buf+120); -sha512_compress(md, md->buf); + STORE64H(md->length, md->buf+120); + sha512_compress(md, md->buf); /* copy output */ -for (i = 0; i < 8; i++) { - STORE64H(md->state[i], out+(8*i)); + for (i = 0; i < 8; i++) { + STORE64H(md->state[i], out+(8*i)); + } + + return 0; } -return 0; -} - -int sha512(const unsigned char *message, size_t message_len, unsigned char *out) +int sha512(const void *message, size_t message_len, void *out) { sha512_context ctx; int ret; diff --git a/src/ed25519/sha512.h b/src/ed25519/sha512.h index e56b00e..e23f8db 100644 --- a/src/ed25519/sha512.h +++ b/src/ed25519/sha512.h @@ -14,8 +14,8 @@ typedef struct sha512_context_ { int sha512_init(sha512_context * md); -int sha512_final(sha512_context * md, unsigned char *out); -int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen); -int sha512(const unsigned char *message, size_t message_len, unsigned char *out); +int sha512_final(sha512_context * md, void *out); +int sha512_update(sha512_context * md, const void *in, size_t inlen); +int sha512(const void *message, size_t message_len, void *out); -#endif \ No newline at end of file +#endif diff --git a/src/edge.c b/src/edge.c index 2eaae5d..0e35cd1 100644 --- a/src/edge.c +++ b/src/edge.c @@ -75,6 +75,7 @@ edge_t *new_edge(void) { void free_edge(edge_t *e) { sockaddrfree(&e->address); + sockaddrfree(&e->local_address); free(e); } diff --git a/src/ethernet.h b/src/ethernet.h index a8b6420..085e96a 100644 --- a/src/ethernet.h +++ b/src/ethernet.h @@ -50,7 +50,7 @@ struct ether_header { uint8_t ether_dhost[ETH_ALEN]; uint8_t ether_shost[ETH_ALEN]; uint16_t ether_type; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #endif #ifndef HAVE_STRUCT_ARPHDR @@ -60,7 +60,7 @@ struct arphdr { uint8_t ar_hln; uint8_t ar_pln; uint16_t ar_op; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #define ARPOP_REQUEST 1 #define ARPOP_REPLY 2 @@ -78,7 +78,7 @@ struct ether_arp { uint8_t arp_spa[4]; uint8_t arp_tha[ETH_ALEN]; uint8_t arp_tpa[4]; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #define arp_hrd ea_hdr.ar_hrd #define arp_pro ea_hdr.ar_pro #define arp_hln ea_hdr.ar_hln diff --git a/src/event.c b/src/event.c index 60d357d..59b96e3 100644 --- a/src/event.c +++ b/src/event.c @@ -285,6 +285,16 @@ bool event_loop(void) { io->cb(io->data, IO_WRITE); else if(FD_ISSET(io->fd, &readable)) io->cb(io->data, IO_READ); + else + continue; + + /* + There are scenarios in which the callback will remove another io_t from the tree + (e.g. closing a double connection). Since splay_each does not support that, we + need to exit the loop now. That's okay, since any remaining events will get picked + up by the next select() call. + */ + break; } } #else diff --git a/src/fake-gai-errnos.h b/src/fake-gai-errnos.h deleted file mode 100644 index 2f41d8f..0000000 --- a/src/fake-gai-errnos.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * fake library for ssh - * - * This file is included in getaddrinfo.c and getnameinfo.c. - * See getaddrinfo.c and getnameinfo.c. - */ - -/* for old netdb.h */ -#ifndef EAI_NODATA -#define EAI_NODATA 1 -#endif - -#ifndef EAI_MEMORY -#define EAI_MEMORY 2 -#endif - -#ifndef EAI_FAMILY -#define EAI_FAMILY 3 -#endif - -#ifndef EAI_SYSTEM -#define EAI_SYSTEM 4 -#endif diff --git a/src/fake-getaddrinfo.c b/src/fake-getaddrinfo.c deleted file mode 100644 index cb821b5..0000000 --- a/src/fake-getaddrinfo.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * fake library for ssh - * - * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror(). - * These funtions are defined in rfc2133. - * - * But these functions are not implemented correctly. The minimum subset - * is implemented for ssh use only. For exapmle, this routine assumes - * that ai_family is AF_INET. Don't use it for another purpose. - */ - -#include "system.h" - -#include "ipv4.h" -#include "ipv6.h" -#include "fake-getaddrinfo.h" -#include "xalloc.h" - - -#if !HAVE_DECL_GAI_STRERROR -char *gai_strerror(int ecode) { - switch (ecode) { - case EAI_NODATA: - return "No address associated with hostname"; - case EAI_MEMORY: - return "Memory allocation failure"; - case EAI_FAMILY: - return "Address family not supported"; - default: - return "Unknown error"; - } -} -#endif /* !HAVE_GAI_STRERROR */ - -#if !HAVE_DECL_FREEADDRINFO -void freeaddrinfo(struct addrinfo *ai) { - struct addrinfo *next; - - while(ai) { - next = ai->ai_next; - free(ai); - ai = next; - } -} -#endif /* !HAVE_FREEADDRINFO */ - -#if !HAVE_DECL_GETADDRINFO -static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) { - struct addrinfo *ai; - - ai = xzalloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); - - ai->ai_addr = (struct sockaddr *)(ai + 1); - ai->ai_addrlen = sizeof(struct sockaddr_in); - ai->ai_addr->sa_family = ai->ai_family = AF_INET; - - ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; - ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; - - return ai; -} - -int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { - struct addrinfo *prev = NULL; - struct hostent *hp; - struct in_addr in = {0}; - int i; - uint16_t port = 0; - - if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) - return EAI_FAMILY; - - if (servname) - port = htons(atoi(servname)); - - if (hints && hints->ai_flags & AI_PASSIVE) { - *res = malloc_ai(port, htonl(0x00000000)); - return 0; - } - - if (!hostname) { - *res = malloc_ai(port, htonl(0x7f000001)); - return 0; - } - - hp = gethostbyname(hostname); - - if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) - return EAI_NODATA; - - for (i = 0; hp->h_addr_list[i]; i++) { - *res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr); - - if(prev) - prev->ai_next = *res; - - prev = *res; - } - - return 0; -} -#endif /* !HAVE_GETADDRINFO */ diff --git a/src/fake-getaddrinfo.h b/src/fake-getaddrinfo.h deleted file mode 100644 index 5809985..0000000 --- a/src/fake-getaddrinfo.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _FAKE_GETADDRINFO_H -#define _FAKE_GETADDRINFO_H - -#include "fake-gai-errnos.h" - -#ifndef AI_PASSIVE -# define AI_PASSIVE 1 -# define AI_CANONNAME 2 -#endif - -#ifndef NI_NUMERICHOST -# define NI_NUMERICHOST 2 -# define NI_NAMEREQD 4 -# define NI_NUMERICSERV 8 -#endif - -#ifndef AI_NUMERICHOST -#define AI_NUMERICHOST 4 -#endif - -#ifndef HAVE_STRUCT_ADDRINFO -struct addrinfo { - int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - size_t ai_addrlen; /* length of ai_addr */ - char *ai_canonname; /* canonical name for hostname */ - struct sockaddr *ai_addr; /* binary address */ - struct addrinfo *ai_next; /* next structure in linked list */ -}; -#endif /* !HAVE_STRUCT_ADDRINFO */ - -#if !HAVE_DECL_GETADDRINFO -int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res); -#endif /* !HAVE_GETADDRINFO */ - -#if !HAVE_DECL_GAI_STRERROR -char *gai_strerror(int ecode); -#endif /* !HAVE_GAI_STRERROR */ - -#if !HAVE_DECL_FREEADDRINFO -void freeaddrinfo(struct addrinfo *ai); -#endif /* !HAVE_FREEADDRINFO */ - -#endif /* _FAKE_GETADDRINFO_H */ diff --git a/src/fake-getnameinfo.c b/src/fake-getnameinfo.c deleted file mode 100644 index 4a4d132..0000000 --- a/src/fake-getnameinfo.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * fake library for ssh - * - * This file includes getnameinfo(). - * These funtions are defined in rfc2133. - * - * But these functions are not implemented correctly. The minimum subset - * is implemented for ssh use only. For exapmle, this routine assumes - * that ai_family is AF_INET. Don't use it for another purpose. - */ - -#include "system.h" - -#include "fake-getnameinfo.h" -#include "fake-getaddrinfo.h" - -#if !HAVE_DECL_GETNAMEINFO - -int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - struct hostent *hp; - int len; - - if(sa->sa_family != AF_INET) - return EAI_FAMILY; - - if(serv && servlen) { - len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); - if(len < 0 || len >= servlen) - return EAI_MEMORY; - } - - if(!host || !hostlen) - return 0; - - if(flags & NI_NUMERICHOST) { - len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); - if(len < 0 || len >= hostlen) - return EAI_MEMORY; - return 0; - } - - hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); - - if(!hp || !hp->h_name || !hp->h_name[0]) - return EAI_NODATA; - - len = snprintf(host, hostlen, "%s", hp->h_name); - if(len < 0 || len >= hostlen) - return EAI_MEMORY; - - return 0; -} -#endif /* !HAVE_GETNAMEINFO */ diff --git a/src/fake-getnameinfo.h b/src/fake-getnameinfo.h deleted file mode 100644 index 043ed97..0000000 --- a/src/fake-getnameinfo.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _FAKE_GETNAMEINFO_H -#define _FAKE_GETNAMEINFO_H - -#if !HAVE_DECL_GETNAMEINFO -int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); -#endif /* !HAVE_GETNAMEINFO */ - -#ifndef NI_MAXSERV -# define NI_MAXSERV 32 -#endif /* !NI_MAXSERV */ -#ifndef NI_MAXHOST -# define NI_MAXHOST 1025 -#endif /* !NI_MAXHOST */ - -#endif /* _FAKE_GETNAMEINFO_H */ diff --git a/src/fsck.c b/src/fsck.c new file mode 100644 index 0000000..b90710b --- /dev/null +++ b/src/fsck.c @@ -0,0 +1,498 @@ +/* + fsck.c -- Check the configuration files for problems + Copyright (C) 2014 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "system.h" + +#include "crypto.h" +#include "ecdsa.h" +#include "ecdsagen.h" +#include "fsck.h" +#include "names.h" +#ifndef DISABLE_LEGACY +#include "rsa.h" +#include "rsagen.h" +#endif +#include "tincctl.h" +#include "utils.h" + +static bool ask_fix(void) { + if(force) + return true; + if(!tty) + return false; +again: + fprintf(stderr, "Fix y/n? "); + char buf[1024]; + if(!fgets(buf, sizeof buf, stdin)) { + tty = false; + return false; + } + if(buf[0] == 'y' || buf[0] == 'Y') + return true; + if(buf[0] == 'n' || buf[0] == 'N') + return false; + goto again; +} + +static void print_tinc_cmd(const char *argv0, const char *format, ...) { + if(confbasegiven) + fprintf(stderr, "%s -c %s ", argv0, confbase); + else if(netname) + fprintf(stderr, "%s -n %s ", argv0, netname); + else + fprintf(stderr, "%s ", argv0); + va_list va; + va_start(va, format); + vfprintf(stderr, format, va); + va_end(va); + fputc('\n', stderr); +} + +static int strtailcmp(const char *str, const char *tail) { + size_t slen = strlen(str); + size_t tlen = strlen(tail); + if(tlen > slen) + return -1; + return memcmp(str + slen - tlen, tail, tlen); +} + +static void check_conffile(const char *fname, bool server) { + FILE *f = fopen(fname, "r"); + if(!f) { + fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno)); + return; + } + + char line[2048]; + int lineno = 0; + bool skip = false; + const int maxvariables = 50; + int count[maxvariables]; + memset(count, 0, sizeof count); + + while(fgets(line, sizeof line, f)) { + if(skip) { + if(!strncmp(line, "-----END", 8)) + skip = false; + continue; + } else { + if(!strncmp(line, "-----BEGIN", 10)) { + skip = true; + continue; + } + } + + int len; + char *variable, *value, *eol; + variable = value = line; + + lineno++; + + eol = line + strlen(line); + while(strchr("\t \r\n", *--eol)) + *eol = '\0'; + + if(!line[0] || line[0] == '#') + continue; + + len = strcspn(value, "\t ="); + value += len; + value += strspn(value, "\t "); + if(*value == '=') { + value++; + value += strspn(value, "\t "); + } + variable[len] = '\0'; + + bool found = false; + + for(int i = 0; variables[i].name; i++) { + if(strcasecmp(variables[i].name, variable)) + continue; + + found = true; + + if(variables[i].type & VAR_OBSOLETE) { + fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n", variable, fname, lineno); + } + + if(i < maxvariables) + count[i]++; + } + + if(!found) + fprintf(stderr, "WARNING: unknown variable %s in %s line %d\n", variable, fname, lineno); + + if(!*value) + fprintf(stderr, "ERROR: no value for variable %s in %s line %d\n", variable, fname, lineno); + } + + for(int i = 0; variables[i].name && i < maxvariables; i++) { + if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) + fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n", variables[i].name, fname); + } + + if(ferror(f)) + fprintf(stderr, "ERROR: while reading %s: %s\n", fname, strerror(errno)); + + fclose(f); +} + +int fsck(const char *argv0) { +#ifdef HAVE_MINGW + int uid = 0; +#else + uid_t uid = getuid(); +#endif + + // Check that tinc.conf is readable. + + if(access(tinc_conf, R_OK)) { + fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno)); + if(errno == ENOENT) { + fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n"); + print_tinc_cmd(argv0, "init"); + } else if(errno == EACCES) { + if(uid != 0) + fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n"); + else + fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf); + } + return 1; + } + + char *name = get_my_name(true); + if(!name) { + fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n"); + return 1; + } + + // Check for private keys. + // TODO: use RSAPrivateKeyFile and Ed25519PrivateKeyFile variables if present. + + struct stat st; + char fname[PATH_MAX]; + char dname[PATH_MAX]; + +#ifndef DISABLE_LEGACY + rsa_t *rsa_priv = NULL; + snprintf(fname, sizeof fname, "%s/rsa_key.priv", confbase); + + if(stat(fname, &st)) { + if(errno != ENOENT) { + // Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file. + fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno)); + fprintf(stderr, "Please correct this error.\n"); + return 1; + } + } else { + FILE *f = fopen(fname, "r"); + if(!f) { + fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno)); + return 1; + } + rsa_priv = rsa_read_pem_private_key(f); + fclose(f); + if(!rsa_priv) { + fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname); + fprintf(stderr, "You can generate a new RSA key with:\n\n"); + print_tinc_cmd(argv0, "generate-rsa-keys"); + return 1; + } + +#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN) + if(st.st_mode & 077) { + fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname); + if(st.st_uid != uid) { + fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname); + } else if(ask_fix()) { + if(chmod(fname, st.st_mode & ~077)) + fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno)); + else + fprintf(stderr, "Fixed permissions of %s.\n", fname); + } + } +#endif + } +#endif + + ecdsa_t *ecdsa_priv = NULL; + snprintf(fname, sizeof fname, "%s/ed25519_key.priv", confbase); + + if(stat(fname, &st)) { + if(errno != ENOENT) { + // Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file. + fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno)); + fprintf(stderr, "Please correct this error.\n"); + return 1; + } + } else { + FILE *f = fopen(fname, "r"); + if(!f) { + fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno)); + return 1; + } + ecdsa_priv = ecdsa_read_pem_private_key(f); + fclose(f); + if(!ecdsa_priv) { + fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname); + fprintf(stderr, "You can generate a new Ed25519 key with:\n\n"); + print_tinc_cmd(argv0, "generate-ed25519-keys"); + return 1; + } + +#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN) + if(st.st_mode & 077) { + fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname); + if(st.st_uid != uid) { + fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname); + } else if(ask_fix()) { + if(chmod(fname, st.st_mode & ~077)) + fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno)); + else + fprintf(stderr, "Fixed permissions of %s.\n", fname); + } + } +#endif + } + +#ifdef DISABLE_LEGACY + if(!ecdsa_priv) { + fprintf(stderr, "ERROR: No Ed25519 private key found.\n"); +#else + if(!rsa_priv && !ecdsa_priv) { + fprintf(stderr, "ERROR: Neither RSA or Ed25519 private key found.\n"); +#endif + fprintf(stderr, "You can generate new keys with:\n\n"); + print_tinc_cmd(argv0, "generate-keys"); + return 1; + } + + // Check for public keys. + // TODO: use RSAPublicKeyFile variable if present. + + snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, name); + if(access(fname, R_OK)) + fprintf(stderr, "WARNING: cannot read %s\n", fname); + + FILE *f; + +#ifndef DISABLE_LEGACY + rsa_t *rsa_pub = NULL; + + f = fopen(fname, "r"); + if(f) + rsa_pub = rsa_read_pem_public_key(f); + fclose(f); + + if(rsa_priv) { + if(!rsa_pub) { + fprintf(stderr, "WARNING: No (usable) public RSA key found.\n"); + if(ask_fix()) { + FILE *f = fopen(fname, "a"); + if(f) { + if(rsa_write_pem_public_key(rsa_priv, f)) + fprintf(stderr, "Wrote RSA public key to %s.\n", fname); + else + fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname); + fclose(f); + } else { + fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno)); + } + } + } else { + // TODO: suggest remedies + size_t len = rsa_size(rsa_priv); + if(len != rsa_size(rsa_pub)) { + fprintf(stderr, "ERROR: public and private RSA keys do not match.\n"); + return 1; + } + char buf1[len], buf2[len], buf3[len]; + randomize(buf1, sizeof buf1); + buf1[0] &= 0x7f; + memset(buf2, 0, sizeof buf2); + memset(buf3, 0, sizeof buf2); + if(!rsa_public_encrypt(rsa_pub, buf1, sizeof buf1, buf2)) { + fprintf(stderr, "ERROR: public RSA key does not work.\n"); + return 1; + } + if(!rsa_private_decrypt(rsa_priv, buf2, sizeof buf2, buf3)) { + fprintf(stderr, "ERROR: private RSA key does not work.\n"); + return 1; + } + if(memcmp(buf1, buf3, sizeof buf1)) { + fprintf(stderr, "ERROR: public and private RSA keys do not match.\n"); + return 1; + } + } + } else { + if(rsa_pub) + fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n"); + } +#endif + + ecdsa_t *ecdsa_pub = NULL; + + f = fopen(fname, "r"); + if(f) { + ecdsa_pub = get_pubkey(f); + if(!f) { + rewind(f); + ecdsa_pub = ecdsa_read_pem_public_key(f); + } + } + fclose(f); + + if(ecdsa_priv) { + if(!ecdsa_pub) { + fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n"); + if(ask_fix()) { + FILE *f = fopen(fname, "a"); + if(f) { + if(ecdsa_write_pem_public_key(ecdsa_priv, f)) + fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname); + else + fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname); + fclose(f); + } else { + fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno)); + } + } + } else { + // TODO: suggest remedies + char *key1 = ecdsa_get_base64_public_key(ecdsa_pub); + if(!key1) { + fprintf(stderr, "ERROR: public Ed25519 key does not work.\n"); + return 1; + } + char *key2 = ecdsa_get_base64_public_key(ecdsa_priv); + if(!key2) { + free(key1); + fprintf(stderr, "ERROR: private Ed25519 key does not work.\n"); + return 1; + } + int result = strcmp(key1, key2); + free(key1); + free(key2); + if(result) { + fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n"); + return 1; + } + } + } else { + if(ecdsa_pub) + fprintf(stderr, "WARNING: A public Ed25519 key was found but no private key is known.\n"); + } + + // Check whether scripts are executable + + struct dirent *ent; + DIR *dir = opendir(confbase); + if(!dir) { + fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno)); + return 1; + } + + while((ent = readdir(dir))) { + if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) + continue; + + strncpy(fname, ent->d_name, sizeof fname); + char *dash = strrchr(fname, '-'); + if(!dash) + continue; + *dash = 0; + + if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) { + static bool explained = false; + fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name); + if(!explained) { + fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase); + fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n"); + explained = true; + } + continue; + } + + snprintf(fname, sizeof fname, "%s" SLASH "%s", confbase, ent->d_name); + if(access(fname, R_OK | X_OK)) { + if(errno != EACCES) { + fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno)); + continue; + } + fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno)); + if(ask_fix()) { + if(chmod(fname, 0755)) + fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno)); + } + } + } + closedir(dir); + + snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase); + dir = opendir(dname); + if(!dir) { + fprintf(stderr, "ERROR: cannot read directory %s: %s\n", dname, strerror(errno)); + return 1; + } + + while((ent = readdir(dir))) { + if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) + continue; + + strncpy(fname, ent->d_name, sizeof fname); + char *dash = strrchr(fname, '-'); + if(!dash) + continue; + *dash = 0; + + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name); + if(access(fname, R_OK | X_OK)) { + if(errno != EACCES) { + fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno)); + continue; + } + fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno)); + if(ask_fix()) { + if(chmod(fname, 0755)) + fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno)); + } + } + } + closedir(dir); + + // Check for obsolete / unsafe / unknown configuration variables. + + check_conffile(tinc_conf, true); + + dir = opendir(dname); + if(dir) { + while((ent = readdir(dir))) { + if(!check_id(ent->d_name)) + continue; + + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name); + check_conffile(fname, false); + } + closedir(dir); + } + + return 0; +} + diff --git a/src/gcrypt/ecdh.c b/src/fsck.h similarity index 60% rename from src/gcrypt/ecdh.c rename to src/fsck.h index 4e30733..51e4f55 100644 --- a/src/gcrypt/ecdh.c +++ b/src/fsck.h @@ -1,6 +1,6 @@ /* - ecdh.c -- Diffie-Hellman key exchange handling - Copyright (C) 2011-2013 Guus Sliepen + fsck.h -- header for fsck.c. + Copyright (C) 2012 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,21 +17,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "../system.h" +#ifndef __TINC_FSCK_H__ +#define __TINC_FSCK_H__ -#include "../ecdh.h" -#include "../logger.h" -#include "../utils.h" -#include "../xalloc.h" +extern int fsck(const char *argv0); -ecdh_t *ecdh_generate_public(void *pubkey) { - logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented"); - return NULL; -} +#endif -bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) { - return false -} - -void ecdh_free(ecdh_t *ecdh) { -} diff --git a/src/gcrypt/ecdsa.c b/src/gcrypt/ecdsa.c deleted file mode 100644 index ee19aec..0000000 --- a/src/gcrypt/ecdsa.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - ecdsa.c -- ECDSA key handling - Copyright (C) 2011-2013 Guus Sliepen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "../system.h" - -#include "../logger.h" -#include "../ecdsa.h" -#include "../utils.h" -#include "../xalloc.h" - -// Get and set ECDSA keys -// -ecdsa_t *ecdsa_set_base64_public_key(const char *p) { - logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented"); - return NULL; -} - -char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) { - return NULL; -} - -// Read PEM ECDSA keys - -ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) { - logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented"); - return NULL; -} - -ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) { - logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented"); - return NULL; -} - -size_t ecdsa_size(ecdsa_t *ecdsa) { - return 0; -} - -bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) { - return false; -} - -bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) { - return false; -} - -bool ecdsa_active(ecdsa_t *ecdsa) { - return false; -} - -void ecdsa_free(ecdsa_t *ecdsa) { -} diff --git a/src/gcrypt/prf.c b/src/gcrypt/prf.c index f9a2112..55c9923 100644 --- a/src/gcrypt/prf.c +++ b/src/gcrypt/prf.c @@ -19,11 +19,88 @@ #include "../system.h" -#include "digest.h" -#include "../digest.h" #include "../prf.h" +#include "../ed25519/sha512.h" + +static void memxor(char *buf, char c, size_t len) { + for(size_t i = 0; i < len; i++) + buf[i] ^= c; +} + +static const size_t mdlen = 64; +static const size_t blklen = 128; + +static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) { + char tmp[blklen + mdlen]; + sha512_context md; + + if(keylen <= blklen) { + memcpy(tmp, key, keylen); + memset(tmp + keylen, 0, blklen - keylen); + } else { + if(sha512(key, keylen, tmp) != 0) + return false; + memset(tmp + mdlen, 0, blklen - mdlen); + } + + if(sha512_init(&md) != 0) + return false; + + // ipad + memxor(tmp, 0x36, blklen); + if(sha512_update(&md, tmp, blklen) != 0) + return false; + + // message + if(sha512_update(&md, msg, msglen) != 0) + return false; + + if(sha512_final(&md, tmp + blklen) != 0) + return false; + + // opad + memxor(tmp, 0x36 ^ 0x5c, blklen); + if(sha512(tmp, sizeof tmp, out) != 0) + return false; + + return true; +} + + +/* Generate key material from a master secret and a seed, based on RFC 4346 section 5. + We use SHA512 instead of MD5 and SHA1. + */ bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) { - logger(DEBUG_ALWAYS, LOG_ERR, "PRF support using libgcrypt not implemented"); - return false; + /* Data is what the "inner" HMAC function processes. + It consists of the previous HMAC result plus the seed. + */ + + char data[mdlen + seedlen]; + memset(data, 0, mdlen); + memcpy(data + mdlen, seed, seedlen); + + char hash[mdlen]; + + while(outlen > 0) { + /* Inner HMAC */ + if(!hmac_sha512(secret, secretlen, data, sizeof data, data)) + return false; + + /* Outer HMAC */ + if(outlen >= mdlen) { + if(!hmac_sha512(secret, secretlen, data, sizeof data, out)) + return false; + out += mdlen; + outlen -= mdlen; + } else { + if(!hmac_sha512(secret, secretlen, data, sizeof data, hash)) + return false; + memcpy(out, hash, outlen); + out += outlen; + outlen = 0; + } + } + + return true; } diff --git a/src/graph.c b/src/graph.c index 70d6573..e570feb 100644 --- a/src/graph.c +++ b/src/graph.c @@ -149,7 +149,7 @@ static void sssp_bfs(void) { abort(); for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */ - if(!e->reverse) + if(!e->reverse || e->to == myself) continue; /* Situation: @@ -238,10 +238,11 @@ static void check_reachability(void) { n->status.udp_confirmed = false; n->maxmtu = MTU; + n->maxrecentlen = 0; n->minmtu = 0; n->mtuprobes = 0; - timeout_del(&n->mtutimeout); + timeout_del(&n->udp_ping_timeout); char *name; char *address; @@ -275,6 +276,10 @@ static void check_reachability(void) { update_node_udp(n, NULL); memset(&n->status, 0, sizeof n->status); n->options = 0; + } else if(n->connection) { + // Speed up UDP probing by sending our key. + if(!n->status.sptps) + send_ans_key(n); } } diff --git a/src/hash.c b/src/hash.c index 91fc3d6..50934d9 100644 --- a/src/hash.c +++ b/src/hash.c @@ -29,7 +29,7 @@ static uint32_t hash_function(const void *p, size_t len) { uint32_t hash = 0; while(true) { for(int i = len > 4 ? 4 : len; --i;) - hash += q[len - i] << (8 * i); + hash += (uint32_t)q[len - i] << (8 * i); hash *= 0x9e370001UL; // Golden ratio prime. if(len <= 4) break; diff --git a/src/have.h b/src/have.h index 85479f7..faa4c9e 100644 --- a/src/have.h +++ b/src/have.h @@ -1,7 +1,7 @@ /* have.h -- include headers which are known to exist Copyright (C) 1998-2005 Ivo Timmermans - 2003-2013 Guus Sliepen + 2003-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,17 +22,14 @@ #define __TINC_HAVE_H__ #ifdef HAVE_MINGW -#ifdef WITH_WINDOWS2000 -#define WINVER Windows2000 -#else #define WINVER WindowsXP -#endif #define WIN32_LEAN_AND_MEAN #endif #include #include #include +#include #include #include #include @@ -40,6 +37,8 @@ #include #include #include +#include +#include #ifdef HAVE_MINGW #include @@ -48,10 +47,6 @@ #include #endif -#ifdef HAVE_STDBOOL_H -#include -#endif - #ifdef HAVE_TERMIOS_H #include #endif @@ -70,9 +65,6 @@ #include #endif -#ifdef HAVE_TIME_H -#include -#endif #ifdef HAVE_SYS_TYPES_H #include @@ -102,10 +94,6 @@ #include #endif -#ifdef HAVE_SYS_UIO_H -#include -#endif - #ifdef HAVE_SYS_UN_H #include #endif @@ -197,6 +185,28 @@ #include #endif +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif + +#ifdef HAVE_RESOLV_H +#include +#endif + +#ifdef HAVE_LINUX_IF_TUN_H +#include +#endif + +#ifdef HAVE_GETOPT_H +#include +#else +#include "getopt.h" +#endif + +#ifdef STATUS +#undef STATUS +#endif + #ifdef HAVE_MINGW #define SLASH "\\" #else diff --git a/src/ifconfig.c b/src/ifconfig.c new file mode 100644 index 0000000..7688a3c --- /dev/null +++ b/src/ifconfig.c @@ -0,0 +1,198 @@ +/* + ifconfig.c -- Generate platform specific interface configuration commands + Copyright (C) 2016 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "system.h" + +#include "conf.h" +#include "ifconfig.h" +#include "subnet.h" + +static long start; + +#ifndef HAVE_MINGW +void ifconfig_header(FILE *out) { + fprintf(out, "#!/bin/sh\n"); + start = ftell(out); +} + +void ifconfig_dhcp(FILE *out) { + fprintf(out, "dhclient -nw \"$INTERFACE\"\n"); +} + +void ifconfig_dhcp6(FILE *out) { + fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n"); +} + +void ifconfig_slaac(FILE *out) { +#ifdef HAVE_LINUX + fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n"); + fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n"); +#else + fprintf(out, "rtsol \"$INTERFACE\" &\n"); +#endif +} + +bool ifconfig_footer(FILE *out) { + if(ftell(out) == start) { + fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE netmask \n"); + return false; + } else { +#ifdef HAVE_LINUX + fprintf(out, "ip link set \"$INTERFACE\" up\n"); +#else + fprintf(out, "ifconfig \"$INTERFACE\" up\n"); +#endif + return true; + } +} +#else +void ifconfig_header(FILE *out) { + start = ftell(out); +} + +void ifconfig_dhcp(FILE *out) { + fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n"); +} + +void ifconfig_dhcp6(FILE *out) { + fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n"); +} + +void ifconfig_slaac(FILE *out) { + // It's the default? +} + +bool ifconfig_footer(FILE *out) { + return ftell(out) != start; +} +#endif + +static subnet_t ipv4, ipv6; + +void ifconfig_address(FILE *out, const char *value) { + subnet_t address = {}; + char address_str[MAXNETSTR]; + if(!str2net(&address, value) || !net2str(address_str, sizeof address_str, &address)) { + fprintf(stderr, "Could not parse address in Ifconfig statement\n"); + return; + } + switch(address.type) { + case SUBNET_IPV4: ipv4 = address; break; + case SUBNET_IPV6: ipv6 = address; break; + default: return; + } +#if defined(HAVE_LINUX) + switch(address.type) { + case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break; + case SUBNET_IPV4: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break; + case SUBNET_IPV6: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break; + default: return; + } +#elif defined(HAVE_BSD) + switch(address.type) { + case SUBNET_MAC: fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str); break; + case SUBNET_IPV4: fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str); break; + case SUBNET_IPV6: fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str); break; + default: return; + } +#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN) + switch(address.type) { + case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break; + case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", address_str); break; + case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", address_str); break; + default: return; + } +#endif +} + +void ifconfig_route(FILE *out, const char *value) { + subnet_t subnet = {}, gateway = {}; + char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = ""; + char *sep = strchr(value, ' '); + if(sep) + *sep++ = 0; + if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof subnet_str, &subnet) || subnet.type == SUBNET_MAC) { + fprintf(stderr, "Could not parse subnet in Route statement\n"); + return; + } + if(sep) { + if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof gateway_str, &gateway) || gateway.type != subnet.type) { + fprintf(stderr, "Could not parse gateway in Route statement\n"); + return; + } + char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0; + } +#if defined(HAVE_LINUX) + if(*gateway_str) { + switch(subnet.type) { + case SUBNET_IPV4: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break; + case SUBNET_IPV6: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break; + default: return; + } + } else { + switch(subnet.type) { + case SUBNET_IPV4: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break; + case SUBNET_IPV6: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break; + default: return; + } + } +#elif defined(HAVE_BSD) + // BSD route command is silly and doesn't accept an interface name as a destination. + if(!*gateway_str) { + switch(subnet.type) { + case SUBNET_IPV4: + if(!ipv4.type) { + fprintf(stderr, "Route requested but no Ifconfig\n"); + return; + } + net2str(gateway_str, sizeof gateway_str, &ipv4); + break; + case SUBNET_IPV6: + if(!ipv6.type) { + fprintf(stderr, "Route requested but no Ifconfig\n"); + return; + } + net2str(gateway_str, sizeof gateway_str, &ipv6); + break; + default: return; + } + char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0; + } + + switch(subnet.type) { + case SUBNET_IPV4: fprintf(out, "route add %s %s\n", subnet_str, gateway_str); break; + case SUBNET_IPV6: fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str); break; + default: return; + } +#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN) + if(*gateway_str) { + switch(subnet.type) { + case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break; + case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break; + default: return; + } + } else { + switch(subnet.type) { + case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str); break; + case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str); break; + default: return; + } + } +#endif +} diff --git a/src/ifconfig.h b/src/ifconfig.h new file mode 100644 index 0000000..3dbf9f6 --- /dev/null +++ b/src/ifconfig.h @@ -0,0 +1,31 @@ +/* + ifconfig.h -- header for ifconfig.c. + Copyright (C) 2016 Guus Sliepen + + 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_IFCONFIG_H__ +#define __TINC_IFCONFIG_H__ + +extern void ifconfig_dhcp(FILE *out); +extern void ifconfig_dhcp6(FILE *out); +extern void ifconfig_slaac(FILE *out); +extern void ifconfig_address(FILE *out, const char *value); +extern void ifconfig_route(FILE *out, const char *value); +extern void ifconfig_header(FILE *out); +extern bool ifconfig_footer(FILE *out); + +#endif diff --git a/src/invitation.c b/src/invitation.c index dff8d5f..08afe78 100644 --- a/src/invitation.c +++ b/src/invitation.c @@ -1,6 +1,6 @@ /* invitation.c -- Create and accept invitations - Copyright (C) 2013-2014 Guus Sliepen + Copyright (C) 2013-2015 Guus Sliepen 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 @@ -23,16 +23,20 @@ #include "crypto.h" #include "ecdsa.h" #include "ecdsagen.h" +#include "ifconfig.h" #include "invitation.h" #include "names.h" #include "netutl.h" #include "rsagen.h" #include "script.h" #include "sptps.h" +#include "subnet.h" #include "tincctl.h" #include "utils.h" #include "xalloc.h" +#include "ed25519/sha512.h" + int addressfamily = AF_UNSPEC; static void scan_for_hostname(const char *filename, char **hostname, char **port) { @@ -82,11 +86,11 @@ char *get_my_hostname() { char *port = NULL; char *hostport = NULL; char *name = get_my_name(false); - char *filename = NULL; + char filename[PATH_MAX] = {0}; // Use first Address statement in own host config file if(check_id(name)) { - xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name); + snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name); scan_for_hostname(filename, &hostname, &port); scan_for_hostname(tinc_conf, &hostname, &port); } @@ -180,7 +184,7 @@ again: hostname = xstrdup(line); save: - if(filename) { + if(*filename) { FILE *f = fopen(filename, "a"); if(f) { fprintf(f, "\nAddress = %s\n", hostname); @@ -205,7 +209,6 @@ done: free(hostname); free(port); - free(filename); return hostport; } @@ -241,14 +244,12 @@ int cmd_invite(int argc, char *argv[]) { return 1; // Ensure no host configuration file with that name exists - char *filename = NULL; - xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]); + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]); if(!access(filename, F_OK)) { - free(filename); fprintf(stderr, "A host config file for %s already exists!\n", argv[1]); return 1; } - free(filename); // If a daemon is running, ensure no other nodes know about this name bool found = false; @@ -270,12 +271,9 @@ int cmd_invite(int argc, char *argv[]) { } } - char hash[25]; - - xasprintf(&filename, "%s" SLASH "invitations", confbase); + snprintf(filename, sizeof filename, "%s" SLASH "invitations", confbase); if(mkdir(filename, 0700) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno)); - free(filename); return 1; } @@ -283,7 +281,6 @@ int cmd_invite(int argc, char *argv[]) { DIR *dir = opendir(filename); if(!dir) { fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno)); - free(filename); return 1; } @@ -295,9 +292,9 @@ int cmd_invite(int argc, char *argv[]) { while((ent = readdir(dir))) { if(strlen(ent->d_name) != 24) continue; - char *invname; + char invname[PATH_MAX]; struct stat st; - xasprintf(&invname, "%s" SLASH "%s", filename, ent->d_name); + snprintf(invname, sizeof invname, "%s" SLASH "%s", filename, ent->d_name); if(!stat(invname, &st)) { if(deadline < st.st_mtime) count++; @@ -307,21 +304,17 @@ int cmd_invite(int argc, char *argv[]) { fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno)); errno = 0; } - free(invname); } + closedir(dir); + if(errno) { fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno)); - closedir(dir); - free(filename); return 1; } - closedir(dir); - free(filename); - ecdsa_t *key; - xasprintf(&filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); + snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); // Remove the key if there are no outstanding invitations. if(!count) @@ -332,23 +325,23 @@ int cmd_invite(int argc, char *argv[]) { if(!f) { if(errno != ENOENT) { fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno)); - free(filename); return 1; } key = ecdsa_generate(); - if(!key) { - free(filename); + if(!key) return 1; - } f = fopen(filename, "w"); if(!f) { fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno)); - free(filename); return 1; } chmod(filename, 0600); - ecdsa_write_pem_private_key(key, f); + if(!ecdsa_write_pem_private_key(key, f)) { + fprintf(stderr, "Could not write ECDSA private key\n"); + fclose(f); + return 1; + } fclose(f); if(connect_tincd(false)) @@ -360,16 +353,13 @@ int cmd_invite(int argc, char *argv[]) { fprintf(stderr, "Could not read private key from %s\n", filename); } - free(filename); if(!key) return 1; // Create a hash of the key. + char hash[64]; char *fingerprint = ecdsa_get_base64_public_key(key); - digest_t *digest = digest_open_by_name("sha256", 18); - if(!digest) - abort(); - digest_create(digest, fingerprint, strlen(fingerprint), hash); + sha512(fingerprint, strlen(fingerprint), hash); b64encode_urlsafe(hash, hash, 18); // Create a random cookie for this invitation. @@ -378,20 +368,19 @@ int cmd_invite(int argc, char *argv[]) { // Create a filename that doesn't reveal the cookie itself char buf[18 + strlen(fingerprint)]; - char cookiehash[25]; + char cookiehash[64]; memcpy(buf, cookie, 18); memcpy(buf + 18, fingerprint, sizeof buf - 18); - digest_create(digest, buf, sizeof buf, cookiehash); + sha512(buf, sizeof buf, cookiehash); b64encode_urlsafe(cookiehash, cookiehash, 18); b64encode_urlsafe(cookie, cookie, 18); // Create a file containing the details of the invitation. - xasprintf(&filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash); + snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash); int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); if(!ifd) { fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno)); - free(filename); return 1; } f = fdopen(ifd, "w"); @@ -403,7 +392,7 @@ int cmd_invite(int argc, char *argv[]) { // Fill in the details. fprintf(f, "Name = %s\n", argv[1]); - if(netname) + if(check_netname(netname, true)) fprintf(f, "NetName = %s\n", netname); fprintf(f, "ConnectTo = %s\n", myname); @@ -426,11 +415,10 @@ int cmd_invite(int argc, char *argv[]) { fprintf(f, "#---------------------------------------------------------------#\n"); fprintf(f, "Name = %s\n", myname); - char *filename2; - xasprintf(&filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname); + char filename2[PATH_MAX]; + snprintf(filename2, sizeof filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname); fcopy(f, filename2); fclose(f); - free(filename2); // Create an URL from the local address, key hash and cookie char *url; @@ -449,7 +437,6 @@ int cmd_invite(int argc, char *argv[]) { puts(url); free(url); - free(filename); free(address); return 0; @@ -554,12 +541,17 @@ static bool finalize_join(void) { } if(!check_id(name)) { - fprintf(stderr, "Invalid Name found in invitation: %s!\n", name); + fprintf(stderr, "Invalid Name found in invitation!\n"); return false; } - if(!netname) + if(!netname) { netname = grep(data, "NetName"); + if(netname && !check_netname(netname, true)) { + fprintf(stderr, "Unsafe NetName found in invitation!\n"); + return false; + } + } bool ask_netname = false; char temp_netname[32]; @@ -570,7 +562,7 @@ make_names: confbase = NULL; } - make_names(); + make_names(false); free(tinc_conf); free(hosts_dir); @@ -608,8 +600,8 @@ make_names: fprintf(f, "Name = %s\n", name); - char *filename; - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name); + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name); FILE *fh = fopen(filename, "w"); if(!fh) { fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); @@ -617,7 +609,19 @@ make_names: return false; } + snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase); + FILE *fup = fopen(filename, "w"); + if(!fup) { + fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); + fclose(f); + fclose(fh); + return false; + } + + ifconfig_header(fup); + // Filter first chunk on approved keywords, split between tinc.conf and hosts/Name + // Generate a tinc-up script from Ifconfig and Route keywords. // Other chunks go unfiltered to their respective host config files const char *p = data; char *l, *value; @@ -656,6 +660,24 @@ make_names: break; } + // Handle Ifconfig and Route statements + if(!found) { + if(!strcasecmp(l, "Ifconfig")) { + if(!strcasecmp(value, "dhcp")) + ifconfig_dhcp(fup); + else if(!strcasecmp(value, "dhcp6")) + ifconfig_dhcp6(fup); + else if(!strcasecmp(value, "slaac")) + ifconfig_slaac(fup); + else + ifconfig_address(fup, value); + continue; + } else if(!strcasecmp(l, "Route")) { + ifconfig_route(fup, value); + continue; + } + } + // Ignore unknown and unsafe variables if(!found) { fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l); @@ -670,7 +692,8 @@ make_names: } fclose(f); - free(filename); + bool valid_tinc_up = ifconfig_footer(fup); + fclose(fup); while(l && !strcasecmp(l, "Name")) { if(!check_id(value)) { @@ -683,7 +706,7 @@ make_names: return false; } - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, value); + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, value); f = fopen(filename, "w"); if(!f) { @@ -711,7 +734,6 @@ make_names: } fclose(f); - free(filename); } // Generate our key and send a copy to the server @@ -723,8 +745,10 @@ make_names: if(!b64key) return false; - xasprintf(&filename, "%s" SLASH "ed25519_key.priv", confbase); + snprintf(filename, sizeof filename, "%s" SLASH "ed25519_key.priv", confbase); f = fopenmask(filename, "w", 0600); + if(!f) + return false; if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Error writing private key!\n"); @@ -739,20 +763,25 @@ make_names: sptps_send_record(&sptps, 1, b64key, strlen(b64key)); free(b64key); + ecdsa_free(key); - +#ifndef DISABLE_LEGACY rsa_t *rsa = rsa_generate(2048, 0x1001); - xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase); + snprintf(filename, sizeof filename, "%s" SLASH "rsa_key.priv", confbase); f = fopenmask(filename, "w", 0600); - rsa_write_pem_private_key(rsa, f); + if(!f || !rsa_write_pem_private_key(rsa, f)) { + fprintf(stderr, "Could not write private RSA key\n"); + } else if(!rsa_write_pem_public_key(rsa, fh)) { + fprintf(stderr, "Could not write public RSA key\n"); + } + fclose(f); - rsa_write_pem_public_key(rsa, fh); fclose(fh); - ecdsa_free(key); rsa_free(rsa); +#endif check_port(name); @@ -768,17 +797,69 @@ ask_netname: line[strlen(line) - 1] = 0; - char *newbase; - xasprintf(&newbase, CONFDIR SLASH "tinc" SLASH "%s", line); + char newbase[PATH_MAX]; + snprintf(newbase, sizeof newbase, CONFDIR SLASH "tinc" SLASH "%s", line); if(rename(confbase, newbase)) { fprintf(stderr, "Error trying to rename %s to %s: %s\n", confbase, newbase, strerror(errno)); - free(newbase); goto ask_netname; } - free(newbase); netname = line; - make_names(); + make_names(false); + } + + char filename2[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase); + snprintf(filename2, sizeof filename2, "%s" SLASH "tinc-up", confbase); + + if(valid_tinc_up) { + if(tty) { + FILE *fup = fopen(filename, "r"); + if(fup) { + fprintf(stderr, "\nPlease review the following tinc-up script:\n\n"); + + char buf[MAXSIZE]; + while(fgets(buf, sizeof buf, fup)) + fputs(buf, stderr); + fclose(fup); + + int response = 0; + do { + fprintf(stderr, "\nDo you want to use this script [y]es/[n]o/[e]dit? "); + response = tolower(getchar()); + } while(!strchr("yne", response)); + + fprintf(stderr, "\n"); + + if(response == 'e') { + char *command; +#ifndef HAVE_MINGW + xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename); +#else + xasprintf(&command, "edit \"%s\"", filename); +#endif + if(system(command)) + response = 'n'; + else + response = 'y'; + free(command); + } + + if(response == 'y') { + rename(filename, filename2); + chmod(filename2, 0755); + fprintf(stderr, "tinc-up enabled.\n"); + } else { + fprintf(stderr, "tinc-up has been left disabled.\n"); + } + } + } else { + fprintf(stderr, "A tinc-up script was generated, but has been left disabled.\n"); + } + } else { + // A placeholder was generated. + rename(filename, filename2); + chmod(filename2, 0755); } fprintf(stderr, "Configuration stored in: %s\n", confbase); @@ -922,16 +1003,31 @@ int cmd_join(int argc, char *argv[]) { if(!ai) return 1; - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if(sock <= 0) { - fprintf(stderr, "Could not open socket: %s\n", strerror(errno)); - return 1; + struct addrinfo *aip = NULL; + +next: + if(!aip) + aip = ai; + else { + aip = aip->ai_next; + if(!aip) + return 1; } - if(connect(sock, ai->ai_addr, ai->ai_addrlen)) { - fprintf(stderr, "Could not connect to %s port %s: %s\n", address, port, strerror(errno)); + sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); + if(sock <= 0) { + fprintf(stderr, "Could not open socket: %s\n", strerror(errno)); + goto next; + } + + if(connect(sock, aip->ai_addr, aip->ai_addrlen)) { + char *addrstr, *portstr; + sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr); + fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno)); + free(addrstr); + free(portstr); closesocket(sock); - return 1; + goto next; } fprintf(stderr, "Connected to %s port %s...\n", address, port); @@ -944,7 +1040,7 @@ int cmd_join(int argc, char *argv[]) { if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) { fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno)); closesocket(sock); - return 1; + goto next; } char hisname[4096] = ""; @@ -953,16 +1049,13 @@ int cmd_join(int argc, char *argv[]) { if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) { fprintf(stderr, "Cannot read greeting from peer\n"); closesocket(sock); - return 1; + goto next; } // Check if the hash of the key he gave us matches the hash in the URL. char *fingerprint = line + 2; - digest_t *digest = digest_open_by_name("sha256", 18); - if(!digest) - abort(); - char hishash[18]; - if(!digest_create(digest, fingerprint, strlen(fingerprint), hishash)) { + char hishash[64]; + if(sha512(fingerprint, strlen(fingerprint), hishash)) { fprintf(stderr, "Could not create digest\n%s\n", line + 2); return 1; } @@ -992,8 +1085,14 @@ int cmd_join(int argc, char *argv[]) { return 1; } - if(!sptps_receive_data(&sptps, line, len)) - return 1; + char *p = line; + while(len) { + int done = sptps_receive_data(&sptps, p, len); + if(!done) + return 1; + len -= done; + p += done; + } } sptps_stop(&sptps); diff --git a/src/ipv4.h b/src/ipv4.h index 6cb969b..997b88d 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -81,7 +81,7 @@ struct ip { uint8_t ip_p; uint16_t ip_sum; struct in_addr ip_src, ip_dst; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #endif #ifndef IP_OFFMASK @@ -143,7 +143,7 @@ struct icmp { #define icmp_radv icmp_dun.id_radv #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #endif #endif /* __TINC_IPV4_H__ */ diff --git a/src/ipv6.h b/src/ipv6.h index 37d999a..cc2c5b6 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -1,7 +1,7 @@ /* ipv6.h -- missing IPv6 related definitions Copyright (C) 2005 Ivo Timmermans - 2006-2012 Guus Sliepen + 2006-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,29 +29,6 @@ #define IPPROTO_ICMPV6 58 #endif -#ifndef HAVE_STRUCT_IN6_ADDR -struct in6_addr { - union { - uint8_t u6_addr8[16]; - uint16_t u6_addr16[8]; - uint32_t u6_addr32[4]; - } in6_u; -} __attribute__ ((__packed__)); -#define s6_addr in6_u.u6_addr8 -#define s6_addr16 in6_u.u6_addr16 -#define s6_addr32 in6_u.u6_addr32 -#endif - -#ifndef HAVE_STRUCT_SOCKADDR_IN6 -struct sockaddr_in6 { - uint16_t sin6_family; - uint16_t sin6_port; - uint32_t sin6_flowinfo; - struct in6_addr sin6_addr; - uint32_t sin6_scope_id; -} __attribute__ ((__packed__)); -#endif - #ifndef IN6_IS_ADDR_V4MAPPED #define IN6_IS_ADDR_V4MAPPED(a) \ ((((__const uint32_t *) (a))[0] == 0) \ @@ -72,7 +49,7 @@ struct ip6_hdr { } ip6_ctlun; struct in6_addr ip6_src; struct in6_addr ip6_dst; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen @@ -91,7 +68,7 @@ struct icmp6_hdr { uint16_t icmp6_un_data16[2]; uint8_t icmp6_un_data8[4]; } icmp6_dataun; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #define ICMP6_DST_UNREACH_NOROUTE 0 #define ICMP6_DST_UNREACH 1 #define ICMP6_PACKET_TOO_BIG 2 @@ -111,7 +88,7 @@ struct icmp6_hdr { struct nd_neighbor_solicit { struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_TARGET_LINKADDR 2 #define nd_ns_type nd_ns_hdr.icmp6_type @@ -124,7 +101,7 @@ struct nd_neighbor_solicit { struct nd_opt_hdr { uint8_t nd_opt_type; uint8_t nd_opt_len; -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #endif #endif /* __TINC_IPV6_H__ */ diff --git a/src/linux/device.c b/src/linux/device.c index 5717d92..a06e6da 100644 --- a/src/linux/device.c +++ b/src/linux/device.c @@ -101,6 +101,9 @@ static bool setup_device(void) { strncpy(ifrname, ifr.ifr_name, IFNAMSIZ); free(iface); iface = xstrdup(ifrname); + } else { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not create a tun/tap interface from %s: %s", device, strerror(errno)); + return false; } logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info); diff --git a/src/list.h b/src/list.h index 0437bd9..b0e7a84 100644 --- a/src/list.h +++ b/src/list.h @@ -79,6 +79,12 @@ extern void list_delete_list(list_t *); extern void list_foreach(list_t *, list_action_t); extern void list_foreach_node(list_t *, list_action_node_t); +/* + Iterates over a list. + + CAUTION: while this construct supports deleting the current item, + it does *not* support deleting *other* nodes while iterating on the list. + */ #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__ */ diff --git a/src/logger.c b/src/logger.c index 2b4c7e3..e46d926 100644 --- a/src/logger.c +++ b/src/logger.c @@ -1,6 +1,6 @@ /* logger.c -- logging code - Copyright (C) 2004-2013 Guus Sliepen + Copyright (C) 2004-2015 Guus Sliepen 2004-2005 Ivo Timmermans This program is free software; you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "logger.h" #include "connection.h" #include "control_common.h" +#include "process.h" #include "sptps.h" debug_t debug_level = DEBUG_NOTHING; @@ -37,7 +38,7 @@ static HANDLE loghandle = NULL; #endif static const char *logident = NULL; bool logcontrol = false; - +int umbilical = 0; static void real_logger(int level, int priority, const char *message) { char timestr[32] = ""; @@ -79,6 +80,11 @@ static void real_logger(int level, int priority, const char *message) { case LOGMODE_NULL: break; } + + if(umbilical && do_detach) { + write(umbilical, message, strlen(message)); + write(umbilical, "\n", 1); + } } if(logcontrol) { @@ -114,9 +120,19 @@ void logger(int level, int priority, const char *format, ...) { 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; + size_t msglen = sizeof message; + + int len = vsnprintf(message, msglen, format, ap); + if(len > 0 && len < sizeof message) { + if(message[len - 1] == '\n') + message[--len] = 0; + + // WARNING: s->handle can point to a connection_t or a node_t, + // but both types have the name and hostname fields at the same offsets. + connection_t *c = s->handle; + if(c) + snprintf(message + len, sizeof message - len, " from %s (%s)", c->name, c->hostname); + } real_logger(DEBUG_ALWAYS, LOG_ERR, message); } @@ -194,6 +210,5 @@ void closelogger(void) { case LOGMODE_NULL: case LOGMODE_STDERR: break; - break; } } diff --git a/src/logger.h b/src/logger.h index 8f69029..252497b 100644 --- a/src/logger.h +++ b/src/logger.h @@ -69,6 +69,7 @@ enum { extern debug_t debug_level; extern bool logcontrol; +extern int umbilical; extern void openlogger(const char *, logmode_t); extern void reopenlogger(void); extern void logger(int, int, const char *, ...) __attribute__ ((__format__(printf, 3, 4))); diff --git a/src/meta.c b/src/meta.c index 73769d9..260cb00 100644 --- a/src/meta.c +++ b/src/meta.c @@ -30,6 +30,10 @@ #include "utils.h" #include "xalloc.h" +#ifndef MIN +#define MIN(x, y) (((x)<(y))?(x):(y)) +#endif + bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) { connection_t *c = handle; @@ -58,6 +62,9 @@ bool send_meta(connection_t *c, const char *buffer, int length) { /* Add our data to buffer */ if(c->status.encryptout) { +#ifdef DISABLE_LEGACY + return false; +#else size_t outlen = length; if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) { @@ -65,6 +72,7 @@ bool send_meta(connection_t *c, const char *buffer, int length) { c->name, c->hostname); return false; } +#endif } else { buffer_add(&c->outbuf, buffer, length); } @@ -74,6 +82,20 @@ bool send_meta(connection_t *c, const char *buffer, int length) { return true; } +void send_meta_raw(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 raw metadata to %s (%s)", length, + c->name, c->hostname); + + buffer_add(&c->outbuf, buffer, length); + + io_set(&c->io, IO_READ | IO_WRITE); +} + void broadcast_meta(connection_t *from, const char *buffer, int length) { for list_each(connection_t, c, connection_list) if(c != from && c->edge) @@ -155,8 +177,33 @@ bool receive_meta(connection_t *c) { } do { - if(c->protocol_minor >= 2) - return sptps_receive_data(&c->sptps, bufp, inlen); + /* Are we receiving a SPTPS packet? */ + + if(c->sptpslen) { + int len = MIN(inlen, c->sptpslen - c->inbuf.len); + buffer_add(&c->inbuf, bufp, len); + + char *sptpspacket = buffer_read(&c->inbuf, c->sptpslen); + if(!sptpspacket) + return true; + + if(!receive_tcppacket_sptps(c, sptpspacket, c->sptpslen)) + return false; + c->sptpslen = 0; + + bufp += len; + inlen -= len; + continue; + } + + if(c->protocol_minor >= 2) { + int len = sptps_receive_data(&c->sptps, bufp, inlen); + if(!len) + return false; + bufp += len; + inlen -= len; + continue; + } if(!c->status.decryptin) { endp = memchr(bufp, '\n', inlen); @@ -170,6 +217,9 @@ bool receive_meta(connection_t *c) { inlen -= endp - bufp; bufp = endp; } else { +#ifdef DISABLE_LEGACY + return false; +#else size_t outlen = inlen; if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) { @@ -179,6 +229,7 @@ bool receive_meta(connection_t *c) { } inlen = 0; +#endif } while(c->inbuf.len) { diff --git a/src/meta.h b/src/meta.h index ddc5418..8b00a5a 100644 --- a/src/meta.h +++ b/src/meta.h @@ -24,6 +24,7 @@ #include "connection.h" extern bool send_meta(struct connection_t *, const char *, int); +extern void send_meta_raw(struct connection_t *, const char *, int); extern bool send_meta_sptps(void *, uint8_t, const void *, size_t); extern bool receive_meta_sptps(void *, uint8_t, const void *, uint16_t); extern void broadcast_meta(struct connection_t *, const char *, int); diff --git a/src/mingw/device.c b/src/mingw/device.c index 19719a7..b047615 100644 --- a/src/mingw/device.c +++ b/src/mingw/device.c @@ -38,7 +38,9 @@ int device_fd = -1; static HANDLE device_handle = INVALID_HANDLE_VALUE; static io_t device_read_io; static OVERLAPPED device_read_overlapped; +static OVERLAPPED device_write_overlapped; static vpn_packet_t device_read_packet; +static vpn_packet_t device_write_packet; char *device = NULL; char *iface = NULL; static char *device_info = NULL; @@ -99,6 +101,9 @@ static bool setup_device(void) { get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Interface"), &iface); + if(device && iface) + logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); + /* Open registry and look for network adapters */ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { @@ -175,6 +180,25 @@ static bool setup_device(void) { return false; } + /* Get version information from tap device */ + + { + ULONG info[3] = {0}; + DWORD len; + if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof info, &info, sizeof info, &len, NULL)) + logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); + else { + logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : ""); + + /* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */ + if(info[0] == 9 && info[1] >= 21) + logger(DEBUG_ALWAYS, LOG_WARNING, + "You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. " + "Using these drivers with tinc is not recommanded as it can result in poor performance. " + "You might want to revert back to 9.0.0.9 instead."); + } + } + /* 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)) { @@ -200,8 +224,12 @@ static void enable_device(void) { DWORD len; DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL); - io_add_event(&device_read_io, device_handle_read, NULL, CreateEvent(NULL, TRUE, FALSE, NULL)); - device_read_overlapped.hEvent = device_read_io.event; + /* We don't use the write event directly, but GetOverlappedResult() does, internally. */ + + device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent); device_issue_read(); } @@ -210,10 +238,22 @@ static void disable_device(void) { io_del(&device_read_io); CancelIo(device_handle); + + /* According to MSDN, CancelIo() does not necessarily wait for the operation to complete. + To prevent race conditions, make sure the operation is complete + before we close the event it's referencing. */ + + DWORD len; + if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) + logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError())); + if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) + logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError())); + device_write_packet.len = 0; + CloseHandle(device_read_overlapped.hEvent); + CloseHandle(device_write_overlapped.hEvent); ULONG status = 0; - DWORD len; DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL); } @@ -231,12 +271,29 @@ static bool read_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) { DWORD outlen; - OVERLAPPED overlapped = {0}; logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info); - if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, &overlapped)) { + if(device_write_packet.len > 0) { + /* Make sure the previous write operation is finished before we start the next one; + otherwise we end up with multiple write ops referencing the same OVERLAPPED structure, + which according to MSDN is a no-no. */ + + if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) { + int log_level = (GetLastError() == ERROR_IO_INCOMPLETE) ? DEBUG_TRAFFIC : DEBUG_ALWAYS; + logger(log_level, LOG_ERR, "Error while checking previous write to %s %s: %s", device_info, device, winerror(GetLastError())); + return false; + } + } + + /* Copy the packet, since the write operation might still be ongoing after we return. */ + + memcpy(&device_write_packet, packet, sizeof *packet); + + if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped)) + device_write_packet.len = 0; + else if (GetLastError() != ERROR_IO_PENDING) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); return false; } diff --git a/src/multicast_device.c b/src/multicast_device.c index 931a8d0..8dab9e0 100644 --- a/src/multicast_device.c +++ b/src/multicast_device.c @@ -162,7 +162,7 @@ static void close_device(void) { static bool read_packet(vpn_packet_t *packet) { int lenin; - if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) { + if((lenin = recv(device_fd, (void *)DATA(packet), MTU, 0)) <= 0) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, sockstrerror(sockerrno)); return false; @@ -185,7 +185,7 @@ static bool write_packet(vpn_packet_t *packet) { logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info); - if(sendto(device_fd, DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) { + if(sendto(device_fd, (void *)DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) { logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, sockstrerror(sockerrno)); return false; diff --git a/src/names.c b/src/names.c index 8218216..6c518f2 100644 --- a/src/names.c +++ b/src/names.c @@ -1,7 +1,7 @@ /* names.c -- generate commonly used (file)names Copyright (C) 1998-2005 Ivo Timmermans - 2000-2013 Guus Sliepen + 2000-2015 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include "system.h" #include "logger.h" +#include "names.h" #include "xalloc.h" char *netname = NULL; @@ -36,7 +37,7 @@ char *program_name = NULL; /* Set all files and paths according to netname */ -void make_names(void) { +void make_names(bool daemon) { #ifdef HAVE_MINGW HKEY key; char installdir[1024] = ""; @@ -56,14 +57,14 @@ void make_names(void) { if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) { if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) { confdir = xstrdup(installdir); - if(!logfilename) - xasprintf(&logfilename, "%s" SLASH "log" SLASH "%s.log", installdir, identname); if(!confbase) { if(netname) xasprintf(&confbase, "%s" SLASH "%s", installdir, netname); else xasprintf(&confbase, "%s", installdir); } + if(!logfilename) + xasprintf(&logfilename, "%s" SLASH "tinc.log", confbase); } RegCloseKey(key); } @@ -85,21 +86,46 @@ void make_names(void) { if(!pidfilename) xasprintf(&pidfilename, "%s" SLASH "pid", confbase); #else - if(!logfilename) - xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname); + bool fallback = false; + if(daemon) { + if(access(LOCALSTATEDIR, R_OK | W_OK | X_OK)) + fallback = true; + } else { + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname); + if(access(fname, R_OK)) { + snprintf(fname, sizeof fname, "%s" SLASH "pid", confbase); + if(!access(fname, R_OK)) + fallback = true; + } + } - if(!pidfilename) - xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname); + if(!fallback) { + if(!logfilename) + xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname); + + if(!pidfilename) + xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname); + } else { + if(!logfilename) + xasprintf(&logfilename, "%s" SLASH "log", confbase); + + if(!pidfilename) { + if(daemon) + logger(DEBUG_ALWAYS, LOG_WARNING, "Could not access " LOCALSTATEDIR SLASH " (%s), storing pid and socket files in %s" SLASH, strerror(errno), confbase); + xasprintf(&pidfilename, "%s" SLASH "pid", confbase); + } + } #endif if(!unixsocketname) { int len = strlen(pidfilename); unixsocketname = xmalloc(len + 8); - strcpy(unixsocketname, pidfilename); + memcpy(unixsocketname, pidfilename, len); if(len > 4 && !strcmp(pidfilename + len - 4, ".pid")) - strcpy(unixsocketname + len - 4, ".socket"); + strncpy(unixsocketname + len - 4, ".socket", 8); else - strcpy(unixsocketname + len, ".socket"); + strncpy(unixsocketname + len, ".socket", 8); } } @@ -111,4 +137,12 @@ void free_names(void) { free(logfilename); free(confbase); free(confdir); + + identname = NULL; + netname = NULL; + unixsocketname = NULL; + pidfilename = NULL; + logfilename = NULL; + confbase = NULL; + confdir = NULL; } diff --git a/src/names.h b/src/names.h index 1163ff6..a2395af 100644 --- a/src/names.h +++ b/src/names.h @@ -1,7 +1,7 @@ /* names.h -- header for names.c Copyright (C) 1998-2005 Ivo Timmermans - 2000-2013 Guus Sliepen + 2000-2015 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ extern char *logfilename; extern char *pidfilename; extern char *program_name; -extern void make_names(void); +extern void make_names(bool daemon); extern void free_names(void); #endif /* __TINC_NAMES_H__ */ diff --git a/src/net.c b/src/net.c index 91b9305..8328db9 100644 --- a/src/net.c +++ b/src/net.c @@ -1,7 +1,7 @@ /* net.c -- most of the network code Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2015 Guus Sliepen 2006 Scott Lamb 2011 Loïc Grenié @@ -36,10 +36,6 @@ #include "subnet.h" #include "xalloc.h" -#ifdef HAVE_RESOLV_H -#include -#endif - int contradicting_add_edge = 0; int contradicting_del_edge = 0; static int sleeptime = 10; @@ -154,8 +150,9 @@ static void timeout_handler(void *data) { if(c->last_ping_time + pingtimeout <= now.tv_sec) { if(c->edge) { + try_tx(c->node, false); if(c->status.pinged) { - logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time); + logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)(now.tv_sec - c->last_ping_time)); } else if(c->last_ping_time + pinginterval <= now.tv_sec) { send_ping(c); continue; @@ -170,9 +167,10 @@ static void timeout_handler(void *data) { } terminate_connection(c, c->edge); } + } - timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000}); + timeout_set(data, &(struct timeval){1, rand() % 100000}); } static void periodic_handler(void *data) { @@ -183,7 +181,7 @@ static void periodic_handler(void *data) { if(contradicting_del_edge > 100 && contradicting_add_edge > 100) { logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime); - usleep(sleeptime * 1000000LL); + nanosleep(&(struct timespec){sleeptime, 0}, NULL); sleeptime *= 2; if(sleeptime < 0) sleeptime = 3600; @@ -212,10 +210,13 @@ static void periodic_handler(void *data) { and we are not already trying to make one, create an outgoing connection to this node. */ - int r = rand() % node_tree->count; + int r = rand() % (node_tree->count - 1); int i = 0; for splay_each(node_t, n, node_tree) { + if(n == myself) + continue; + if(i++ != r) continue; @@ -311,15 +312,12 @@ static void sighup_handler(void *data) { static void sigalrm_handler(void *data) { logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum)); -#ifdef HAVE_DECL_RES_INIT - res_init(); -#endif retry(); } #endif int reload_configuration(void) { - char *fname = NULL; + char fname[PATH_MAX]; /* Reread our own configuration file */ @@ -333,9 +331,8 @@ int reload_configuration(void) { read_config_options(config_tree, NULL); - xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name); + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name); read_config_file(config_tree, fname); - free(fname); /* Parse some options that are allowed to be changed while tinc is running */ @@ -412,13 +409,12 @@ int reload_configuration(void) { if(c->status.control) continue; - xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name); + snprintf(fname, sizeof 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->edge); } - free(fname); } last_config_check = now.tv_sec; @@ -449,7 +445,7 @@ void retry(void) { */ int main_loop(void) { timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000}); - timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000}); + timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){0, 0}); #ifndef HAVE_MINGW signal_t sighup = {0}; diff --git a/src/net.h b/src/net.h index dcc99a4..c3c82de 100644 --- a/src/net.h +++ b/src/net.h @@ -1,7 +1,7 @@ /* net.h -- header for net.c Copyright (C) 1998-2005 Ivo Timmermans - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -115,6 +115,7 @@ typedef struct listen_socket_t { io_t udp; sockaddr_t sa; bool bindto; + int priority; } listen_socket_t; #include "conf.h" @@ -138,6 +139,14 @@ extern int addressfamily; extern unsigned replaywin; extern bool localdiscovery; +extern bool udp_discovery; +extern int udp_discovery_keepalive_interval; +extern int udp_discovery_interval; +extern int udp_discovery_timeout; + +extern int mtu_info_interval; +extern int udp_info_interval; + extern listen_socket_t listen_socket[MAXSOCKETS]; extern int listen_sockets; extern io_t unix_socket; @@ -183,10 +192,11 @@ extern void handle_new_meta_connection(void *, int); extern void handle_new_unix_connection(void *, int); extern int setup_listen_socket(const sockaddr_t *); extern int setup_vpn_in_socket(const sockaddr_t *); -extern bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len); +extern bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len); extern bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len); extern void send_packet(struct node_t *, vpn_packet_t *); extern void receive_tcppacket(struct connection_t *, const char *, int); +extern bool receive_tcppacket_sptps(struct connection_t *, const char *, int); extern void broadcast_packet(const struct node_t *, vpn_packet_t *); extern char *get_name(void); extern void device_enable(void); @@ -201,7 +211,6 @@ extern void terminate_connection(struct connection_t *, bool); extern bool node_read_ecdsa_public_key(struct node_t *); extern bool read_ecdsa_public_key(struct connection_t *); extern bool read_rsa_public_key(struct connection_t *); -extern void send_mtu_probe(struct node_t *); extern void handle_device_data(void *, int); extern void handle_meta_connection_data(struct connection_t *); extern void regenerate_key(void); @@ -210,6 +219,7 @@ extern void retry(void); extern int reload_configuration(void); extern void load_all_subnets(void); extern void load_all_nodes(void); +extern void try_tx(struct node_t *n, bool); #ifndef HAVE_MINGW #define closesocket(s) close(s) diff --git a/src/net_packet.c b/src/net_packet.c index c146109..21e6c2a 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -1,7 +1,7 @@ /* net_packet.c -- Handles in- and outgoing VPN packets Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2010 Timothy Redaelli 2010 Brandon Black @@ -37,6 +37,8 @@ #include "digest.h" #include "device.h" #include "ethernet.h" +#include "ipv4.h" +#include "ipv6.h" #include "graph.h" #include "logger.h" #include "net.h" @@ -46,6 +48,15 @@ #include "utils.h" #include "xalloc.h" +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* The minimum size of a probe is 14 bytes, but since we normally use CBC mode + encryption, we can add a few extra random bytes without increasing the + resulting packet size. */ +#define MIN_PROBE_SIZE 18 + int keylifetime = 0; #ifdef HAVE_LZO static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS]; @@ -53,226 +64,118 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999 static void send_udppacket(node_t *, vpn_packet_t *); -unsigned replaywin = 16; +unsigned replaywin = 32; bool localdiscovery = true; +bool udp_discovery = true; +int udp_discovery_keepalive_interval = 10; +int udp_discovery_interval = 2; +int udp_discovery_timeout = 30; #define MAX_SEQNO 1073741824 -/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval - mtuprobes == 31: sleep pinginterval seconds - mtuprobes == 32: send 1 burst, sleep pingtimeout second - mtuprobes == 33: no response from other side, restart PMTU discovery process - - Probes are sent in batches of at least three, with random sizes between the - lower and upper boundaries for the MTU thus far discovered. - - After the initial discovery, a fourth packet is added to each batch with a - size larger than the currently known PMTU, to test if the PMTU has increased. - - In case local discovery is enabled, another packet is added to each batch, - which will be broadcast to the local network. - -*/ - -static void send_mtu_probe_handler(void *data) { - node_t *n = data; - int timeout = 1; - - n->mtuprobes++; - - if(!n->status.reachable || !n->status.validkey) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname); - n->mtuprobes = 0; +static void try_fix_mtu(node_t *n) { + if(n->mtuprobes < 0) return; - } - if(n->mtuprobes > 32) { - if(!n->minmtu) { - n->mtuprobes = 31; - timeout = pinginterval; - goto end; - } - - logger(DEBUG_TRAFFIC, LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname); - n->status.udp_confirmed = false; - n->mtuprobes = 1; - n->minmtu = 0; - n->maxmtu = MTU; - } - - if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) { - logger(DEBUG_TRAFFIC, LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname); - n->mtuprobes = 31; - } - - if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { + if(n->mtuprobes == 20 || n->minmtu >= n->maxmtu) { if(n->minmtu > n->maxmtu) n->minmtu = n->maxmtu; else n->maxmtu = n->minmtu; n->mtu = n->minmtu; 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 = -1; } - - if(n->mtuprobes == 31) { - timeout = pinginterval; - goto end; - } else if(n->mtuprobes == 32) { - timeout = pingtimeout; - } - - for(int i = 0; i < 4 + localdiscovery; i++) { - int len; - - if(i == 0) { - if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) - continue; - len = n->maxmtu + 8; - } else if(n->maxmtu <= n->minmtu) { - len = n->maxmtu; - } else { - len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu); - } - - if(len < 64) - len = 64; - - vpn_packet_t packet; - packet.offset = DEFAULT_PACKET_OFFSET; - memset(DATA(&packet), 0, 14); - randomize(DATA(&packet) + 14, len - 14); - packet.len = len; - packet.priority = 0; - n->status.send_locally = i >= 4 && n->mtuprobes <= 10 && n->prevedge; - - logger(DEBUG_TRAFFIC, LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname); - - send_udppacket(n, &packet); - } - - n->status.send_locally = false; - n->probe_counter = 0; - gettimeofday(&n->probe_time, NULL); - - /* Calculate the packet loss of incoming traffic by comparing the rate of - packets received to the rate with which the sequence number has increased. - */ - - if(n->received > n->prev_received) - n->packetloss = 1.0 - (n->received - n->prev_received) / (float)(n->received_seqno - n->prev_received_seqno); - else - n->packetloss = n->received_seqno <= n->prev_received_seqno; - - n->prev_received_seqno = n->received_seqno; - n->prev_received = n->received; - -end: - timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000}); } -void send_mtu_probe(node_t *n) { - timeout_add(&n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0}); - send_mtu_probe_handler(n); +static void udp_probe_timeout_handler(void *data) { + node_t *n = data; + if(!n->status.udp_confirmed) + return; + + logger(DEBUG_TRAFFIC, LOG_INFO, "Too much time has elapsed since last UDP ping response from %s (%s), stopping UDP communication", n->name, n->hostname); + n->status.udp_confirmed = false; + n->maxrecentlen = 0; + n->mtuprobes = 0; + n->minmtu = 0; + n->maxmtu = MTU; } -static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { - if(!DATA(packet)[0]) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe request %d from %s (%s)", packet->len, n->name, n->hostname); +static void send_udp_probe_reply(node_t *n, vpn_packet_t *packet, length_t len) { + if(!n->status.sptps && !n->status.validkey) { + logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP probe reply to %s (%s) but we don't have his key yet", n->name, n->hostname); + return; + } - /* It's a probe request, send back a reply */ + /* Type 2 probe replies were introduced in protocol 17.3 */ + if ((n->options >> 24) >= 3) { + DATA(packet)[0] = 2; + uint16_t len16 = htons(len); + memcpy(DATA(packet) + 1, &len16, 2); + packet->len = MIN_PROBE_SIZE; + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending type 2 probe reply length %u to %s (%s)", len, n->name, n->hostname); - /* Type 2 probe replies were introduced in protocol 17.3 */ - if ((n->options >> 24) >= 3) { - uint8_t *data = DATA(packet); - *data++ = 2; - uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2; - struct timeval now; - gettimeofday(&now, NULL); - uint32_t sec = htonl(now.tv_sec); memcpy(data, &sec, 4); data += 4; - uint32_t usec = htonl(now.tv_usec); memcpy(data, &usec, 4); data += 4; - packet->len -= 10; - } else { - /* Legacy protocol: n won't understand type 2 probe replies. */ - DATA(packet)[0] = 1; - } - - /* Temporarily set udp_confirmed, so that the reply is sent - back exactly the way it came in. */ - - bool udp_confirmed = n->status.udp_confirmed; - n->status.udp_confirmed = true; - send_udppacket(n, packet); - n->status.udp_confirmed = udp_confirmed; } else { - length_t probelen = len; - if (DATA(packet)[0] == 2) { - if (len < 3) - logger(DEBUG_TRAFFIC, LOG_WARNING, "Received invalid (too short) MTU probe reply from %s (%s)", n->name, n->hostname); - else { - uint16_t probelen16; memcpy(&probelen16, DATA(packet) + 1, 2); probelen = ntohs(probelen16); - } - } - logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", DATA(packet)[0], probelen, n->name, n->hostname); + /* Legacy protocol: n won't understand type 2 probe replies. */ + DATA(packet)[0] = 1; + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending type 1 probe reply length %u to %s (%s)", len, n->name, n->hostname); + } - /* It's a valid reply: now we know bidirectional communication - is possible using the address and socket that the reply - packet used. */ + /* Temporarily set udp_confirmed, so that the reply is sent + back exactly the way it came in. */ - n->status.udp_confirmed = true; + bool udp_confirmed = n->status.udp_confirmed; + n->status.udp_confirmed = true; + send_udppacket(n, packet); + n->status.udp_confirmed = udp_confirmed; +} - /* If we haven't established the PMTU yet, restart the discovery process. */ +static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { + if(!DATA(packet)[0]) { + logger(DEBUG_TRAFFIC, LOG_INFO, "Got UDP probe request %d from %s (%s)", packet->len, n->name, n->hostname); + return send_udp_probe_reply(n, packet, len); + } - if(n->mtuprobes > 30) { - if (probelen == n->maxmtu + 8) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); - n->maxmtu = MTU; - n->mtuprobes = 10; - return; - } + if (DATA(packet)[0] == 2) { + // It's a type 2 probe reply, use the length field inside the packet + uint16_t len16; + memcpy(&len16, DATA(packet) + 1, 2); + len = ntohs(len16); + } - if(n->minmtu) - n->mtuprobes = 30; - else - n->mtuprobes = 1; - } + logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d UDP probe reply %d from %s (%s)", DATA(packet)[0], len, n->name, n->hostname); - /* If applicable, raise the minimum supported MTU */ + /* It's a valid reply: now we know bidirectional communication + is possible using the address and socket that the reply + packet used. */ + n->status.udp_confirmed = true; - if(probelen > n->maxmtu) - probelen = n->maxmtu; - if(n->minmtu < probelen) - n->minmtu = probelen; + // Reset the UDP ping timer. + n->udp_ping_sent = now; - /* Calculate RTT and bandwidth. - The RTT is the time between the MTU probe burst was sent and the first - reply is received. The bandwidth is measured using the time between the - arrival of the first and third probe reply (or type 2 probe requests). - */ + if(udp_discovery) { + timeout_del(&n->udp_ping_timeout); + timeout_add(&n->udp_ping_timeout, &udp_probe_timeout_handler, n, &(struct timeval){udp_discovery_timeout, 0}); + } - struct timeval now, diff; - gettimeofday(&now, NULL); - timersub(&now, &n->probe_time, &diff); + if(len > n->maxmtu) { + logger(DEBUG_TRAFFIC, LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); + n->minmtu = len; + n->maxmtu = MTU; + /* Set mtuprobes to 1 so that try_mtu() doesn't reset maxmtu */ + n->mtuprobes = 1; + return; + } else if(n->mtuprobes < 0 && len == n->maxmtu) { + /* We got a maxmtu sized packet, confirming the PMTU is still valid. */ + n->mtuprobes = -1; + n->mtu_ping_sent = now; + } - struct timeval probe_timestamp = now; - if (DATA(packet)[0] == 2 && packet->len >= 11) { - uint32_t sec; memcpy(&sec, DATA(packet) + 3, 4); - uint32_t usec; memcpy(&usec, DATA(packet) + 7, 4); - probe_timestamp.tv_sec = ntohl(sec); - probe_timestamp.tv_usec = ntohl(usec); - } - - n->probe_counter++; + /* If applicable, raise the minimum supported MTU */ - if(n->probe_counter == 1) { - n->rtt = diff.tv_sec + diff.tv_usec * 1e-6; - n->probe_time = probe_timestamp; - } else if(n->probe_counter == 3) { - struct timeval probe_timestamp_diff; - timersub(&probe_timestamp, &n->probe_time, &probe_timestamp_diff); - n->bandwidth = 2.0 * probelen / (probe_timestamp_diff.tv_sec + probe_timestamp_diff.tv_usec * 1e-6); - logger(DEBUG_TRAFFIC, LOG_DEBUG, "%s (%s) RTT %.2f ms, burst bandwidth %.3f Mbit/s, rx packet loss %.2f %%", n->name, n->hostname, n->rtt * 1e3, n->bandwidth * 8e-6, n->packetloss * 1e2); - } + if(n->minmtu < len) { + n->minmtu = len; + try_fix_mtu(n); } } @@ -351,10 +254,14 @@ static bool try_mac(node_t *n, const vpn_packet_t *inpkt) { if(n->status.sptps) return sptps_verify_datagram(&n->sptps, DATA(inpkt), inpkt->len); - if(!digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest)) +#ifdef DISABLE_LEGACY + return false; +#else + if(!n->status.validkey_in || !digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest)) return false; - return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest)); + return digest_verify(n->indigest, inpkt->data, inpkt->len - digest_length(n->indigest), inpkt->data + inpkt->len - digest_length(n->indigest)); +#endif } static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) { @@ -375,15 +282,28 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) { } return false; } - inpkt->offset += 2 * sizeof(node_id_t); - if(!sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t))) { - logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname); + n->status.udppacket = true; + bool result = sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len); + n->status.udppacket = false; + + if(!result) { + /* Uh-oh. It might be that the tunnel is stuck in some corrupted state, + so let's restart SPTPS in case that helps. But don't do that too often + to prevent storms, and because that would make life a little too easy + for external attackers trying to DoS us. */ + if(n->last_req_key < now.tv_sec - 10) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode raw TCP packet from %s (%s), restarting SPTPS", n->name, n->hostname); + send_req_key(n); + } return false; } return true; } - if(!n->status.validkey) { +#ifdef DISABLE_LEGACY + return false; +#else + if(!n->status.validkey_in) { logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname); return false; } @@ -484,13 +404,17 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) { origlen -= MTU/64 + 20; } + if(inpkt->len > n->maxrecentlen) + n->maxrecentlen = inpkt->len; + inpkt->priority = 0; if(!DATA(inpkt)[12] && !DATA(inpkt)[13]) - mtu_probe_h(n, inpkt, origlen); + udp_probe_h(n, inpkt, origlen); else receive_packet(n, inpkt); return true; +#endif } void receive_tcppacket(connection_t *c, const char *buffer, int len) { @@ -510,34 +434,66 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) { receive_packet(c->node, &outpkt); } -static bool try_sptps(node_t *n) { - if(n->status.validkey) - return true; - - /* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET - messages anyway, so there's no need for SPTPS at all. */ - if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY)) +bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) { + if (len < sizeof(node_id_t) + sizeof(node_id_t)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname); return false; - - 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 < now.tv_sec) { - 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 false; + node_t *to = lookup_node_id((node_id_t *)data); + data += sizeof(node_id_t); len -= sizeof(node_id_t); + if(!to) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown destination ID", c->name, c->hostname); + return true; + } + + node_t *from = lookup_node_id((node_id_t *)data); + data += sizeof(node_id_t); len -= sizeof(node_id_t); + if(!from) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown source ID", c->name, c->hostname); + return true; + } + + if(!to->status.reachable) { + /* This can happen in the form of a race condition + if the node just became unreachable. */ + logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot relay TCP packet from %s (%s) because the destination, %s (%s), is unreachable", from->name, from->hostname, to->name, to->hostname); + return true; + } + + /* Help the sender reach us over UDP. + Note that we only do this if we're the destination or the static relay; + otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */ + if(to->via == myself) + send_udp_info(myself, from); + + /* If we're not the final recipient, relay the packet. */ + + if(to != myself) { + send_sptps_data(to, from, 0, data, len); + try_tx(to, true); + return true; + } + + /* The packet is for us */ + + if(!sptps_receive_data(&from->sptps, data, len)) { + /* Uh-oh. It might be that the tunnel is stuck in some corrupted state, + so let's restart SPTPS in case that helps. But don't do that too often + to prevent storms. */ + if(from->last_req_key < now.tv_sec - 10) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode raw TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname); + send_req_key(from); + } + return true; + } + + send_mtu_info(myself, from, MTU); + return true; } static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) { - /* Note: condition order is as intended - even if we have a direct - metaconnection, we want to try SPTPS anyway as it's the only way to - get UDP going */ - if(!try_sptps(n) && !n->connection) + if(!n->status.validkey && !n->connection) return; uint8_t type = 0; @@ -665,10 +621,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { vpn_packet_t *outpkt; int origlen = origpkt->len; size_t outlen; -#if defined(SOL_IP) && defined(IP_TOS) - static int priority = 0; int origpriority = origpkt->priority; -#endif pkt1.offset = DEFAULT_PACKET_OFFSET; pkt2.offset = DEFAULT_PACKET_OFFSET; @@ -681,20 +634,16 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(n->status.sptps) return send_sptps_packet(n, origpkt); +#ifdef DISABLE_LEGACY + return; +#else /* Make sure we have a valid key */ if(!n->status.validkey) { logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s), forwarding via TCP", n->name, n->hostname); - - if(n->last_req_key + 10 <= now.tv_sec) { - send_req_key(n); - n->last_req_key = now.tv_sec; - } - send_tcppacket(n->nexthop->connection, origpkt); - return; } @@ -767,54 +716,72 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(!sa) choose_udp_address(n, &sa, &sock); -#if defined(SOL_IP) && defined(IP_TOS) - if(priorityinheritance && origpriority != priority - && listen_socket[n->sock].sa.sa.sa_family == AF_INET) { - priority = origpriority; - logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority); - if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ - logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno)); - } + if(priorityinheritance && origpriority != listen_socket[sock].priority) { + listen_socket[sock].priority = origpriority; + switch(sa->sa.sa_family) { +#if defined(IPPROTO_IP) && defined(IP_TOS) + case AF_INET: + logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority); + if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */ + logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno)); + break; #endif +#if defined(IPPROTO_IPV6) & defined(IPV6_TCLASS) + case AF_INET6: + logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority); + if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */ + logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno)); + break; +#endif + default: + break; + } + } - if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) { + if(sendto(listen_socket[sock].udp.fd, (void *)SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { if(n->maxmtu >= origlen) n->maxmtu = origlen - 1; if(n->mtu >= origlen) n->mtu = origlen - 1; + try_fix_mtu(n); } else logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno)); } end: origpkt->len = origlen; +#endif } -static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) { +bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len) { node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop; bool direct = from == myself && to == relay; bool relay_supported = (relay->options >> 24) >= 4; bool tcponly = (myself->options | relay->options) & OPTION_TCPONLY; - /* We don't really need the relay's key, but we need to establish a UDP tunnel with it and discover its MTU. */ - if (!direct && relay_supported && !tcponly) - try_sptps(relay); - - /* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU. - TODO: When relaying, the original sender does not know the end-to-end PMTU (it only knows the PMTU of the first hop). - This can lead to scenarios where large packets are sent over UDP to relay, but then relay has no choice but fall back to TCP. */ + /* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU. */ if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) { + if(type != SPTPS_HANDSHAKE && (to->nexthop->connection->options >> 24) >= 7) { + char buf[len + sizeof to->id + sizeof from->id]; char* buf_ptr = buf; + memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id; + memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id; + memcpy(buf_ptr, data, len); buf_ptr += len; + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname); + return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof buf); + } + 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(from == myself && !to->status.validkey) { + /* If this is a handshake packet, use ANS_KEY instead of REQ_KEY, for two reasons: + - We don't want intermediate nodes to switch to UDP to relay these packets; + - ANS_KEY allows us to learn the reflexive UDP address. */ + if(type == SPTPS_HANDSHAKE) { to->incompression = myself->incompression; return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, from->name, to->name, buf, to->incompression); } else { - return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, REQ_SPTPS, buf); + return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, SPTPS_PACKET, buf); } } @@ -841,7 +808,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void choose_local_address(relay, &sa, &sock); if(!sa) choose_udp_address(relay, &sa, &sock); - logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname); + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (UDP)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname); if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { // Compensate for SPTPS overhead @@ -850,6 +817,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void relay->maxmtu = len - 1; if(relay->mtu >= len) relay->mtu = len - 1; + try_fix_mtu(relay); } else { logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", relay->name, relay->hostname, sockstrerror(sockerrno)); return false; @@ -859,10 +827,6 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void return true; } -bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) { - return send_sptps_data_priv(handle, myself, type, data, len); -} - bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) { node_t *from = handle; @@ -884,9 +848,15 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t inpkt.offset = DEFAULT_PACKET_OFFSET; if(type == PKT_PROBE) { + if(!from->status.udppacket) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got SPTPS PROBE packet from %s (%s) via TCP", from->name, from->hostname); + return false; + } inpkt.len = len; memcpy(DATA(&inpkt), data, len); - mtu_probe_h(from, &inpkt, len); + if(inpkt.len > from->maxrecentlen) + from->maxrecentlen = inpkt.len; + udp_probe_h(from, &inpkt, len); return true; } @@ -937,56 +907,412 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t } } + if(from->status.udppacket && inpkt.len > from->maxrecentlen) + from->maxrecentlen = inpkt.len; + receive_packet(from, &inpkt); return true; } -/* - send a packet to the given vpn ip. +// This function tries to get SPTPS keys, if they aren't already known. +// This function makes no guarantees - it is up to the caller to check the node's state to figure out if the keys are available. +static void try_sptps(node_t *n) { + if(n->status.validkey) + return; + + 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 < now.tv_sec) { + 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; +} + +static void send_udp_probe_packet(node_t *n, int len) { + vpn_packet_t packet; + packet.offset = DEFAULT_PACKET_OFFSET; + memset(DATA(&packet), 0, 14); + randomize(DATA(&packet) + 14, len - 14); + packet.len = len; + packet.priority = 0; + + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending UDP probe length %d to %s (%s)", len, n->name, n->hostname); + + send_udppacket(n, &packet); +} + +// This function tries to establish a UDP tunnel to a node so that packets can be sent. +// If a tunnel is already established, it makes sure it stays up. +// This function makes no guarantees - it is up to the caller to check the node's state to figure out if UDP is usable. +static void try_udp(node_t* n) { + if(!udp_discovery) + return; + + /* Send gratuitous probe replies to 1.1 nodes. */ + + if((n->options >> 24) >= 3 && n->status.udp_confirmed) { + struct timeval ping_tx_elapsed; + timersub(&now, &n->udp_reply_sent, &ping_tx_elapsed); + + if(ping_tx_elapsed.tv_sec >= udp_discovery_keepalive_interval - 1) { + n->udp_reply_sent = now; + if(n->maxrecentlen) { + vpn_packet_t pkt; + pkt.len = n->maxrecentlen; + pkt.offset = DEFAULT_PACKET_OFFSET; + memset(DATA(&pkt), 0, 14); + randomize(DATA(&pkt) + 14, MIN_PROBE_SIZE - 14); + send_udp_probe_reply(n, &pkt, pkt.len); + n->maxrecentlen = 0; + } + } + } + + /* Probe request */ + + struct timeval ping_tx_elapsed; + timersub(&now, &n->udp_ping_sent, &ping_tx_elapsed); + + int interval = n->status.udp_confirmed ? udp_discovery_keepalive_interval : udp_discovery_interval; + + if(ping_tx_elapsed.tv_sec >= interval) { + send_udp_probe_packet(n, MIN_PROBE_SIZE); + n->udp_ping_sent = now; + + if(localdiscovery && !n->status.udp_confirmed && n->prevedge) { + n->status.send_locally = true; + send_udp_probe_packet(n, MIN_PROBE_SIZE); + n->status.send_locally = false; + } + } +} + +static length_t choose_initial_maxmtu(node_t *n) { +#ifdef IP_MTU + + int sock = -1; + + const sockaddr_t *sa = NULL; + int sockindex; + choose_udp_address(n, &sa, &sockindex); + if(!sa) + return MTU; + + sock = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP); + if(sock < 0) { + logger(DEBUG_TRAFFIC, LOG_ERR, "Creating MTU assessment socket for %s (%s) failed: %s", n->name, n->hostname, sockstrerror(sockerrno)); + return MTU; + } + + if(connect(sock, &sa->sa, SALEN(sa->sa))) { + logger(DEBUG_TRAFFIC, LOG_ERR, "Connecting MTU assessment socket for %s (%s) failed: %s", n->name, n->hostname, sockstrerror(sockerrno)); + close(sock); + return MTU; + } + + int ip_mtu; + socklen_t ip_mtu_len = sizeof ip_mtu; + if(getsockopt(sock, IPPROTO_IP, IP_MTU, &ip_mtu, &ip_mtu_len)) { + logger(DEBUG_TRAFFIC, LOG_ERR, "getsockopt(IP_MTU) on %s (%s) failed: %s", n->name, n->hostname, sockstrerror(sockerrno)); + close(sock); + return MTU; + } + + close(sock); + + /* getsockopt(IP_MTU) returns the MTU of the physical interface. + We need to remove various overheads to get to the tinc MTU. */ + length_t mtu = ip_mtu; + mtu -= (sa->sa.sa_family == AF_INET6) ? sizeof(struct ip6_hdr) : sizeof(struct ip); + mtu -= 8; /* UDP */ + if(n->status.sptps) { + mtu -= SPTPS_DATAGRAM_OVERHEAD; + if((n->options >> 24) >= 4) + mtu -= sizeof(node_id_t) + sizeof(node_id_t); +#ifndef DISABLE_LEGACY + } else { + mtu -= digest_length(n->outdigest); + + /* Now it's tricky. We use CBC mode, so the length of the + encrypted payload must be a multiple of the blocksize. The + sequence number is also part of the encrypted payload, so we + must account for it after correcting for the blocksize. + Furthermore, the padding in the last block must be at least + 1 byte. */ + + length_t blocksize = cipher_blocksize(n->outcipher); + + if(blocksize > 1) { + mtu /= blocksize; + mtu *= blocksize; + mtu--; + } + + mtu -= 4; // seqno +#endif + } + + if (mtu < 512) { + logger(DEBUG_TRAFFIC, LOG_ERR, "getsockopt(IP_MTU) on %s (%s) returned absurdly small value: %d", n->name, n->hostname, ip_mtu); + return MTU; + } + if (mtu > MTU) + return MTU; + + logger(DEBUG_TRAFFIC, LOG_INFO, "Using system-provided maximum tinc MTU for %s (%s): %hd", n->name, n->hostname, mtu); + return mtu; + +#else + + return MTU; + +#endif +} + +/* This function tries to determines the MTU of a node. + By calling this function repeatedly, n->minmtu will be progressively + increased, and at some point, n->mtu will be fixed to n->minmtu. If the MTU + is already fixed, this function checks if it can be increased. */ + +static void try_mtu(node_t *n) { + if(!(n->options & OPTION_PMTU_DISCOVERY)) + return; + + if(udp_discovery && !n->status.udp_confirmed) { + n->maxrecentlen = 0; + n->mtuprobes = 0; + n->minmtu = 0; + n->maxmtu = MTU; + return; + } + + /* mtuprobes == 0..19: initial discovery, send bursts with 1 second interval, mtuprobes++ + mtuprobes == 20: fix MTU, and go to -1 + mtuprobes == -1: send one maxmtu and one maxmtu+1 probe every pinginterval + mtuprobes ==-2..-3: send one maxmtu probe every second + mtuprobes == -4: maxmtu no longer valid, reset minmtu and maxmtu and go to 0 */ + + struct timeval elapsed; + timersub(&now, &n->mtu_ping_sent, &elapsed); + if(n->mtuprobes >= 0) { + if(n->mtuprobes != 0 && elapsed.tv_sec == 0 && elapsed.tv_usec < 333333) + return; + } else { + if(n->mtuprobes < -1) { + if(elapsed.tv_sec < 1) + return; + } else { + if(elapsed.tv_sec < pinginterval) + return; + } + } + + n->mtu_ping_sent = now; + + try_fix_mtu(n); + + if(n->mtuprobes < -3) { + /* We lost three MTU probes, restart discovery */ + logger(DEBUG_TRAFFIC, LOG_INFO, "Decrease in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); + n->mtuprobes = 0; + n->minmtu = 0; + } + + if(n->mtuprobes < 0) { + /* After the initial discovery, we only send one maxmtu and one + maxmtu+1 probe to detect PMTU increases. */ + send_udp_probe_packet(n, n->maxmtu); + if(n->mtuprobes == -1 && n->maxmtu + 1 < MTU) + send_udp_probe_packet(n, n->maxmtu + 1); + n->mtuprobes--; + } else { + /* Before initial discovery begins, set maxmtu to the most likely value. + If it's underestimated, we will correct it after initial discovery. */ + if(n->mtuprobes == 0) + n->maxmtu = choose_initial_maxmtu(n); + + for (;;) { + /* Decreasing the number of probes per cycle might make the algorithm react faster to lost packets, + but it will typically increase convergence time in the no-loss case. */ + const length_t probes_per_cycle = 8; + + /* This magic value was determined using math simulations. + It will result in a 1329-byte first probe, followed (if there was a reply) by a 1407-byte probe. + Since 1407 is just below the range of tinc MTUs over typical networks, + this fine-tuning allows tinc to cover a lot of ground very quickly. + This fine-tuning is only valid for maxmtu = MTU; if maxmtu is smaller, + then it's better to use a multiplier of 1. Indeed, this leads to an interesting scenario + if choose_initial_maxmtu() returns the actual MTU value - it will get confirmed with one single probe. */ + const float multiplier = (n->maxmtu == MTU) ? 0.97 : 1; + + const float cycle_position = probes_per_cycle - (n->mtuprobes % probes_per_cycle) - 1; + const length_t minmtu = MAX(n->minmtu, 512); + const float interval = n->maxmtu - minmtu; + + /* The core of the discovery algorithm is this exponential. + It produces very large probes early in the cycle, and then it very quickly decreases the probe size. + This reflects the fact that in the most difficult cases, we don't get any feedback for probes that + are too large, and therefore we need to concentrate on small offsets so that we can quickly converge + on the precise MTU as we are approaching it. + The last probe of the cycle is always 1 byte in size - this is to make sure we'll get at least one + reply per cycle so that we can make progress. */ + const length_t offset = powf(interval, multiplier * cycle_position / (probes_per_cycle - 1)); + + length_t maxmtu = n->maxmtu; + send_udp_probe_packet(n, minmtu + offset); + /* If maxmtu changed, it means the probe was rejected by the system because it was too large. + In that case, we recalculate with the new maxmtu and try again. */ + if(n->mtuprobes < 0 || maxmtu == n->maxmtu) + break; + } + + if(n->mtuprobes >= 0) + n->mtuprobes++; + } +} + +/* These functions try to establish a tunnel to a node (or its relay) so that + packets can be sent (e.g. exchange keys). + If a tunnel is already established, it tries to improve it (e.g. by trying + to establish a UDP tunnel instead of TCP). This function makes no + guarantees - it is up to the caller to check the node's state to figure out + if TCP and/or UDP is usable. By calling this function repeatedly, the + tunnel is gradually improved until we hit the wall imposed by the underlying + network environment. It is recommended to call this function every time a + packet is sent (or intended to be sent) to a node, so that the tunnel keeps + improving as packets flow, and then gracefully downgrades itself as it goes + idle. +*/ + +static void try_tx_sptps(node_t *n, bool mtu) { + /* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET + messages anyway, so there's no need for SPTPS at all. */ + + if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY)) + return; + + /* Otherwise, try to do SPTPS authentication with n if necessary. */ + + try_sptps(n); + + /* Do we need to statically relay packets? */ + + node_t *via = (n->via == myself) ? n->nexthop : n->via; + + /* If we do have a static relay, try everything with that one instead, if it supports relaying. */ + + if(via != n) { + if((via->options >> 24) < 4) + return; + return try_tx(via, mtu); + } + + /* Otherwise, try to establish UDP connectivity. */ + + try_udp(n); + if(mtu) + try_mtu(n); + + /* If we don't have UDP connectivity (yet), we need to use a dynamic relay (nexthop) + while we try to establish direct connectivity. */ + + if(!n->status.udp_confirmed && n != n->nexthop && (n->nexthop->options >> 24) >= 4) + try_tx(n->nexthop, mtu); +} + +static void try_tx_legacy(node_t *n, bool mtu) { + /* Does he have our key? If not, send one. */ + + if(!n->status.validkey_in) + send_ans_key(n); + + /* Check if we already have a key, or request one. */ + + if(!n->status.validkey) { + if(n->last_req_key + 10 <= now.tv_sec) { + send_req_key(n); + n->last_req_key = now.tv_sec; + } + return; + } + + try_udp(n); + if(mtu) + try_mtu(n); +} + +void try_tx(node_t *n, bool mtu) { + if(!n->status.reachable) + return; + if(n->status.sptps) + try_tx_sptps(n, mtu); + else + try_tx_legacy(n, mtu); +} + void send_packet(node_t *n, vpn_packet_t *packet) { - node_t *via; + // If it's for myself, write it to the tun/tap device. if(n == myself) { - if(overwrite_mac) + if(overwrite_mac) { memcpy(DATA(packet), mymac.x, ETH_ALEN); + // Use an arbitrary fake source address. + memcpy(DATA(packet) + ETH_ALEN, DATA(packet), ETH_ALEN); + DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; + } n->out_packets++; n->out_bytes += packet->len; devops.write(packet); return; } - logger(DEBUG_TRAFFIC, LOG_ERR, "Sending packet of %d bytes to %s (%s)", - packet->len, n->name, n->hostname); + logger(DEBUG_TRAFFIC, LOG_ERR, "Sending packet of %d bytes to %s (%s)", packet->len, n->name, n->hostname); + + // If the node is not reachable, drop it. if(!n->status.reachable) { - logger(DEBUG_TRAFFIC, LOG_INFO, "Node %s (%s) is not reachable", - n->name, n->hostname); + logger(DEBUG_TRAFFIC, LOG_INFO, "Node %s (%s) is not reachable", n->name, n->hostname); return; } + // Keep track of packet statistics. + n->out_packets++; n->out_bytes += packet->len; + // Check if it should be sent as an SPTPS packet. + if(n->status.sptps) { send_sptps_packet(n, packet); + try_tx(n, true); return; } - via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via; + // Determine which node to actually send it to. + + node_t *via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via; if(via != n) - logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet to %s via %s (%s)", - n->name, via->name, n->via->hostname); + logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet to %s via %s (%s)", n->name, via->name, n->via->hostname); + + // Try to send via UDP, unless TCP is forced. if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) { if(!send_tcppacket(via->connection, packet)) terminate_connection(via->connection, true); - } else - send_udppacket(via, packet); -} + return; + } -/* Broadcast a packet using the minimum spanning tree */ + send_udppacket(via, packet); + try_tx(via, true); +} void broadcast_packet(const node_t *from, vpn_packet_t *packet) { // Always give ourself a copy of the packet. @@ -1028,47 +1354,208 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) { } } +/* We got a packet from some IP address, but we don't know who sent it. Try to + verify the message authentication code against all active session keys. + Since this is actually an expensive operation, we only do a full check once + a minute, the rest of the time we only check against nodes for which we know + an IP address that matches the one from the packet. */ + static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { - node_t *n = NULL; + node_t *match = NULL; bool hard = false; static time_t last_hard_try = 0; - for splay_each(edge_t, e, edge_weight_tree) { - if(!e->to->status.reachable || e->to == myself) + for splay_each(node_t, n, node_tree) { + if(!n->status.reachable || n == myself) continue; - if(sockaddrcmp_noport(from, &e->address)) { + if(!n->status.validkey_in && !(n->status.sptps && n->sptps.instate)) + continue; + + bool soft = false; + + for splay_each(edge_t, e, n->edge_tree) { + if(!e->reverse) + continue; + if(!sockaddrcmp_noport(from, &e->reverse->address)) { + soft = true; + break; + } + } + + if(!soft) { if(last_hard_try == now.tv_sec) continue; hard = true; } - if(!try_mac(e->to, pkt)) + if(!try_mac(n, pkt)) continue; - n = e->to; + match = n; break; } if(hard) last_hard_try = now.tv_sec; - last_hard_try = now.tv_sec; - return n; + return match; +} + +static void handle_incoming_vpn_packet(listen_socket_t *ls, vpn_packet_t *pkt, sockaddr_t *addr) { + char *hostname; + node_id_t nullid = {}; + node_t *from, *to; + bool direct = false; + + sockaddrunmap(addr); /* Some braindead IPv6 implementations do stupid things. */ + + // Try to figure out who sent this packet. + + node_t *n = lookup_node_udp(addr); + + if(n && !n->status.udp_confirmed) + n = NULL; // Don't believe it if we don't have confirmation yet. + + if(!n) { + // It might be from a 1.1 node, which might have a source ID in the packet. + pkt->offset = 2 * sizeof(node_id_t); + from = lookup_node_id(SRCID(pkt)); + if(from && !memcmp(DSTID(pkt), &nullid, sizeof nullid) && from->status.sptps) { + if(sptps_verify_datagram(&from->sptps, DATA(pkt), pkt->len - 2 * sizeof(node_id_t))) + n = from; + else + goto skip_harder; + } + } + + if(!n) { + pkt->offset = 0; + n = try_harder(addr, pkt); + } + +skip_harder: + if(!n) { + if(debug_level >= DEBUG_PROTOCOL) { + hostname = sockaddr2hostname(addr); + logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname); + free(hostname); + } + return; + } + + pkt->offset = 0; + + if(n->status.sptps) { + bool relay_enabled = (n->options >> 24) >= 4; + if (relay_enabled) { + pkt->offset = 2 * sizeof(node_id_t); + pkt->len -= pkt->offset; + } + + if(!memcmp(DSTID(pkt), &nullid, sizeof nullid) || !relay_enabled) { + direct = true; + from = n; + to = myself; + } else { + from = lookup_node_id(SRCID(pkt)); + to = lookup_node_id(DSTID(pkt)); + } + if(!from || !to) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname); + return; + } + + if(!to->status.reachable) { + /* This can happen in the form of a race condition + if the node just became unreachable. */ + logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot relay packet from %s (%s) because the destination, %s (%s), is unreachable", from->name, from->hostname, to->name, to->hostname); + return; + } + + /* The packet is supposed to come from the originator or its static relay + (i.e. with no dynamic relays in between). + If it did not, "help" the static relay by sending it UDP info. + Note that we only do this if we're the destination or the static relay; + otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */ + + if(n != from->via && to->via == myself) + send_udp_info(myself, from); + + /* If we're not the final recipient, relay the packet. */ + + if(to != myself) { + send_sptps_data(to, from, 0, DATA(pkt), pkt->len); + try_tx(to, true); + return; + } + } else { + direct = true; + from = n; + } + + if(!receive_udppacket(from, pkt)) + return; + + n->sock = ls - listen_socket; + if(direct && sockaddrcmp(addr, &n->address)) + update_node_udp(n, addr); + + /* If the packet went through a relay, help the sender find the appropriate MTU + through the relay path. */ + + if(!direct) + send_mtu_info(myself, n, MTU); } void handle_incoming_vpn_data(void *data, int flags) { listen_socket_t *ls = data; + +#ifdef HAVE_RECVMMSG +#define MAX_MSG 64 + static int num = MAX_MSG; + static vpn_packet_t pkt[MAX_MSG]; + static sockaddr_t addr[MAX_MSG]; + static struct mmsghdr msg[MAX_MSG]; + static struct iovec iov[MAX_MSG]; + + for(int i = 0; i < num; i++) { + pkt[i].offset = 0; + + iov[i] = (struct iovec){ + .iov_base = DATA(&pkt[i]), + .iov_len = MAXSIZE, + }; + + msg[i].msg_hdr = (struct msghdr){ + .msg_name = &addr[i].sa, + .msg_namelen = sizeof addr[i], + .msg_iov = &iov[i], + .msg_iovlen = 1, + }; + } + + num = recvmmsg(ls->udp.fd, msg, MAX_MSG, MSG_DONTWAIT, NULL); + + if(num < 0) { + if(!sockwouldblock(sockerrno)) + logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); + return; + } + + for(int i = 0; i < num; i++) { + pkt[i].len = msg[i].msg_len; + if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE) + continue; + handle_incoming_vpn_packet(ls, &pkt[i], &addr[i]); + } +#else vpn_packet_t pkt; - char *hostname; - node_id_t nullid = {}; sockaddr_t addr = {}; socklen_t addrlen = sizeof addr; - node_t *from, *to; - bool direct = false; pkt.offset = 0; - int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen); + int len = recvfrom(ls->udp.fd, (void *)DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen); if(len <= 0 || len > MAXSIZE) { if(!sockwouldblock(sockerrno)) @@ -1078,71 +1565,8 @@ void handle_incoming_vpn_data(void *data, int flags) { pkt.len = len; - sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */ - - // Try to figure out who sent this packet. - - node_t *n = lookup_node_udp(&addr); - - if(!n) { - // It might be from a 1.1 node, which might have a source ID in the packet. - pkt.offset = 2 * sizeof(node_id_t); - from = lookup_node_id(SRCID(&pkt)); - if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) { - if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t))) - n = from; - else - goto skip_harder; - } - } - - if(!n) { - pkt.offset = 0; - n = try_harder(&addr, &pkt); - } - -skip_harder: - if(!n) { - if(debug_level >= DEBUG_PROTOCOL) { - hostname = sockaddr2hostname(&addr); - logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname); - free(hostname); - } - return; - } - - if(n->status.sptps) { - pkt.offset = 2 * sizeof(node_id_t); - - if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid)) { - direct = true; - from = n; - to = myself; - } else { - from = lookup_node_id(SRCID(&pkt)); - to = lookup_node_id(DSTID(&pkt)); - } - if(!from || !to) { - logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname); - return; - } - - if(to != myself) { - send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)); - return; - } - } else { - direct = true; - from = n; - } - - pkt.offset = 0; - if(!receive_udppacket(from, &pkt)) - return; - - n->sock = ls - listen_socket; - if(direct && sockaddrcmp(&addr, &n->address)) - update_node_udp(n, &addr); + handle_incoming_vpn_packet(ls, &pkt, &addr); +#endif } void handle_device_data(void *data, int flags) { diff --git a/src/net_setup.c b/src/net_setup.c index 29f1212..30e6f84 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -1,7 +1,7 @@ /* net_setup.c -- Setup. Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2006 Scott Lamb 2010 Brandon Black @@ -43,6 +43,10 @@ #include "utils.h" #include "xalloc.h" +#ifdef HAVE_MINIUPNPC +#include "upnp.h" +#endif + char *myport; static char *myname; static io_t device_io; @@ -137,18 +141,17 @@ bool read_ecdsa_public_key(connection_t *c) { } c->ecdsa = ecdsa_read_pem_public_key(fp); - fclose(fp); - if(!c->ecdsa) + if(!c->ecdsa && errno != ENOENT) logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname); + + fclose(fp); free(fname); return c->ecdsa; } +#ifndef DISABLE_LEGACY bool read_rsa_public_key(connection_t *c) { - if(ecdsa_active(c->ecdsa)) - return true; - FILE *fp; char *fname; char *n; @@ -182,6 +185,7 @@ bool read_rsa_public_key(connection_t *c) { free(fname); return c->rsa; } +#endif static bool read_ecdsa_private_key(void) { FILE *fp; @@ -226,14 +230,14 @@ static bool read_ecdsa_private_key(void) { static bool read_invitation_key(void) { FILE *fp; - char *fname; + char fname[PATH_MAX]; if(invitation_key) { ecdsa_free(invitation_key); invitation_key = NULL; } - xasprintf(&fname, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); + snprintf(fname, sizeof fname, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); fp = fopen(fname, "r"); @@ -244,10 +248,10 @@ static bool read_invitation_key(void) { logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname); } - free(fname); return invitation_key; } +#ifndef DISABLE_LEGACY static bool read_rsa_private_key(void) { FILE *fp; char *fname; @@ -304,6 +308,7 @@ static bool read_rsa_private_key(void) { free(fname); return myself->connection->rsa; } +#endif static timeout_t keyexpire_timeout; @@ -315,6 +320,8 @@ static void keyexpire_handler(void *data) { void regenerate_key(void) { logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys"); send_key_changed(); + for splay_each(node_t, n, node_tree) + n->status.validkey_in = false; } /* @@ -323,13 +330,12 @@ void regenerate_key(void) { void load_all_subnets(void) { DIR *dir; struct dirent *ent; - char *dname; + char dname[PATH_MAX]; - xasprintf(&dname, "%s" SLASH "hosts", confbase); + snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase); dir = opendir(dname); if(!dir) { logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); - free(dname); return; } @@ -362,6 +368,7 @@ void load_all_subnets(void) { if((s2 = lookup_subnet(n, s))) { s2->expires = -1; + free(s); } else { subnet_add(n, s); } @@ -376,13 +383,12 @@ void load_all_subnets(void) { void load_all_nodes(void) { DIR *dir; struct dirent *ent; - char *dname; + char dname[PATH_MAX]; - xasprintf(&dname, "%s" SLASH "hosts", confbase); + snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase); dir = opendir(dname); if(!dir) { logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); - free(dname); return; } @@ -506,6 +512,14 @@ bool setup_myself_reloadable(void) { if(myself->options & OPTION_TCPONLY) myself->options |= OPTION_INDIRECT; + get_config_bool(lookup_config(config_tree, "UDPDiscovery"), &udp_discovery); + get_config_int(lookup_config(config_tree, "UDPDiscoveryKeepaliveInterval"), &udp_discovery_keepalive_interval); + get_config_int(lookup_config(config_tree, "UDPDiscoveryInterval"), &udp_discovery_interval); + get_config_int(lookup_config(config_tree, "UDPDiscoveryTimeout"), &udp_discovery_timeout); + + get_config_int(lookup_config(config_tree, "MTUInfoInterval"), &mtu_info_interval); + get_config_int(lookup_config(config_tree, "UDPInfoInterval"), &udp_info_interval); + get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery); @@ -577,9 +591,14 @@ bool setup_myself_reloadable(void) { subnet_add(NULL, s); } -#if !defined(SOL_IP) || !defined(IP_TOS) +#if !defined(IPPROTO_IP) || !defined(IP_TOS) if(priorityinheritance) - logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance"); + logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv4 connections", "PriorityInheritance"); +#endif + +#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS) + if(priorityinheritance) + logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv6 connections", "PriorityInheritance"); #endif if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) @@ -652,6 +671,9 @@ static bool add_listen_address(char *address, bool bindto) { hint.ai_protocol = IPPROTO_TCP; hint.ai_flags = AI_PASSIVE; +#if HAVE_DECL_RES_INIT + res_init(); +#endif int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai); free(address); @@ -773,6 +795,13 @@ static bool setup_myself(void) { myself->options |= PROT_MINOR << 24; +#ifdef DISABLE_LEGACY + experimental = read_ecdsa_private_key(); + if(!experimental) { + logger(DEBUG_ALWAYS, LOG_ERR, "No private key available, cannot start tinc!"); + return false; + } +#else if(!get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental)) { experimental = read_ecdsa_private_key(); if(!experimental) @@ -790,6 +819,7 @@ static bool setup_myself(void) { return false; } } +#endif /* Ensure myport is numeric */ @@ -831,14 +861,14 @@ static bool setup_myself(void) { } if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { - if(udp_rcvbuf <= 0) { + 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) { + if(udp_sndbuf < 0) { logger(DEBUG_ALWAYS, LOG_ERR, "UDPSndBuf cannot be negative!"); return false; } @@ -854,6 +884,7 @@ static bool setup_myself(void) { sptps_replaywin = replaywin; } +#ifndef DISABLE_LEGACY /* Generate packet encryption key */ if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) @@ -891,6 +922,7 @@ static bool setup_myself(void) { } free(digest); +#endif /* Compression */ @@ -939,6 +971,7 @@ static bool setup_myself(void) { else if(!strcasecmp(type, "vde")) devops = vde_devops; #endif + free(type); } get_config_bool(lookup_config(config_tree, "DeviceStandby"), &device_standby); @@ -1035,6 +1068,25 @@ static bool setup_myself(void) { xasprintf(&myself->hostname, "MYSELF port %s", myport); myself->connection->hostname = xstrdup(myself->hostname); + char *upnp = NULL; + get_config_string(lookup_config(config_tree, "UPnP"), &upnp); + bool upnp_tcp = false; + bool upnp_udp = false; + if (upnp) { + if (!strcasecmp(upnp, "yes")) + upnp_tcp = upnp_udp = true; + else if (!strcasecmp(upnp, "udponly")) + upnp_udp = true; + free(upnp); + } + if (upnp_tcp || upnp_udp) { +#ifdef HAVE_MINIUPNPC + upnp_init(upnp_tcp, upnp_udp); +#else + logger(DEBUG_ALWAYS, LOG_WARNING, "UPnP was requested, but tinc isn't built with miniupnpc support!"); +#endif + } + /* Done. */ last_config_check = now.tv_sec; @@ -1102,8 +1154,7 @@ void close_network_connections(void) { if(myself && myself->connection) { subnet_update(myself, NULL, false); - terminate_connection(myself->connection, false); - free_connection(myself->connection); + connection_del(myself->connection); } for(int i = 0; i < listen_sockets; i++) { diff --git a/src/net_socket.c b/src/net_socket.c index 1bf9d16..bafea64 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -1,7 +1,7 @@ /* net_socket.c -- Handle various kinds of sockets. Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2006 Scott Lamb 2009 Florian Forster @@ -35,16 +35,11 @@ #include "utils.h" #include "xalloc.h" -/* Needed on Mac OS/X */ -#ifndef SOL_TCP -#define SOL_TCP IPPROTO_TCP -#endif - int addressfamily = AF_UNSPEC; int maxtimeout = 900; int seconds_till_retry = 5; -int udp_rcvbuf = 0; -int udp_sndbuf = 0; +int udp_rcvbuf = 1024 * 1024; +int udp_sndbuf = 1024 * 1024; int max_connection_burst = 100; listen_socket_t listen_socket[MAXSOCKETS]; @@ -73,14 +68,19 @@ static void configure_tcp(connection_t *c) { } #endif -#if defined(SOL_TCP) && defined(TCP_NODELAY) +#if defined(IPPROTO_TCP) && defined(TCP_NODELAY) option = 1; - setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option); + setsockopt(c->socket, IPPROTO_TCP, TCP_NODELAY, (void *)&option, sizeof option); #endif -#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) +#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) option = IPTOS_LOWDELAY; - setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option); + setsockopt(c->socket, IPPROTO_IP, IP_TOS, (void *)&option, sizeof option); +#endif + +#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY) + option = IPTOS_LOWDELAY; + setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof option); #endif } @@ -163,9 +163,9 @@ int setup_listen_socket(const sockaddr_t *sa) { option = 1; setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); -#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) +#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) - setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); + setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); #endif if(get_config_string @@ -261,10 +261,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { #define IP_DONTFRAGMENT IP_DONTFRAG #endif -#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) +#if defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) if(myself->options & OPTION_PMTU_DISCOVERY) { option = IP_PMTUDISC_DO; - setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); + setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); } #elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT) if(myself->options & OPTION_PMTU_DISCOVERY) { @@ -273,10 +273,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { } #endif -#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) +#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) if(myself->options & OPTION_PMTU_DISCOVERY) { option = IPV6_PMTUDISC_DO; - setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); + setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); } #elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG) if(myself->options & OPTION_PMTU_DISCOVERY) { @@ -517,10 +517,10 @@ begin: #endif if(proxytype != PROXY_EXEC) { -#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) +#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) int option = 1; if(c->address.sa.sa_family == AF_INET6) - setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); + setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); #endif bind_to_interface(c->socket); @@ -547,10 +547,13 @@ begin: /* Now that there is a working socket, fill in the rest and register this connection. */ + c->last_ping_time = time(NULL); c->status.connecting = true; c->name = xstrdup(outgoing->name); +#ifndef DISABLE_LEGACY c->outcipher = myself->connection->outcipher; c->outdigest = myself->connection->outdigest; +#endif c->outmaclength = myself->connection->outmaclength; c->outcompression = myself->connection->outcompression; c->last_ping_time = now.tv_sec; @@ -602,9 +605,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) { if(n && n->connection) { logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name); - - n->connection->outgoing = outgoing; - return; + if(!n->connection->outgoing) { + n->connection->outgoing = outgoing; + return; + } else { + goto remove; + } } init_configuration(&outgoing->config_tree); @@ -615,12 +621,16 @@ void setup_outgoing_connection(outgoing_t *outgoing) { if(n) outgoing->aip = outgoing->ai = get_known_addresses(n); if(!outgoing->ai) { - logger(DEBUG_ALWAYS, LOG_ERR, "No address known for %s", outgoing->name); - return; + logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name); + goto remove; } } do_outgoing_connection(outgoing); + return; + +remove: + list_delete(outgoing_list, outgoing); } /* @@ -696,8 +706,10 @@ void handle_new_meta_connection(void *data, int flags) { c = new_connection(); c->name = xstrdup(""); +#ifndef DISABLE_LEGACY c->outcipher = myself->connection->outcipher; c->outdigest = myself->connection->outdigest; +#endif c->outmaclength = myself->connection->outmaclength; c->outcompression = myself->connection->outcompression; @@ -796,6 +808,11 @@ void try_outgoing_connections(void) { continue; } + if(!strcmp(name, myself->name)) { + free(name); + continue; + } + bool found = false; for list_each(outgoing_t, outgoing, outgoing_list) { diff --git a/src/netutl.c b/src/netutl.c index 989a152..2eebb64 100644 --- a/src/netutl.c +++ b/src/netutl.c @@ -39,6 +39,9 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock hint.ai_family = addressfamily; hint.ai_socktype = socktype; +#if HAVE_DECL_RES_INIT + res_init(); +#endif err = getaddrinfo(address, service, &hint, &ai); if(err) { @@ -80,7 +83,13 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) { char *scopeid; int err; - if(sa->sa.sa_family == AF_UNKNOWN) { + if(sa->sa.sa_family == AF_UNSPEC) { + if(addrstr) + *addrstr = xstrdup("unspec"); + if(portstr) + *portstr = xstrdup("unspec"); + return; + } else if(sa->sa.sa_family == AF_UNKNOWN) { if(addrstr) *addrstr = xstrdup(sa->unknown.address); if(portstr) @@ -112,7 +121,10 @@ char *sockaddr2hostname(const sockaddr_t *sa) { char port[NI_MAXSERV] = "unknown"; int err; - if(sa->sa.sa_family == AF_UNKNOWN) { + if(sa->sa.sa_family == AF_UNSPEC) { + xasprintf(&str, "unspec port unspec"); + return str; + } else if(sa->sa.sa_family == AF_UNKNOWN) { xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port); return str; } diff --git a/src/node.c b/src/node.c index e97bfaf..7242e95 100644 --- a/src/node.c +++ b/src/node.c @@ -30,12 +30,11 @@ #include "utils.h" #include "xalloc.h" -static digest_t *sha256; +#include "ed25519/sha512.h" splay_tree_t *node_tree; static splay_tree_t *node_id_tree; -static hash_t *node_udp_cache; -static hash_t *node_id_cache; +static splay_tree_t *node_udp_tree; node_t *myself; @@ -47,22 +46,23 @@ static int node_id_compare(const node_t *a, const node_t *b) { return memcmp(&a->id, &b->id, sizeof(node_id_t)); } -void init_nodes(void) { - sha256 = digest_open_by_name("sha256", sizeof(node_id_t)); +static int node_udp_compare(const node_t *a, const node_t *b) { + int result = sockaddrcmp(&a->address, &b->address); + if (result) + return result; + return (a->name && b->name) ? strcmp(a->name, b->name) : 0; +} +void init_nodes(void) { node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node); node_id_tree = splay_alloc_tree((splay_compare_t) node_id_compare, NULL); - node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t)); - node_id_cache = hash_alloc(0x100, sizeof(node_id_t)); + node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL); } void exit_nodes(void) { - hash_free(node_id_cache); - hash_free(node_udp_cache); + splay_delete_tree(node_udp_tree); splay_delete_tree(node_id_tree); splay_delete_tree(node_tree); - - digest_close(sha256); } node_t *new_node(void) { @@ -86,15 +86,17 @@ void free_node(node_t *n) { sockaddrfree(&n->address); +#ifndef DISABLE_LEGACY cipher_close(n->incipher); digest_close(n->indigest); cipher_close(n->outcipher); digest_close(n->outdigest); +#endif ecdsa_free(n->ecdsa); sptps_stop(&n->sptps); - timeout_del(&n->mtutimeout); + timeout_del(&n->udp_ping_timeout); if(n->hostname) free(n->hostname); @@ -109,15 +111,16 @@ void free_node(node_t *n) { } void node_add(node_t *n) { - digest_create(sha256, n->name, strlen(n->name), &n->id); + unsigned char buf[64]; + sha512(n->name, strlen(n->name),buf); + memcpy(&n->id, buf, sizeof n->id); splay_insert(node_tree, n); splay_insert(node_id_tree, n); } void node_del(node_t *n) { - hash_delete(node_udp_cache, &n->address); - hash_delete(node_id_cache, &n->id); + splay_delete(node_udp_tree, n); for splay_each(subnet_t, s, n->subnet_tree) subnet_del(n, s); @@ -138,19 +141,13 @@ node_t *lookup_node(char *name) { } node_t *lookup_node_id(const node_id_t *id) { - node_t *n = hash_search(node_id_cache, id); - if(!n) { - node_t tmp = {.id = *id}; - n = splay_search(node_id_tree, &tmp); - if(n) - hash_insert(node_id_cache, id, n); - } - - return n; + node_t n = {.id = *id}; + return splay_search(node_id_tree, &n); } node_t *lookup_node_udp(const sockaddr_t *sa) { - return hash_search(node_udp_cache, sa); + node_t tmp = {.address = *sa}; + return splay_search(node_udp_tree, &tmp); } void update_node_udp(node_t *n, const sockaddr_t *sa) { @@ -159,7 +156,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) { return; } - hash_delete(node_udp_cache, &n->address); + splay_delete(node_udp_tree, n); if(sa) { n->address = *sa; @@ -170,7 +167,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) { break; } } - hash_insert(node_udp_cache, sa, n); + splay_insert(node_udp_tree, n); free(n->hostname); n->hostname = sockaddr2hostname(&n->address); logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname); @@ -179,6 +176,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) { /* invalidate UDP information - note that this is a security feature as well to make sure we can't be tricked into flooding any random address with UDP packets */ n->status.udp_confirmed = false; + n->maxrecentlen = 0; n->mtuprobes = 0; n->minmtu = 0; n->maxmtu = MTU; @@ -188,13 +186,18 @@ bool dump_nodes(connection_t *c) { for splay_each(node_t, n, node_tree) { char id[2 * sizeof n->id + 1]; for (size_t c = 0; c < sizeof n->id; ++c) - sprintf(id + 2 * c, "%02hhx", n->id.x[c]); + snprintf(id + 2 * c, 3, "%02hhx", n->id.x[c]); id[sizeof id - 1] = 0; send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES, - n->name, id, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher), - digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), n->outcompression, - n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-", - n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change); + n->name, id, n->hostname ?: "unknown port unknown", +#ifdef DISABLE_LEGACY + 0, 0, 0, +#else + cipher_get_nid(n->outcipher), digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), +#endif + n->outcompression, n->options, bitfield_to_int(&n->status, sizeof n->status), + n->nexthop ? n->nexthop->name : "-", n->via ? n->via->name ?: "-" : "-", n->distance, + n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change); } return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES); diff --git a/src/node.h b/src/node.h index b6db18b..6ca6432 100644 --- a/src/node.h +++ b/src/node.h @@ -38,17 +38,19 @@ typedef struct node_status_t { unsigned int sptps:1; /* 1 if this node supports SPTPS */ unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */ unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */ - unsigned int unused:23; + unsigned int udppacket:1; /* 1 if the most recently received packet was UDP */ + unsigned int validkey_in:1; /* 1 if we have sent a valid key to him */ + unsigned int unused:21; } node_status_t; typedef struct node_t { char *name; /* name of this node */ + char *hostname; /* the hostname of its real ip */ node_id_t id; /* unique node ID (name hash) */ uint32_t options; /* options turned on for this node */ int sock; /* Socket to use for outgoing UDP packets */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */ - char *hostname; /* the hostname of its real ip */ node_status_t status; time_t last_state_change; @@ -57,11 +59,13 @@ typedef struct node_t { ecdsa_t *ecdsa; /* His public ECDSA key */ sptps_t sptps; +#ifndef DISABLE_LEGACY cipher_t *incipher; /* Cipher for UDP packets */ digest_t *indigest; /* Digest for UDP packets */ cipher_t *outcipher; /* Cipher for UDP packets */ digest_t *outdigest; /* Digest for UDP packets */ +#endif int incompression; /* Compressionlevel, 0 = no compression */ int outcompression; /* Compressionlevel, 0 = no compression */ @@ -85,16 +89,21 @@ typedef struct node_t { uint32_t farfuture; /* Packets in a row that have arrived from the far future */ unsigned char* late; /* Bitfield marking late packets */ + struct timeval udp_reply_sent; /* Last time a (gratuitous) UDP probe reply was sent */ + struct timeval udp_ping_sent; /* Last time a UDP probe was sent */ + timeout_t udp_ping_timeout; /* Ping timeout event */ + + struct timeval mtu_ping_sent; /* Last time a MTU probe was sent */ + + struct timeval mtu_info_sent; /* Last time a MTU_INFO message was sent */ + struct timeval udp_info_sent; /* Last time a UDP_INFO message was sent */ + + length_t maxrecentlen; /* Maximum size of recently received packets */ + length_t mtu; /* Maximum size of packets to send to this node */ length_t minmtu; /* Probed minimum MTU */ length_t maxmtu; /* Probed maximum MTU */ int mtuprobes; /* Number of probes */ - timeout_t mtutimeout; /* Probe event */ - struct timeval probe_time; /* Time the last probe was sent or received */ - int probe_counter; /* Number of probes received since last burst was sent */ - float rtt; /* Last measured round trip time */ - float bandwidth; /* Last measured bandwidth */ - float packetloss; /* Last measured packet loss rate */ uint64_t in_packets; uint64_t in_bytes; diff --git a/src/nolegacy/crypto.c b/src/nolegacy/crypto.c new file mode 100644 index 0000000..f1113b4 --- /dev/null +++ b/src/nolegacy/crypto.c @@ -0,0 +1,87 @@ +/* + crypto.c -- Cryptographic miscellaneous functions and initialisation + Copyright (C) 2007-2014 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "../system.h" + +#include "../crypto.h" + +#ifndef HAVE_MINGW + +static int random_fd = -1; + +static void random_init(void) { + random_fd = open("/dev/urandom", O_RDONLY); + if(random_fd < 0) + random_fd = open("/dev/random", O_RDONLY); + if(random_fd < 0) { + fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno)); + abort(); + } +} + +static void random_exit(void) { + close(random_fd); +} + +void randomize(void *out, size_t outlen) { + while(outlen) { + size_t len = read(random_fd, out, outlen); + if(len <= 0) { + if(errno == EAGAIN || errno == EINTR) + continue; + fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno)); + abort(); + } + out += len; + outlen -= len; + } +} + +#else + +#include +HCRYPTPROV prov; + +void random_init(void) { + if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + fprintf(stderr, "CryptAcquireContext() failed!\n"); + abort(); + } +} + +void random_exit(void) { + CryptReleaseContext(prov, 0); +} + +void randomize(void *out, size_t outlen) { + if(!CryptGenRandom(prov, outlen, out)) { + fprintf(stderr, "CryptGenRandom() failed\n"); + abort(); + } +} + +#endif + +void crypto_init(void) { + random_init(); +} + +void crypto_exit(void) { + random_exit(); +} diff --git a/src/nolegacy/prf.c b/src/nolegacy/prf.c new file mode 100644 index 0000000..55c9923 --- /dev/null +++ b/src/nolegacy/prf.c @@ -0,0 +1,106 @@ +/* + prf.c -- Pseudo-Random Function for key material generation + Copyright (C) 2011-2013 Guus Sliepen + + 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 "../prf.h" +#include "../ed25519/sha512.h" + +static void memxor(char *buf, char c, size_t len) { + for(size_t i = 0; i < len; i++) + buf[i] ^= c; +} + +static const size_t mdlen = 64; +static const size_t blklen = 128; + +static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) { + char tmp[blklen + mdlen]; + sha512_context md; + + if(keylen <= blklen) { + memcpy(tmp, key, keylen); + memset(tmp + keylen, 0, blklen - keylen); + } else { + if(sha512(key, keylen, tmp) != 0) + return false; + memset(tmp + mdlen, 0, blklen - mdlen); + } + + if(sha512_init(&md) != 0) + return false; + + // ipad + memxor(tmp, 0x36, blklen); + if(sha512_update(&md, tmp, blklen) != 0) + return false; + + // message + if(sha512_update(&md, msg, msglen) != 0) + return false; + + if(sha512_final(&md, tmp + blklen) != 0) + return false; + + // opad + memxor(tmp, 0x36 ^ 0x5c, blklen); + if(sha512(tmp, sizeof tmp, out) != 0) + return false; + + return true; +} + + +/* Generate key material from a master secret and a seed, based on RFC 4346 section 5. + We use SHA512 instead of MD5 and SHA1. + */ + +bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) { + /* Data is what the "inner" HMAC function processes. + It consists of the previous HMAC result plus the seed. + */ + + char data[mdlen + seedlen]; + memset(data, 0, mdlen); + memcpy(data + mdlen, seed, seedlen); + + char hash[mdlen]; + + while(outlen > 0) { + /* Inner HMAC */ + if(!hmac_sha512(secret, secretlen, data, sizeof data, data)) + return false; + + /* Outer HMAC */ + if(outlen >= mdlen) { + if(!hmac_sha512(secret, secretlen, data, sizeof data, out)) + return false; + out += mdlen; + outlen -= mdlen; + } else { + if(!hmac_sha512(secret, secretlen, data, sizeof data, hash)) + return false; + memcpy(out, hash, outlen); + out += outlen; + outlen = 0; + } + } + + return true; +} diff --git a/src/openssl/cipher.c b/src/openssl/cipher.c index 9b39a28..04aee27 100644 --- a/src/openssl/cipher.c +++ b/src/openssl/cipher.c @@ -79,6 +79,13 @@ size_t cipher_keylength(const cipher_t *cipher) { return cipher->cipher->key_len + cipher->cipher->iv_len; } +size_t cipher_blocksize(const cipher_t *cipher) { + if(!cipher || !cipher->cipher) + return 1; + + return cipher->cipher->block_size; +} + bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) { bool result; diff --git a/src/process.c b/src/process.c index 2243bf9..5bb7eb3 100644 --- a/src/process.c +++ b/src/process.c @@ -42,6 +42,7 @@ bool sigalrm = false; extern char **g_argv; extern bool use_logfile; +extern bool use_syslog; /* Some functions the less gifted operating systems might lack... */ @@ -61,12 +62,9 @@ static bool install_service(void) { return false; } - if(!strchr(program_name, '\\')) { - GetCurrentDirectory(sizeof command - 1, command + 1); - strncat(command, "\\", sizeof command - strlen(command)); - } - - strncat(command, program_name, sizeof command - strlen(command)); + HMODULE module = GetModuleHandle(NULL); + GetModuleFileName(module, command + 1, sizeof command - 1); + command[sizeof command - 1] = 0; strncat(command, "\"", sizeof command - strlen(command)); @@ -189,6 +187,8 @@ bool init_service(void) { Detach from current terminal */ bool detach(void) { + logmode_t logmode; + #ifndef HAVE_MINGW signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); @@ -200,7 +200,7 @@ bool detach(void) { if(do_detach) { #ifndef HAVE_MINGW - if(daemon(0, 0)) { + if(daemon(1, 0)) { logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno)); return false; } @@ -210,12 +210,17 @@ bool detach(void) { #endif } - openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR)); + if(use_logfile) + logmode = LOGMODE_FILE; + else if(use_syslog || do_detach) + logmode = LOGMODE_SYSLOG; + else + logmode = LOGMODE_STDERR; + + openlogger(identname, logmode); logger(DEBUG_ALWAYS, LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d", - VERSION, BUILD_DATE, BUILD_TIME, debug_level); + BUILD_VERSION, BUILD_DATE, BUILD_TIME, debug_level); return true; } - - diff --git a/src/protocol.c b/src/protocol.c index 1ec169a..f533a93 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -41,6 +41,9 @@ static bool (*request_handlers[])(connection_t *, const char *) = { add_subnet_h, del_subnet_h, add_edge_h, del_edge_h, key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h, + NULL, NULL, /* Not "real" requests (yet) */ + sptps_tcppacket_h, + udp_info_h, mtu_info_h, }; /* Request names */ @@ -51,6 +54,7 @@ static char (*request_name[]) = { "PING", "PONG", "ADD_SUBNET", "DEL_SUBNET", "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL", + "REQ_PUBKEY", "ANS_PUBKEY", "SPTPS_PACKET", "UDP_INFO", "MTU_INFO", }; static splay_tree_t *past_request_tree; @@ -132,7 +136,8 @@ bool receive_request(connection_t *c, const char *request) { if(!request_handlers[reqno](c, request)) { /* Something went wrong. Probably scriptkiddies. Terminate. */ - logger(DEBUG_ALWAYS, LOG_ERR, "Error while processing %s from %s (%s)", request_name[reqno], c->name, c->hostname); + if(reqno != TERMREQ) + logger(DEBUG_ALWAYS, LOG_ERR, "Error while processing %s from %s (%s)", request_name[reqno], c->name, c->hostname); return false; } } else { diff --git a/src/protocol.h b/src/protocol.h index 080d50c..dee6eb8 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -26,7 +26,7 @@ /* Protocol version. Different major versions are incompatible. */ #define PROT_MAJOR 17 -#define PROT_MINOR 4 /* Should not exceed 255! */ +#define PROT_MINOR 7 /* Should not exceed 255! */ /* Silly Windows */ @@ -48,7 +48,8 @@ typedef enum request_t { /* Tinc 1.1 requests */ CONTROL, REQ_PUBKEY, ANS_PUBKEY, - REQ_SPTPS, + SPTPS_PACKET, + UDP_INFO, MTU_INFO, LAST /* Guardian for the highest request number */ } request_t; @@ -107,6 +108,9 @@ extern void send_key_changed(void); extern bool send_req_key(struct node_t *); extern bool send_ans_key(struct node_t *); extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *); +extern bool send_sptps_tcppacket(struct connection_t *, const char*, int); +extern bool send_udp_info(struct node_t *, struct node_t *); +extern bool send_mtu_info(struct node_t *, struct node_t *, int); /* Request handlers */ @@ -128,6 +132,9 @@ extern bool key_changed_h(struct connection_t *, const char *); extern bool req_key_h(struct connection_t *, const char *); extern bool ans_key_h(struct connection_t *, const char *); extern bool tcppacket_h(struct connection_t *, const char *); +extern bool sptps_tcppacket_h(struct connection_t *, const char *); extern bool control_h(struct connection_t *, const char *); +extern bool udp_info_h(struct connection_t *, const char *); +extern bool mtu_info_h(struct connection_t *, const char *); #endif /* __TINC_PROTOCOL_H__ */ diff --git a/src/protocol_auth.c b/src/protocol_auth.c index cd39f28..0a7ad1c 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -45,6 +45,8 @@ #include "utils.h" #include "xalloc.h" +#include "ed25519/sha512.h" + ecdsa_t *invitation_key = NULL; static bool send_proxyrequest(connection_t *c) { @@ -115,7 +117,7 @@ static bool send_proxyrequest(connection_t *c) { i += 2; c->tcplen += 22; } else { - logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family); + logger(DEBUG_ALWAYS, LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family); return false; } if(i > len) @@ -211,17 +213,13 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat return false; // Recover the filename from the cookie and the key - digest_t *digest = digest_open_by_name("sha256", 18); - if(!digest) - abort(); char *fingerprint = ecdsa_get_base64_public_key(invitation_key); char hashbuf[18 + strlen(fingerprint)]; - char cookie[25]; + char cookie[64]; memcpy(hashbuf, data, 18); memcpy(hashbuf + 18, fingerprint, sizeof hashbuf - 18); - digest_create(digest, hashbuf, sizeof hashbuf, cookie); + sha512(hashbuf, sizeof hashbuf, cookie); b64encode_urlsafe(cookie, cookie, 18); - digest_close(digest); free(fingerprint); char filename[PATH_MAX], usedname[PATH_MAX]; @@ -388,7 +386,7 @@ bool id_h(connection_t *c, const char *request) { /* Forbid version rollback for nodes whose Ed25519 key we know */ - if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) { + if(ecdsa_active(c->ecdsa) && c->protocol_minor < 1) { logger(DEBUG_ALWAYS, LOG_ERR, "Peer %s (%s) tries to roll back protocol version to %d.%d", c->name, c->hostname, c->protocol_major, c->protocol_minor); return false; @@ -412,6 +410,9 @@ bool id_h(connection_t *c, const char *request) { } bool send_metakey(connection_t *c) { +#ifdef DISABLE_LEGACY + return false; +#else if(!myself->connection->rsa) { logger(DEBUG_CONNECTIONS, LOG_ERR, "Peer %s (%s) uses legacy protocol which we don't support", c->name, c->hostname); return false; @@ -480,9 +481,13 @@ bool send_metakey(connection_t *c) { c->status.encryptout = true; return result; +#endif } bool metakey_h(connection_t *c, const char *request) { +#ifdef DISABLE_LEGACY + return false; +#else if(!myself->connection->rsa) return false; @@ -545,9 +550,13 @@ bool metakey_h(connection_t *c, const char *request) { c->allow_request = CHALLENGE; return send_challenge(c); +#endif } bool send_challenge(connection_t *c) { +#ifdef DISABLE_LEGACY + return false; +#else const size_t len = rsa_size(c->rsa); char buffer[len * 2 + 1]; @@ -565,9 +574,13 @@ bool send_challenge(connection_t *c) { /* Send the challenge */ return send_request(c, "%d %s", CHALLENGE, buffer); +#endif } bool challenge_h(connection_t *c, const char *request) { +#ifdef DISABLE_LEGACY + return false; +#else if(!myself->connection->rsa) return false; @@ -606,9 +619,13 @@ bool challenge_h(connection_t *c, const char *request) { c->allow_request = CHAL_REPLY; return send_request(c, "%d %s", CHAL_REPLY, buffer); +#endif } bool chal_reply_h(connection_t *c, const char *request) { +#ifdef DISABLE_LEGACY + return false; +#else char hishash[MAX_STRING_SIZE]; if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) { @@ -645,9 +662,13 @@ bool chal_reply_h(connection_t *c, const char *request) { c->allow_request = ACK; return send_ack(c); +#endif } static bool send_upgrade(connection_t *c) { +#ifdef DISABLE_LEGACY + return false; +#else /* Special case when protocol_minor is 1: the other end is Ed25519 capable, * but doesn't know our key yet. So send it now. */ @@ -659,6 +680,7 @@ static bool send_upgrade(connection_t *c) { bool result = send_request(c, "%d %s", ACK, pubkey); free(pubkey); return result; +#endif } bool send_ack(connection_t *c) { @@ -758,6 +780,8 @@ static bool upgrade_h(connection_t *c, const char *request) { logger(DEBUG_ALWAYS, LOG_INFO, "Got Ed25519 public key from %s (%s), upgrading!", c->name, c->hostname); append_config_file(c->name, "Ed25519PublicKey", pubkey); c->allow_request = TERMREQ; + if(c->outgoing) + c->outgoing->timeout = 0; return send_termreq(c); } diff --git a/src/protocol_edge.c b/src/protocol_edge.c index 4760162..dc0cf05 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -37,19 +37,26 @@ bool send_add_edge(connection_t *c, const edge_t *e) { bool x; char *address, *port; - char *local_address, *local_port; sockaddr2str(&e->address, &address, &port); - sockaddr2str(&e->local_address, &local_address, &local_port); - x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, rand(), - e->from->name, e->to->name, address, port, - e->options, e->weight, local_address, local_port); + if(e->local_address.sa.sa_family) { + char *local_address, *local_port; + sockaddr2str(&e->local_address, &local_address, &local_port); + + x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, rand(), + e->from->name, e->to->name, address, port, + e->options, e->weight, local_address, local_port); + free(local_address); + free(local_port); + } else { + x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(), + e->from->name, e->to->name, address, port, + e->options, e->weight); + } free(address); free(port); - free(local_address); - free(local_port); return x; } @@ -61,9 +68,9 @@ bool add_edge_h(connection_t *c, const char *request) { char to_name[MAX_STRING_SIZE]; char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; - char address_local[MAX_STRING_SIZE] = "unknown"; - char port_local[MAX_STRING_SIZE] = "unknown"; - sockaddr_t address, local_address; + char address_local[MAX_STRING_SIZE]; + char port_local[MAX_STRING_SIZE]; + sockaddr_t address, local_address = {{0}}; uint32_t options; int weight; @@ -117,27 +124,71 @@ bool add_edge_h(connection_t *c, const char *request) { /* Convert addresses */ address = str2sockaddr(to_address, to_port); - local_address = str2sockaddr(address_local, port_local); + if(parameter_count >= 8) + local_address = str2sockaddr(address_local, port_local); /* Check if edge already exists */ e = lookup_edge(from, to); if(e) { - if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address) || sockaddrcmp(&e->local_address, &local_address)) { + if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { if(from == myself) { logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", "ADD_EDGE", c->name, c->hostname); send_add_edge(c, e); + sockaddrfree(&local_address); return true; } else { logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) which does not match existing entry", "ADD_EDGE", c->name, c->hostname); - edge_del(e); - graph(); + e->options = options; + if(sockaddrcmp(&e->address, &address)) { + sockaddrfree(&e->address); + e->address = address; + } + if(e->weight != weight) { + splay_node_t *node = splay_unlink(edge_weight_tree, e); + e->weight = weight; + splay_insert_node(edge_weight_tree, node); + } + + goto done; } - } else + } else if(sockaddrcmp(&e->local_address, &local_address)) { + if(from == myself) { + if(e->local_address.sa.sa_family && local_address.sa.sa_family) { + // Someone has the wrong local address for ourself. Correct then. + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", + "ADD_EDGE", c->name, c->hostname); + send_add_edge(c, e); + sockaddrfree(&local_address); + return true; + } + // Otherwise, just ignore it. + sockaddrfree(&local_address); + return true; + } else if(local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN) { + // We learned a new local address for this edge. + // local_address.sa.sa_family will be 0 if we got it from older tinc versions + // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions + // but for edge which does not have local_address + sockaddrfree(&e->local_address); + e->local_address = local_address; + + // Tell others about it. + if(!tunnelserver) + forward_request(c, request); + + return true; + } else { + sockaddrfree(&local_address); + return true; + } + } else { + sockaddrfree(&local_address); return true; + } } else if(from == myself) { logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist", "ADD_EDGE", c->name, c->hostname); @@ -147,6 +198,7 @@ bool add_edge_h(connection_t *c, const char *request) { e->to = to; send_del_edge(c, e); free_edge(e); + sockaddrfree(&local_address); return true; } @@ -159,6 +211,7 @@ bool add_edge_h(connection_t *c, const char *request) { e->weight = weight; edge_add(e); +done: /* Tell the rest about the new edge */ if(!tunnelserver) diff --git a/src/protocol_key.c b/src/protocol_key.c index 8b19d90..d24d4ac 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -36,6 +36,7 @@ static bool mykeyused = false; void send_key_changed(void) { +#ifndef DISABLE_LEGACY send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name); /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */ @@ -43,6 +44,7 @@ void send_key_changed(void) { for list_each(connection_t, c, connection_list) if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps) send_ans_key(c->node); +#endif /* Force key exchange for connections using SPTPS */ @@ -87,9 +89,13 @@ bool key_changed_h(connection_t *c, const char *request) { return true; } +static bool send_sptps_data_myself(void *handle, uint8_t type, const void *data, size_t len) { + return send_sptps_data(handle, myself, type, data, len); +} + static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) { node_t *to = handle; - to->sptps.send_data = send_sptps_data; + to->sptps.send_data = send_sptps_data_myself; char buf[len * 4 / 3 + 5]; b64encode(data, buf, len); return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf); @@ -103,9 +109,6 @@ bool send_req_key(node_t *to) { return true; } - if(to->sptps.label) - logger(DEBUG_ALWAYS, LOG_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name); - char label[25 + strlen(myself->name) + strlen(to->name)]; snprintf(label, sizeof label, "tinc UDP key expansion %s %s", myself->name, to->name); sptps_stop(&to->sptps); @@ -121,7 +124,52 @@ bool send_req_key(node_t *to) { /* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */ -static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) { +static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, node_t *to, int reqno) { + /* If this is a SPTPS packet, see if sending UDP info helps. + Note that we only do this if we're the destination or the static relay; + otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */ + if((reqno == REQ_KEY || reqno == SPTPS_PACKET) && to->via == myself) + send_udp_info(myself, from); + + if(reqno == SPTPS_PACKET) { + /* This is a SPTPS data packet. */ + + char buf[MAX_STRING_SIZE]; + int len; + if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s) to %s (%s): %s", "SPTPS_PACKET", from->name, from->hostname, to->name, to->hostname, "invalid SPTPS data"); + return true; + } + + if(to != myself) { + /* We don't just forward the request, because we want to use UDP if it's available. */ + send_sptps_data(to, from, 0, buf, len); + try_tx(to, true); + } else { + /* The packet is for us */ + if(!sptps_receive_data(&from->sptps, buf, len)) { + /* Uh-oh. It might be that the tunnel is stuck in some corrupted state, + so let's restart SPTPS in case that helps. But don't do that too often + to prevent storms. */ + if(from->last_req_key < now.tv_sec - 10) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname); + send_req_key(from); + } + return true; + } + send_mtu_info(myself, from, MTU); + } + + return true; + } + + /* Requests that are not SPTPS data packets are forwarded as-is. */ + + if (to != myself) + return send_request(to->nexthop->connection, "%s", request); + + /* The request is for us */ + switch(reqno) { case REQ_PUBKEY: { if(!node_read_ecdsa_public_key(from)) { @@ -176,24 +224,9 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in from->status.validkey = false; from->status.waitingforkey = true; from->last_req_key = now.tv_sec; - sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record); - sptps_receive_data(&from->sptps, buf, len); - return true; - } - - case REQ_SPTPS: { - if(!from->status.validkey) { - logger(DEBUG_PROTOCOL, LOG_ERR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname); - return true; - } - - char buf[MAX_STRING_SIZE]; - int len; - if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) { - logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data"); - return true; - } + sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data_myself, receive_sptps_record); sptps_receive_data(&from->sptps, buf, len); + send_mtu_info(myself, from, MTU); return true; } @@ -241,7 +274,7 @@ bool req_key_h(connection_t *c, const char *request) { if(to == myself) { /* Yes */ /* Is this an extended REQ_KEY message? */ if(experimental && reqno) - return req_key_ext_h(c, request, from, reqno); + return req_key_ext_h(c, request, from, to, reqno); /* No, just send our key back */ send_ans_key(from); @@ -255,7 +288,10 @@ bool req_key_h(connection_t *c, const char *request) { return true; } - /* TODO: forwarding SPTPS packets in this way is inefficient because we send them over TCP without checking for UDP connectivity */ + /* Is this an extended REQ_KEY message? */ + if(experimental && reqno) + return req_key_ext_h(c, request, from, to, reqno); + send_request(to->nexthop->connection, "%s", request); } @@ -266,6 +302,9 @@ bool send_ans_key(node_t *to) { if(to->status.sptps) abort(); +#ifdef DISABLE_LEGACY + return false; +#else size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1; char key[keylen * 2 + 1]; @@ -300,12 +339,15 @@ bool send_ans_key(node_t *to) { to->received = 0; if(replaywin) memset(to->late, 0, replaywin); + to->status.validkey_in = true; + return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY, myself->name, to->name, key, cipher_get_nid(to->incipher), digest_get_nid(to->indigest), (int)digest_length(to->indigest), to->incompression); +#endif } bool ans_key_h(connection_t *c, const char *request) { @@ -358,7 +400,7 @@ bool ans_key_h(connection_t *c, const char *request) { return true; } - if(!*address && from->address.sa.sa_family != AF_UNSPEC) { + if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) { char *address, *port; logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name); sockaddr2str(&from->address, &address, &port); @@ -371,10 +413,12 @@ bool ans_key_h(connection_t *c, const char *request) { return send_request(to->nexthop->connection, "%s", request); } +#ifndef DISABLE_LEGACY /* Don't use key material until every check has passed. */ cipher_close(from->outcipher); digest_close(from->outdigest); - from->status.validkey = false; +#endif + if (!from->status.sptps) from->status.validkey = false; if(compression < 0 || compression > 11) { logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname); @@ -388,9 +432,18 @@ bool ans_key_h(connection_t *c, const char *request) { if(from->status.sptps) { char buf[strlen(key)]; int len = b64decode(key, buf, strlen(key)); - - if(!len || !sptps_receive_data(&from->sptps, buf, len)) - logger(DEBUG_ALWAYS, LOG_ERR, "Error processing SPTPS data from %s (%s)", from->name, from->hostname); + if(!len || !sptps_receive_data(&from->sptps, buf, len)) { + /* Uh-oh. It might be that the tunnel is stuck in some corrupted state, + so let's restart SPTPS in case that helps. But don't do that too often + to prevent storms. + Note that simply relying on handshake timeout is not enough, because + that doesn't apply to key regeneration. */ + if(from->last_req_key < now.tv_sec - 10) { + logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode handshake TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname); + send_req_key(from); + } + return true; + } if(from->status.validkey) { if(*address && *port) { @@ -398,16 +451,17 @@ bool ans_key_h(connection_t *c, const char *request) { sockaddr_t sa = str2sockaddr(address, port); update_node_udp(from, &sa); } - - /* Don't send probes if we can't send UDP packets directly to that node. - TODO: the indirect (via) condition can change at any time as edges are added and removed, so this should probably be moved to graph.c. */ - if((from->via == myself || from->via == from) && from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY)) - send_mtu_probe(from); } + send_mtu_info(myself, from, MTU); + return true; } +#ifdef DISABLE_LEGACY + logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses legacy protocol!", from->name, from->hostname); + return false; +#else /* Check and lookup cipher and digest algorithms */ if(cipher) { @@ -458,8 +512,6 @@ bool ans_key_h(connection_t *c, const char *request) { update_node_udp(from, &sa); } - if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY)) - send_mtu_probe(from); - return true; +#endif } diff --git a/src/protocol_misc.c b/src/protocol_misc.c index 713dacf..95bd322 100644 --- a/src/protocol_misc.c +++ b/src/protocol_misc.c @@ -28,8 +28,15 @@ #include "netutl.h" #include "protocol.h" #include "utils.h" +#include "xalloc.h" + +#ifndef MIN +#define MIN(x, y) (((x)<(y))?(x):(y)) +#endif int maxoutbufsize = 0; +int mtu_info_interval = 5; +int udp_info_interval = 5; /* Status and error notification routines */ @@ -149,3 +156,229 @@ bool tcppacket_h(connection_t *c, const char *request) { return true; } + +bool send_sptps_tcppacket(connection_t *c, const char* packet, int len) { + /* If there already is a lot of data in the outbuf buffer, discard this packet. + We use a very simple Random Early Drop algorithm. */ + + if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX) + return true; + + if(!send_request(c, "%d %d", SPTPS_PACKET, len)) + return false; + + send_meta_raw(c, packet, len); + return true; +} + +bool sptps_tcppacket_h(connection_t *c, const char* request) { + short int len; + + if(sscanf(request, "%*d %hd", &len) != 1) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "SPTPS_PACKET", c->name, + c->hostname); + return false; + } + + /* Set sptpslen to len, this will tell receive_meta() that a SPTPS packet is coming. */ + + c->sptpslen = len; + + return true; +} + +/* Transmitting UDP information */ + +bool send_udp_info(node_t *from, node_t *to) { + /* If there's a static relay in the path, there's no point in sending the message + farther than the static relay. */ + to = (to->via == myself) ? to->nexthop : to->via; + + /* Skip cases where sending UDP info messages doesn't make sense. + This is done here in order to avoid repeating the same logic in multiple callsites. */ + + if(to == myself) + return true; + + if(!to->status.reachable) + return true; + + if(from == myself) { + if(to->connection) + return true; + + struct timeval elapsed; + timersub(&now, &to->udp_info_sent, &elapsed); + if(elapsed.tv_sec < udp_info_interval) + return true; + } + + if((myself->options | from->options | to->options) & OPTION_TCPONLY) + return true; + + if((to->nexthop->options >> 24) < 5) + return true; + + char *from_address, *from_port; + /* If we're the originator, the address we use is irrelevant + because the first intermediate node will ignore it. + We use our local address as it somewhat makes sense + and it's simpler than introducing an encoding for "null" addresses anyway. */ + sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port); + + bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port); + + free(from_address); + free(from_port); + + if(from == myself) + to->udp_info_sent = now; + + return x; +} + +bool udp_info_h(connection_t *c, const char* request) { + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + char from_address[MAX_STRING_SIZE]; + char from_port[MAX_STRING_SIZE]; + + if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname); + return false; + } + + if(!check_id(from_name) || !check_id(to_name)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name"); + return false; + } + + node_t *from = lookup_node(from_name); + if(!from) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, from_name); + return true; + } + + if(from != from->via) { + /* Not supposed to happen, as it means the message wandered past a static relay */ + logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname); + return true; + } + + /* If we have a direct edge to "from", we are in a better position + to guess its address than it is itself. */ + if(!from->connection && !from->status.udp_confirmed) { + sockaddr_t from_addr = str2sockaddr(from_address, from_port); + if(sockaddrcmp(&from_addr, &from->address)) + update_node_udp(from, &from_addr); + } + + node_t *to = lookup_node(to_name); + if(!to) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, to_name); + return true; + } + + /* Send our own data (which could be what we just received) up the chain. */ + + return send_udp_info(from, to); +} + +/* Transmitting MTU information */ + +bool send_mtu_info(node_t *from, node_t *to, int mtu) { + /* Skip cases where sending MTU info messages doesn't make sense. + This is done here in order to avoid repeating the same logic in multiple callsites. */ + + if(to == myself) + return true; + + if(!to->status.reachable) + return true; + + if(from == myself) { + if(to->connection) + return true; + + struct timeval elapsed; + timersub(&now, &to->mtu_info_sent, &elapsed); + if(elapsed.tv_sec < mtu_info_interval) + return true; + } + + if((to->nexthop->options >> 24) < 6) + return true; + + /* We will send the passed-in MTU value, unless we believe ours is better. */ + + node_t *via = (from->via == myself) ? from->nexthop : from->via; + if(from->minmtu == from->maxmtu && from->via == myself) { + /* We have a direct measurement. Override the value entirely. + Note that we only do that if we are sitting as a static relay in the path; + otherwise, we can't guarantee packets will flow through us, and increasing + MTU could therefore end up being too optimistic. */ + mtu = from->minmtu; + } else if(via->minmtu == via->maxmtu) { + /* Static relay. Ensure packets will make it through the entire relay path. */ + mtu = MIN(mtu, via->minmtu); + } else if(via->nexthop->minmtu == via->nexthop->maxmtu) { + /* Dynamic relay. Ensure packets will make it through the entire relay path. */ + mtu = MIN(mtu, via->nexthop->minmtu); + } + + if(from == myself) + to->mtu_info_sent = now; + + /* If none of the conditions above match in the steady state, it means we're using TCP, + so the MTU is irrelevant. That said, it is still important to honor the MTU that was passed in, + because other parts of the relay path might be able to use UDP, which means they care about the MTU. */ + + return send_request(to->nexthop->connection, "%d %s %s %d", MTU_INFO, from->name, to->name, mtu); +} + +bool mtu_info_h(connection_t *c, const char* request) { + char from_name[MAX_STRING_SIZE]; + char to_name[MAX_STRING_SIZE]; + int mtu; + + if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &mtu) != 3) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "MTU_INFO", c->name, c->hostname); + return false; + } + + if(mtu < 512) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid MTU"); + return false; + } + + mtu = MIN(mtu, MTU); + + if(!check_id(from_name) || !check_id(to_name)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid name"); + return false; + } + + node_t *from = lookup_node(from_name); + if(!from) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, from_name); + return true; + } + + /* If we don't know the current MTU for that node, use the one we received. + Even if we're about to make our own measurements, the value we got from downstream nodes should be pretty close + so it's a good idea to use it in the mean time. */ + if(from->mtu != mtu && from->minmtu != from->maxmtu) { + logger(DEBUG_TRAFFIC, LOG_INFO, "Using provisional MTU %d for node %s (%s)", mtu, from->name, from->hostname); + from->mtu = mtu; + } + + node_t *to = lookup_node(to_name); + if(!to) { + logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, to_name); + return true; + } + + /* Continue passing the MTU value (or a better one if we have it) up the chain. */ + + return send_mtu_info(from, to, mtu); +} diff --git a/src/route.c b/src/route.c index 2785146..0c9f2aa 100644 --- a/src/route.c +++ b/src/route.c @@ -105,6 +105,260 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) { return true; } +static void swap_mac_addresses(vpn_packet_t *packet) { + mac_t tmp; + memcpy(&tmp, &DATA(packet)[0], sizeof tmp); + memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp); + memcpy(&DATA(packet)[6], &tmp, sizeof tmp); +} + +/* RFC 792 */ + +static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { + struct ip ip = {0}; + struct icmp icmp = {0}; + + struct in_addr ip_src; + struct in_addr ip_dst; + uint32_t oldlen; + + if(ratelimit(3)) + return; + + /* Swap Ethernet source and destination addresses */ + + swap_mac_addresses(packet); + + /* Copy headers from packet into properly aligned structs on the stack */ + + memcpy(&ip, DATA(packet) + ether_size, ip_size); + + /* Remember original source and destination */ + + ip_src = ip.ip_src; + ip_dst = ip.ip_dst; + + /* Try to reply with an IP address assigned to the local machine */ + + if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) { + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd != -1) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = ip.ip_src; + if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + socklen_t addrlen = sizeof(addr); + if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + ip_dst = addr.sin_addr; + } + } + close(sockfd); + } + } + + oldlen = packet->len - ether_size; + + if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) + icmp.icmp_nextmtu = htons(packet->len - ether_size); + + if(oldlen >= IP_MSS - ip_size - icmp_size) + oldlen = IP_MSS - ip_size - icmp_size; + + /* Copy first part of original contents to ICMP message */ + + memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen); + + /* Fill in IPv4 header */ + + ip.ip_v = 4; + ip.ip_hl = ip_size / 4; + ip.ip_tos = 0; + ip.ip_len = htons(ip_size + icmp_size + oldlen); + ip.ip_id = 0; + ip.ip_off = 0; + ip.ip_ttl = 255; + ip.ip_p = IPPROTO_ICMP; + ip.ip_sum = 0; + ip.ip_src = ip_dst; + ip.ip_dst = ip_src; + + ip.ip_sum = inet_checksum(&ip, ip_size, ~0); + + /* Fill in ICMP header */ + + icmp.icmp_type = type; + icmp.icmp_code = code; + icmp.icmp_cksum = 0; + + icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0); + icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum); + + /* Copy structs on stack back to packet */ + + memcpy(DATA(packet) + ether_size, &ip, ip_size); + memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size); + + packet->len = ether_size + ip_size + icmp_size + oldlen; + + send_packet(source, packet); +} + +/* RFC 2463 */ + +static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { + struct ip6_hdr ip6; + struct icmp6_hdr icmp6 = {0}; + uint16_t checksum; + + struct { + struct in6_addr ip6_src; /* source address */ + struct in6_addr ip6_dst; /* destination address */ + uint32_t length; + uint32_t next; + } pseudo; + + if(ratelimit(3)) + return; + + /* Swap Ethernet source and destination addresses */ + + swap_mac_addresses(packet); + + /* Copy headers from packet to structs on the stack */ + + memcpy(&ip6, DATA(packet) + ether_size, ip6_size); + + /* Remember original source and destination */ + + pseudo.ip6_src = ip6.ip6_dst; + pseudo.ip6_dst = ip6.ip6_src; + + /* Try to reply with an IP address assigned to the local machine */ + + if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) { + int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd != -1) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = ip6.ip6_src; + if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) { + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + socklen_t addrlen = sizeof(addr); + if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) { + pseudo.ip6_src = addr.sin6_addr; + } + } + close(sockfd); + } + } + + pseudo.length = packet->len - ether_size; + + if(type == ICMP6_PACKET_TOO_BIG) + icmp6.icmp6_mtu = htonl(pseudo.length); + + if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) + pseudo.length = IP_MSS - ip6_size - icmp6_size; + + /* Copy first part of original contents to ICMP message */ + + memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length); + + /* Fill in IPv6 header */ + + ip6.ip6_flow = htonl(0x60000000UL); + ip6.ip6_plen = htons(icmp6_size + pseudo.length); + ip6.ip6_nxt = IPPROTO_ICMPV6; + ip6.ip6_hlim = 255; + ip6.ip6_src = pseudo.ip6_src; + ip6.ip6_dst = pseudo.ip6_dst; + + /* Fill in ICMP header */ + + icmp6.icmp6_type = type; + icmp6.icmp6_code = code; + icmp6.icmp6_cksum = 0; + + /* Create pseudo header */ + + pseudo.length = htonl(icmp6_size + pseudo.length); + pseudo.next = htonl(IPPROTO_ICMPV6); + + /* Generate checksum */ + + checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); + checksum = inet_checksum(&icmp6, icmp6_size, checksum); + checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); + + icmp6.icmp6_cksum = checksum; + + /* Copy structs on stack back to packet */ + + memcpy(DATA(packet) + ether_size, &ip6, ip6_size); + memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size); + + packet->len = ether_size + ip6_size + ntohl(pseudo.length); + + send_packet(source, packet); +} + +static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { + uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13]; + length_t ethlen = ether_size; + + if(type == ETH_P_8021Q) { + type = DATA(packet)[16] << 8 | DATA(packet)[17]; + ethlen += 4; + } + + switch (type) { + case ETH_P_IP: + if(!checklength(source, packet, ethlen + ip_size)) + return false; + + if(DATA(packet)[ethlen + 8] <= 1) { + if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED) + route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); + return false; + } + + uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9]; + DATA(packet)[ethlen + 8]--; + uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9]; + + uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11]; + checksum += old + (~new & 0xFFFF); + while(checksum >> 16) + checksum = (checksum & 0xFFFF) + (checksum >> 16); + DATA(packet)[ethlen + 10] = checksum >> 8; + DATA(packet)[ethlen + 11] = checksum & 0xff; + + return true; + + case ETH_P_IPV6: + if(!checklength(source, packet, ethlen + ip6_size)) + return false; + + if(DATA(packet)[ethlen + 7] <= 1) { + if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED) + route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); + return false; + } + + DATA(packet)[ethlen + 7]--; + + return true; + + default: + return true; + } +} + static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) { if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) return; @@ -164,7 +418,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac /* Found it */ uint16_t oldmss = DATA(packet)[start + 22 + i] << 8 | DATA(packet)[start + 23 + i]; uint16_t newmss = mtu - start - 20; - uint16_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17]; + uint32_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17]; if(oldmss <= newmss) break; @@ -175,22 +429,17 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac DATA(packet)[start + 22 + i] = newmss >> 8; DATA(packet)[start + 23 + i] = newmss & 0xff; csum ^= 0xffff; - csum -= oldmss; + csum += oldmss ^ 0xffff; csum += newmss; + csum = (csum & 0xffff) + (csum >> 16); + csum += csum >> 16; csum ^= 0xffff; DATA(packet)[start + 16] = csum >> 8; - DATA(packet)[start + 17] = csum & 0xff; + DATA(packet)[start + 17] = csum; break; } } -static void swap_mac_addresses(vpn_packet_t *packet) { - mac_t tmp; - memcpy(&tmp, &DATA(packet)[0], sizeof tmp); - memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp); - memcpy(&DATA(packet)[6], &tmp, sizeof tmp); -} - static void age_subnets(void *data) { bool left = false; @@ -248,77 +497,12 @@ static void learn_mac(mac_t *address) { } } -/* RFC 792 */ +static void route_broadcast(node_t *source, vpn_packet_t *packet) { + if(decrement_ttl && source != myself) + if(!do_decrement_ttl(source, packet)) + return; -static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { - struct ip ip = {0}; - struct icmp icmp = {0}; - - struct in_addr ip_src; - struct in_addr ip_dst; - uint32_t oldlen; - - if(ratelimit(3)) - return; - - /* Swap Ethernet source and destination addresses */ - - swap_mac_addresses(packet); - - /* Copy headers from packet into properly aligned structs on the stack */ - - memcpy(&ip, DATA(packet) + ether_size, ip_size); - - /* Remember original source and destination */ - - ip_src = ip.ip_src; - ip_dst = ip.ip_dst; - - oldlen = packet->len - ether_size; - - if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - icmp.icmp_nextmtu = htons(packet->len - ether_size); - - if(oldlen >= IP_MSS - ip_size - icmp_size) - oldlen = IP_MSS - ip_size - icmp_size; - - /* Copy first part of original contents to ICMP message */ - - memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen); - - /* Fill in IPv4 header */ - - ip.ip_v = 4; - ip.ip_hl = ip_size / 4; - ip.ip_tos = 0; - ip.ip_len = htons(ip_size + icmp_size + oldlen); - ip.ip_id = 0; - ip.ip_off = 0; - ip.ip_ttl = 255; - ip.ip_p = IPPROTO_ICMP; - ip.ip_sum = 0; - ip.ip_src = ip_dst; - ip.ip_dst = ip_src; - - ip.ip_sum = inet_checksum(&ip, ip_size, ~0); - - /* Fill in ICMP header */ - - icmp.icmp_type = type; - icmp.icmp_code = code; - icmp.icmp_cksum = 0; - - icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0); - icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum); - - /* Copy structs on stack back to packet */ - - memcpy(DATA(packet) + ether_size, &ip, ip_size); - memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size); - - packet->len = ether_size + ip_size + icmp_size + oldlen; - - send_packet(source, packet); + broadcast_packet(source, packet); } /* RFC 791 */ @@ -396,7 +580,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { } if (!subnet->owner) { - broadcast_packet(source, packet); + route_broadcast(source, packet); return; } @@ -411,6 +595,10 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); + if(decrement_ttl && source != myself && subnet->owner != myself) + if(!do_decrement_ttl(source, packet)) + return; + if(priorityinheritance) packet->priority = DATA(packet)[15]; @@ -441,86 +629,6 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { send_packet(subnet->owner, packet); } -/* RFC 2463 */ - -static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { - struct ip6_hdr ip6; - struct icmp6_hdr icmp6 = {0}; - uint16_t checksum; - - struct { - struct in6_addr ip6_src; /* source address */ - struct in6_addr ip6_dst; /* destination address */ - uint32_t length; - uint32_t next; - } pseudo; - - if(ratelimit(3)) - return; - - /* Swap Ethernet source and destination addresses */ - - swap_mac_addresses(packet); - - /* Copy headers from packet to structs on the stack */ - - memcpy(&ip6, DATA(packet) + ether_size, ip6_size); - - /* Remember original source and destination */ - - pseudo.ip6_src = ip6.ip6_dst; - pseudo.ip6_dst = ip6.ip6_src; - - pseudo.length = packet->len - ether_size; - - if(type == ICMP6_PACKET_TOO_BIG) - icmp6.icmp6_mtu = htonl(pseudo.length); - - if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) - pseudo.length = IP_MSS - ip6_size - icmp6_size; - - /* Copy first part of original contents to ICMP message */ - - memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length); - - /* Fill in IPv6 header */ - - ip6.ip6_flow = htonl(0x60000000UL); - ip6.ip6_plen = htons(icmp6_size + pseudo.length); - ip6.ip6_nxt = IPPROTO_ICMPV6; - ip6.ip6_hlim = 255; - ip6.ip6_src = pseudo.ip6_src; - ip6.ip6_dst = pseudo.ip6_dst; - - /* Fill in ICMP header */ - - icmp6.icmp6_type = type; - icmp6.icmp6_code = code; - icmp6.icmp6_cksum = 0; - - /* Create pseudo header */ - - pseudo.length = htonl(icmp6_size + pseudo.length); - pseudo.next = htonl(IPPROTO_ICMPV6); - - /* Generate checksum */ - - checksum = inet_checksum(&pseudo, sizeof pseudo, ~0); - checksum = inet_checksum(&icmp6, icmp6_size, checksum); - checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum); - - icmp6.icmp6_cksum = checksum; - - /* Copy structs on stack back to packet */ - - memcpy(DATA(packet) + ether_size, &ip6, ip6_size); - memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size); - - packet->len = ether_size + ip6_size + ntohl(pseudo.length); - - send_packet(source, packet); -} - static void route_neighborsol(node_t *source, vpn_packet_t *packet); static void route_ipv6(node_t *source, vpn_packet_t *packet) { @@ -556,7 +664,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) { } if (!subnet->owner) { - broadcast_packet(source, packet); + route_broadcast(source, packet); return; } @@ -571,6 +679,10 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) { if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); + if(decrement_ttl && source != myself && subnet->owner != myself) + if(!do_decrement_ttl(source, packet)) + return; + via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; if(via == source) { @@ -687,6 +799,10 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) { if(subnet->owner == myself) return; /* silently ignore */ + if(decrement_ttl) + if(!do_decrement_ttl(source, packet)) + return; + /* Create neighbor advertation reply */ memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */ @@ -782,15 +898,17 @@ static void route_arp(node_t *source, vpn_packet_t *packet) { if(subnet->owner == myself) return; /* silently ignore */ - memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */ - DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ + if(decrement_ttl) + if(!do_decrement_ttl(source, packet)) + return; memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */ memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */ memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */ memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ - memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ + memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* set source hard/proto addr */ + arp.arp_sha[ETH_ALEN - 1] ^= 0xFF; /* for consistency with route_packet() */ arp.arp_op = htons(ARPOP_REPLY); /* Copy structs on stack back to packet */ @@ -818,7 +936,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { subnet = lookup_subnet_mac(NULL, &dest); if(!subnet || !subnet->owner) { - broadcast_packet(source, packet); + route_broadcast(source, packet); return; } @@ -830,6 +948,10 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) return; + if(decrement_ttl && source != myself && subnet->owner != myself) + if(!do_decrement_ttl(source, packet)) + return; + uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13]; if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size) @@ -888,58 +1010,6 @@ static void send_pcap(vpn_packet_t *packet) { } } -static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { - uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13]; - length_t ethlen = ether_size; - - if(type == ETH_P_8021Q) { - type = DATA(packet)[16] << 8 | DATA(packet)[17]; - ethlen += 4; - } - - switch (type) { - case ETH_P_IP: - if(!checklength(source, packet, ethlen + ip_size)) - return false; - - if(DATA(packet)[ethlen + 8] < 1) { - if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED) - route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); - return false; - } - - uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9]; - DATA(packet)[ethlen + 8]--; - uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9]; - - uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11]; - checksum += old + (~new & 0xFFFF); - while(checksum >> 16) - checksum = (checksum & 0xFFFF) + (checksum >> 16); - DATA(packet)[ethlen + 10] = checksum >> 8; - DATA(packet)[ethlen + 11] = checksum & 0xff; - - return true; - - case ETH_P_IPV6: - if(!checklength(source, packet, ethlen + ip6_size)) - return false; - - if(DATA(packet)[ethlen + 7] < 1) { - if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED) - route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); - return false; - } - - DATA(packet)[ethlen + 7]--; - - return true; - - default: - return true; - } -} - void route(node_t *source, vpn_packet_t *packet) { if(pcap) send_pcap(packet); @@ -952,10 +1022,6 @@ void route(node_t *source, vpn_packet_t *packet) { if(!checklength(source, packet, ether_size)) return; - if(decrement_ttl && source != myself) - if(!do_decrement_ttl(source, packet)) - return; - uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13]; switch (routing_mode) { @@ -984,7 +1050,7 @@ void route(node_t *source, vpn_packet_t *packet) { break; case RMODE_HUB: - broadcast_packet(source, packet); + route_broadcast(source, packet); break; } } diff --git a/src/script.c b/src/script.c index 6389cb4..d4db889 100644 --- a/src/script.c +++ b/src/script.c @@ -1,7 +1,7 @@ /* script.c -- call an external script Copyright (C) 1999-2005 Ivo Timmermans, - 2000-2013 Guus Sliepen + 2000-2015 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,21 +26,59 @@ #include "script.h" #include "xalloc.h" +#ifdef HAVE_PUTENV +static void unputenv(const char *p) { + const char *e = strchr(p, '='); + if(!e) + return; + int len = e - p; +#ifndef HAVE_UNSETENV +#ifdef HAVE_MINGW + // Windows requires putenv("FOO=") to unset %FOO% + len++; +#endif +#endif + char var[len + 1]; + strncpy(var, p, len); + var[len] = 0; +#ifdef HAVE_UNSETENV + unsetenv(var); +#else + // We must keep what we putenv() around in memory. + // To do this without memory leaks, keep things in a list and reuse if possible. + static list_t list = {}; + for list_each(char, data, &list) { + if(!strcmp(data, var)) { + putenv(data); + return; + } + } + char *data = xstrdup(var); + list_insert_tail(&list, data); + putenv(data); +#endif +} +#else +static void putenv(const char *p) {} +static void unputenv(const char *p) {} +#endif + bool execute_script(const char *name, char **envp) { -#ifdef HAVE_SYSTEM - char *scriptname; + char scriptname[PATH_MAX]; char *command; - xasprintf(&scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension); + snprintf(scriptname, sizeof scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension); /* First check if there is a script */ #ifdef HAVE_MINGW if(!*scriptextension) { const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD"; - char fullname[strlen(scriptname) + strlen(pathext)]; - char *ext = fullname + strlen(scriptname); - strcpy(fullname, scriptname); + size_t pathlen = strlen(pathext); + size_t scriptlen = strlen(scriptname); + char fullname[scriptlen + pathlen + 1]; + char *ext = fullname + scriptlen; + strncpy(fullname, scriptname, sizeof fullname); const char *p = pathext; bool found = false; @@ -51,32 +89,26 @@ bool execute_script(const char *name, char **envp) { ext[q - p] = 0; q++; } else { - strcpy(ext, p); + strncpy(ext, p, pathlen + 1); } if((found = !access(fullname, F_OK))) break; p = q; } - if(!found) { - free(scriptname); + if(!found) return true; - } } else #endif - if(access(scriptname, F_OK)) { - free(scriptname); + if(access(scriptname, F_OK)) return true; - } logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name); -#ifdef HAVE_PUTENV /* Set environment */ for(int i = 0; envp[i]; i++) putenv(envp[i]); -#endif if(scriptinterpreter) xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname); @@ -86,19 +118,11 @@ bool execute_script(const char *name, char **envp) { int status = system(command); free(command); - free(scriptname); /* Unset environment */ - for(int i = 0; envp[i]; i++) { - char *e = strchr(envp[i], '='); - if(e) { - char p[e - envp[i] + 1]; - strncpy(p, envp[i], e - envp[i]); - p[e - envp[i]] = '\0'; - putenv(p); - } - } + for(int i = 0; envp[i]; i++) + unputenv(envp[i]); if(status != -1) { #ifdef WEXITSTATUS @@ -121,6 +145,6 @@ bool execute_script(const char *name, char **envp) { logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno)); return false; } -#endif + return true; } diff --git a/src/splay_tree.h b/src/splay_tree.h index 5848870..3ddf217 100644 --- a/src/splay_tree.h +++ b/src/splay_tree.h @@ -106,6 +106,12 @@ extern splay_node_t *splay_search_closest_greater_node(splay_tree_t *, const voi extern void splay_foreach(const splay_tree_t *, splay_action_t); extern void splay_foreach_node(const splay_tree_t *, splay_action_t); +/* + Iterates over a tree. + + CAUTION: while this construct supports deleting the current item, + it does *not* support deleting *other* nodes while iterating on the tree. + */ #define splay_each(type, item, tree) (type *item = (type *)1; item; item = NULL) for(splay_node_t *node = (tree)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next) #endif diff --git a/src/sptps.c b/src/sptps.c index a598768..712d50e 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -1,6 +1,6 @@ /* sptps.c -- Simple Peer-to-Peer Security - Copyright (C) 2011-2014 Guus Sliepen , + Copyright (C) 2011-2015 Guus Sliepen , 2010 Brandon L. Black This program is free software; you can redistribute it and/or modify @@ -204,7 +204,7 @@ static bool generate_key_material(sptps_t *s, const char *shared, size_t len) { // Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce char seed[s->labellen + 64 + 13]; - strcpy(seed, "key expansion"); + memcpy(seed, "key expansion", 13); if(s->initiator) { memcpy(seed + 13, s->mykex + 1, 32); memcpy(seed + 45, s->hiskex + 1, 32); @@ -384,10 +384,11 @@ static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) { if (update_state) s->farfuture++; if(farfuture) - return error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture); + return update_state ? error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture) : false; // Unless we have seen lots of them, in which case we consider the others lost. - warning(s, "Lost %d packets\n", seqno - s->inseqno); + if(update_state) + warning(s, "Lost %d packets\n", seqno - s->inseqno); if (update_state) { // Mark all packets in the replay window as being late. memset(s->late, 255, s->replaywin); @@ -395,7 +396,7 @@ static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) { } else if (seqno < s->inseqno) { // If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it. if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8))) - return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno); + return update_state ? error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno) : false; } else if (update_state) { // We missed some packets. Mark them in the bitmap as being late. for(int i = s->inseqno; i < seqno; i++) @@ -447,6 +448,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len uint32_t seqno; memcpy(&seqno, data, 4); seqno = ntohl(seqno); + data += 4; len -= 4; if(!s->instate) { if(seqno != s->inseqno) @@ -454,39 +456,40 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len s->inseqno = seqno + 1; - uint8_t type = data[4]; + uint8_t type = *(data++); len--; if(type != SPTPS_HANDSHAKE) return error(s, EIO, "Application record received before handshake finished"); - return receive_handshake(s, data + 5, len - 5); + return receive_handshake(s, data, len); } // Decrypt char buffer[len]; - size_t outlen; - - if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen)) + if(!chacha_poly1305_decrypt(s->incipher, seqno, data, len, buffer, &outlen)) return error(s, EIO, "Failed to decrypt and verify packet"); if(!sptps_check_seqno(s, seqno, true)) return false; // Append a NULL byte for safety. - buffer[len - 20] = 0; + buffer[outlen] = 0; - uint8_t type = buffer[0]; + data = buffer; + len = outlen; + + uint8_t type = *(data++); len--; if(type < SPTPS_HANDSHAKE) { if(!s->instate) return error(s, EIO, "Application record received before handshake finished"); - if(!s->receive_record(s->handle, type, buffer + 1, len - 21)) - abort(); + if(!s->receive_record(s->handle, type, data, len)) + return false; } else if(type == SPTPS_HANDSHAKE) { - if(!receive_handshake(s, buffer + 1, len - 21)) - abort(); + if(!receive_handshake(s, data, len)) + return false; } else { return error(s, EIO, "Invalid record type %d", type); } @@ -495,90 +498,92 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len } // Receive incoming data. Check if it contains a complete record, if so, handle it. -bool sptps_receive_data(sptps_t *s, const void *data, size_t len) { +size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) { + size_t total_read = 0; + if(!s->state) return error(s, EIO, "Invalid session state zero"); if(s->datagram) - return sptps_receive_data_datagram(s, data, len); + return sptps_receive_data_datagram(s, data, len) ? len : false; - while(len) { - // First read the 2 length bytes. - if(s->buflen < 2) { - size_t toread = 2 - s->buflen; - if(toread > len) - toread = len; - - memcpy(s->inbuf + s->buflen, data, toread); - - s->buflen += toread; - len -= toread; - data += toread; - - // Exit early if we don't have the full length. - if(s->buflen < 2) - return true; - - // Get the length bytes - - memcpy(&s->reclen, s->inbuf, 2); - s->reclen = ntohs(s->reclen); - - // If we have the length bytes, ensure our buffer can hold the whole request. - s->inbuf = realloc(s->inbuf, s->reclen + 19UL); - if(!s->inbuf) - return error(s, errno, strerror(errno)); - - // Exit early if we have no more data to process. - if(!len) - return true; - } - - // Read up to the end of the record. - size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; + // First read the 2 length bytes. + if(s->buflen < 2) { + size_t toread = 2 - s->buflen; if(toread > len) toread = len; memcpy(s->inbuf + s->buflen, data, toread); + + total_read += toread; s->buflen += toread; len -= toread; data += toread; - // If we don't have a whole record, exit. - if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) - return true; + // Exit early if we don't have the full length. + if(s->buflen < 2) + return total_read; - // Update sequence number. + // Get the length bytes - uint32_t seqno = s->inseqno++; + memcpy(&s->reclen, s->inbuf, 2); + s->reclen = ntohs(s->reclen); - // Check HMAC and decrypt. - if(s->instate) { - if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) - return error(s, EINVAL, "Failed to decrypt and verify record"); - } + // If we have the length bytes, ensure our buffer can hold the whole request. + s->inbuf = realloc(s->inbuf, s->reclen + 19UL); + if(!s->inbuf) + return error(s, errno, strerror(errno)); - // Append a NULL byte for safety. - s->inbuf[s->reclen + 3UL] = 0; - - uint8_t type = s->inbuf[2]; - - if(type < SPTPS_HANDSHAKE) { - if(!s->instate) - return error(s, EIO, "Application record received before handshake finished"); - if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) - return false; - } else if(type == SPTPS_HANDSHAKE) { - if(!receive_handshake(s, s->inbuf + 3, s->reclen)) - return false; - } else { - return error(s, EIO, "Invalid record type %d", type); - } - - s->buflen = 0; + // Exit early if we have no more data to process. + if(!len) + return total_read; } - return true; + // Read up to the end of the record. + size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; + if(toread > len) + toread = len; + + memcpy(s->inbuf + s->buflen, data, toread); + total_read += toread; + s->buflen += toread; + len -= toread; + data += toread; + + // If we don't have a whole record, exit. + if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) + return total_read; + + // Update sequence number. + + uint32_t seqno = s->inseqno++; + + // Check HMAC and decrypt. + if(s->instate) { + if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) + return error(s, EINVAL, "Failed to decrypt and verify record"); + } + + // Append a NULL byte for safety. + s->inbuf[s->reclen + 3UL] = 0; + + uint8_t type = s->inbuf[2]; + + if(type < SPTPS_HANDSHAKE) { + if(!s->instate) + return error(s, EIO, "Application record received before handshake finished"); + if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) + return false; + } else if(type == SPTPS_HANDSHAKE) { + if(!receive_handshake(s, s->inbuf + 3, s->reclen)) + return false; + } else { + return error(s, EIO, "Invalid record type %d", type); + } + + s->buflen = 0; + + return total_read; } // Start a SPTPS session. diff --git a/src/sptps.h b/src/sptps.h index a2633bd..75a9565 100644 --- a/src/sptps.h +++ b/src/sptps.h @@ -88,7 +88,7 @@ extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record); extern bool sptps_stop(sptps_t *s); extern bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len); -extern bool sptps_receive_data(sptps_t *s, const void *data, size_t len); +extern size_t sptps_receive_data(sptps_t *s, const void *data, size_t len); extern bool sptps_force_kex(sptps_t *s); extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len); diff --git a/src/sptps_keypair.c b/src/sptps_keypair.c index 399404e..fde8622 100644 --- a/src/sptps_keypair.c +++ b/src/sptps_keypair.c @@ -88,7 +88,10 @@ int main(int argc, char *argv[]) { FILE *fp = fopen(argv[1], "w"); if(fp) { - ecdsa_write_pem_private_key(key, fp); + if(!ecdsa_write_pem_private_key(key, fp)) { + fprintf(stderr, "Could not write ECDSA private key\n"); + return 1; + } fclose(fp); } else { fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[1], strerror(errno)); @@ -97,7 +100,8 @@ int main(int argc, char *argv[]) { fp = fopen(argv[2], "w"); if(fp) { - ecdsa_write_pem_public_key(key, fp); + if(!ecdsa_write_pem_public_key(key, fp)) + fprintf(stderr, "Could not write ECDSA public key\n"); fclose(fp); } else { fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[2], strerror(errno)); diff --git a/src/sptps_speed.c b/src/sptps_speed.c index ab41e8d..bde3d69 100644 --- a/src/sptps_speed.c +++ b/src/sptps_speed.c @@ -33,6 +33,7 @@ bool send_request(void *c, const char *msg, ...) { return false; } struct list_t *connection_list = NULL; bool send_meta(void *c, const char *msg , int len) { return false; } char *logfilename = NULL; +bool do_detach = false; struct timeval now; static bool send_data(void *handle, uint8_t type, const void *data, size_t len) { @@ -46,11 +47,16 @@ static bool receive_record(void *handle, uint8_t type, const void *data, uint16_ } static void receive_data(sptps_t *sptps) { - char buf[4096]; + char buf[4096], *bufp = buf; int fd = *(int *)sptps->handle; size_t len = recv(fd, buf, sizeof buf, 0); - if(!sptps_receive_data(sptps, buf, len)) - abort(); + while(len) { + size_t done = sptps_receive_data(sptps, bufp, len); + if(!done) + abort(); + bufp += done; + len -= done; + } } struct timespec start; @@ -101,19 +107,26 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Ed25519 sign for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) - ecdsa_sign(key1, buf1, 256, buf2); - fprintf(stderr, "%22.2lf op/s\n", rate); + if(!ecdsa_sign(key1, buf1, 256, buf2)) + return 1; + fprintf(stderr, "%20.2lf op/s\n", rate); fprintf(stderr, "Ed25519 verify for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) - ecdsa_verify(key1, buf1, 256, buf2); - fprintf(stderr, "%20.2lf op/s\n", rate); + if(!ecdsa_verify(key1, buf1, 256, buf2)) { + fprintf(stderr, "Signature verification failed\n"); + return 1; + } + fprintf(stderr, "%18.2lf op/s\n", rate); ecdh1 = ecdh_generate_public(buf1); fprintf(stderr, "ECDH for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { ecdh2 = ecdh_generate_public(buf2); - ecdh_compute_shared(ecdh2, buf1, buf3); + if(!ecdh2) + return 1; + if(!ecdh_compute_shared(ecdh2, buf1, buf3)) + return 1; } fprintf(stderr, "%28.2lf op/s\n", rate); ecdh_free(ecdh1); diff --git a/src/sptps_test.c b/src/sptps_test.c index 95bfda8..a394175 100644 --- a/src/sptps_test.c +++ b/src/sptps_test.c @@ -35,8 +35,10 @@ bool send_request(void *c, const char *msg, ...) { return false; } struct list_t *connection_list = NULL; bool send_meta(void *c, const char *msg , int len) { return false; } char *logfilename = NULL; +bool do_detach = false; struct timeval now; +static bool special; static bool verbose; static bool readonly; static bool writeonly; @@ -69,6 +71,7 @@ static struct option const long_options[] = { {"writeonly", no_argument, NULL, 'w'}, {"packet-loss", required_argument, NULL, 'L'}, {"replay-window", required_argument, NULL, 'W'}, + {"special", no_argument, NULL, 's'}, {"verbose", required_argument, NULL, 'v'}, {"help", no_argument, NULL, 1}, {NULL, 0, NULL, 0} @@ -88,6 +91,7 @@ static void usage() { " -w, --writeonly Only send data from stdin to the socket.\n" " -L, --packet-loss RATE Fake packet loss of RATE percent.\n" " -R, --replay-window N Set replay window to N bytes.\n" + " -s, --special Enable special handling of lines starting with #, ^ and $.\n" " -v, --verbose Display debug messages.\n" "\n"); fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n"); @@ -106,7 +110,7 @@ int main(int argc, char *argv[]) { ecdsa_t *mykey = NULL, *hiskey = NULL; bool quit = false; - while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) { + while((r = getopt_long(argc, argv, "dqrstwL:W:v", long_options, &option_index)) != EOF) { switch (r) { case 0: /* long option */ break; @@ -149,6 +153,10 @@ int main(int argc, char *argv[]) { verbose = true; break; + case 's': /* special character handling */ + special = true; + break; + case '?': /* wrong options */ usage(); return 1; @@ -271,11 +279,19 @@ int main(int argc, char *argv[]) { crypto_init(); FILE *fp = fopen(argv[1], "r"); + if(!fp) { + fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno)); + return 1; + } if(!(mykey = ecdsa_read_pem_private_key(fp))) return 1; fclose(fp); fp = fopen(argv[2], "r"); + if(!fp) { + fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno)); + return 1; + } if(!(hiskey = ecdsa_read_pem_public_key(fp))) return 1; fclose(fp); @@ -315,11 +331,11 @@ int main(int argc, char *argv[]) { readonly = true; continue; } - if(buf[0] == '#') + if(special && buf[0] == '#') s.outseqno = atoi(buf + 1); - if(buf[0] == '^') + if(special && buf[0] == '^') sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0); - else if(buf[0] == '$') { + else if(special && buf[0] == '$') { sptps_force_kex(&s); if(len > 1) sptps_send_record(&s, 0, buf, len); @@ -348,8 +364,19 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Dropped.\n"); continue; } - if(!sptps_receive_data(&s, buf, len) && !datagram) - return 1; + char *bufp = buf; + while(len) { + size_t done = sptps_receive_data(&s, bufp, len); + if(!done) { + if(!datagram) + return 1; + } else { + break; + } + + bufp += done; + len -= done; + } } } diff --git a/src/subnet.c b/src/subnet.c index 534e5b5..090a62b 100644 --- a/src/subnet.c +++ b/src/subnet.c @@ -40,9 +40,9 @@ splay_tree_t *subnet_tree; /* Subnet lookup cache */ -hash_t *ipv4_cache; -hash_t *ipv6_cache; -hash_t *mac_cache; +static hash_t *ipv4_cache; +static hash_t *ipv6_cache; +static hash_t *mac_cache; void subnet_cache_flush(void) { hash_clear(ipv4_cache); diff --git a/src/subnet.h b/src/subnet.h index 9fd95b6..6184e6b 100644 --- a/src/subnet.h +++ b/src/subnet.h @@ -22,6 +22,7 @@ #define __TINC_SUBNET_H__ #include "net.h" +#include "node.h" typedef enum subnet_type_t { SUBNET_MAC = 0, @@ -44,8 +45,6 @@ typedef struct subnet_ipv6_t { int prefixlength; } subnet_ipv6_t; -#include "node.h" - typedef struct subnet_t { struct node_t *owner; /* the owner of this subnet */ diff --git a/src/subnet_parse.c b/src/subnet_parse.c index c919b59..611d6bd 100644 --- a/src/subnet_parse.c +++ b/src/subnet_parse.c @@ -401,11 +401,8 @@ bool net2str(char *netstr, int len, const subnet_t *subnet) { len -= result; } - if (subnet->weight != DEFAULT_WEIGHT) { + if (subnet->weight != DEFAULT_WEIGHT) snprintf(netstr, len, "#%d", subnet->weight); - netstr += result; - len -= result; - } return true; } diff --git a/src/system.h b/src/system.h index 7180b87..2201ff3 100644 --- a/src/system.h +++ b/src/system.h @@ -1,7 +1,7 @@ /* system.h -- system headers Copyright (C) 1998-2005 Ivo Timmermans - 2003-2013 Guus Sliepen + 2003-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,12 +25,6 @@ #include "have.h" -#ifndef HAVE_STDBOOL_H -typedef int bool; -#define true 1 -#define false 0 -#endif - #ifndef HAVE_STRSIGNAL # define strsignal(p) "" #endif @@ -39,8 +33,4 @@ typedef int bool; #include "dropin.h" -#ifndef HAVE_SOCKLEN_T -typedef int socklen_t; -#endif - #endif /* __TINC_SYSTEM_H__ */ diff --git a/src/tincctl.c b/src/tincctl.c index abaf6ee..e42ec2c 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -1,6 +1,6 @@ /* tincctl.c -- Controlling a running tincd - Copyright (C) 2007-2014 Guus Sliepen + Copyright (C) 2007-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,7 @@ #include "control_common.h" #include "crypto.h" #include "ecdsagen.h" +#include "fsck.h" #include "info.h" #include "invitation.h" #include "names.h" @@ -66,7 +67,7 @@ char line[4096]; static int code; static int req; static int result; -static bool force = false; +bool force = false; bool tty = true; bool confbasegiven = false; bool netnamegiven = false; @@ -87,8 +88,8 @@ static struct option const long_options[] = { static void version(void) { printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE, - VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR); - printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n" + BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR); + printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n" "See the AUTHORS file for a complete list.\n\n" "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" "and you are welcome to redistribute it under certain conditions;\n" @@ -105,6 +106,7 @@ static void usage(bool status) { " -c, --config=DIR Read configuration options from DIR.\n" " -n, --net=NETNAME Connect to net NETNAME.\n" " --pidfile=FILENAME Read control cookie from FILENAME.\n" + " --force Force some commands to work despite warnings.\n" " --help Display this help and exit.\n" " --version Output version information and exit.\n" "\n" @@ -119,8 +121,12 @@ static void usage(bool status) { " restart [tincd options] Restart tincd.\n" " reload Partially reload configuration of running tincd.\n" " pid Show PID of currently running tincd.\n" +#ifdef DISABLE_LEGACY + " generate-keys Generate a new Ed25519 public/private keypair.\n" +#else " generate-keys [bits] Generate new RSA and Ed25519 public/private keypairs.\n" " generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n" +#endif " generate-ed25519-keys Generate a new Ed25519 public/private keypair.\n" " dump Dump a list of one of the following things:\n" " [reachable] nodes - all known nodes in the VPN\n" @@ -128,6 +134,7 @@ static void usage(bool status) { " subnets - all known subnets in the VPN\n" " connections - all meta connections with ourself\n" " [di]graph - graph of the VPN in dotty format\n" + " invitations - outstanding invitations\n" " info NODE|SUBNET|ADDRESS Give information about a particular NODE, SUBNET or ADDRESS.\n" " purge Purge unreachable nodes\n" " debug N Set debug level\n" @@ -140,12 +147,15 @@ static void usage(bool status) { " log [level] Dump log output [up to the specified level]\n" " export Export host configuration of local node to standard output\n" " export-all Export all host configuration files to standard output\n" - " import [--force] Import host configuration file(s) from standard input\n" - " exchange [--force] Same as export followed by import\n" - " exchange-all [--force] Same as export-all followed by import\n" + " import Import host configuration file(s) from standard input\n" + " exchange Same as export followed by import\n" + " exchange-all Same as export-all followed by import\n" " invite NODE [...] Generate an invitation for NODE\n" - " join INVITATION Join a VPN using an INVITIATION\n" + " join INVITATION Join a VPN using an INVITATION\n" " network [NETNAME] List all known networks, or switch to the one named NETNAME.\n" + " fsck Check the configuration files for problems.\n" + " sign [FILE] Generate a signed version of a file.\n" + " verify NODE [FILE] Verify that a file was signed by the given NODE.\n" "\n"); printf("Report bugs to tinc@tinc-vpn.org.\n"); } @@ -225,6 +235,12 @@ FILE *fopenmask(const char *filename, const char *mode, mode_t perms) { perms &= ~mask; umask(~perms); FILE *f = fopen(filename, mode); + + if(!f) { + fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); + return NULL; + } + #ifdef HAVE_FCHMOD if((perms & 0444) && f) fchmod(fileno(f), perms); @@ -314,7 +330,7 @@ static void disable_old_keys(const char *filename, const char *what) { static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) { FILE *r; - char *directory; + char directory[PATH_MAX] = "."; char buf[PATH_MAX]; char buf2[PATH_MAX]; @@ -342,7 +358,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo if(filename[0] != '/') { #endif /* The directory is a relative path or a filename. */ - directory = get_current_dir_name(); + getcwd(directory, sizeof directory); snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename); filename = buf2; } @@ -368,7 +384,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo static bool ed25519_keygen(bool ask) { ecdsa_t *key; FILE *f; - char *pubname, *privname; + char fname[PATH_MAX]; fprintf(stderr, "Generating Ed25519 keypair:\n"); @@ -378,29 +394,25 @@ static bool ed25519_keygen(bool ask) { } else fprintf(stderr, "Done.\n"); - xasprintf(&privname, "%s" SLASH "ed25519_key.priv", confbase); - f = ask_and_open(privname, "private Ed25519 key", "a", ask, 0600); - free(privname); + snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase); + f = ask_and_open(fname, "private Ed25519 key", "a", ask, 0600); if(!f) - return false; + goto error; if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Error writing private key!\n"); - ecdsa_free(key); - fclose(f); - return false; + goto error; } fclose(f); if(name) - xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name); + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); else - xasprintf(&pubname, "%s" SLASH "ed25519_key.pub", confbase); + snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.pub", confbase); - f = ask_and_open(pubname, "public Ed25519 key", "a", ask, 0666); - free(pubname); + f = ask_and_open(fname, "public Ed25519 key", "a", ask, 0666); if(!f) return false; @@ -413,8 +425,15 @@ static bool ed25519_keygen(bool ask) { ecdsa_free(key); return true; + +error: + if(f) + fclose(f); + ecdsa_free(key); + return false; } +#ifndef DISABLE_LEGACY /* Generate a public/private RSA keypair, and ask for a file to store them in. @@ -422,7 +441,7 @@ static bool ed25519_keygen(bool ask) { static bool rsa_keygen(int bits, bool ask) { rsa_t *key; FILE *f; - char *pubname, *privname; + char fname[PATH_MAX]; // Make sure the key size is a multiple of 8 bits. bits &= ~0x7; @@ -441,45 +460,46 @@ static bool rsa_keygen(int bits, bool ask) { } else fprintf(stderr, "Done.\n"); - xasprintf(&privname, "%s" SLASH "rsa_key.priv", confbase); - f = ask_and_open(privname, "private RSA key", "a", ask, 0600); - free(privname); + snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.priv", confbase); + f = ask_and_open(fname, "private RSA key", "a", ask, 0600); if(!f) - return false; + goto error; if(!rsa_write_pem_private_key(key, f)) { fprintf(stderr, "Error writing private key!\n"); - fclose(f); - rsa_free(key); - return false; + goto error; } fclose(f); if(name) - xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name); + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name); else - xasprintf(&pubname, "%s" SLASH "rsa_key.pub", confbase); + snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.pub", confbase); - f = ask_and_open(pubname, "public RSA key", "a", ask, 0666); - free(pubname); + f = ask_and_open(fname, "public RSA key", "a", ask, 0666); if(!f) - return false; + goto error; if(!rsa_write_pem_public_key(key, f)) { fprintf(stderr, "Error writing public key!\n"); - fclose(f); - rsa_free(key); - return false; + goto error; } fclose(f); rsa_free(key); return true; + +error: + if(f) + fclose(f); + rsa_free(key); + return false; } +#endif char buffer[4096]; size_t blen = 0; @@ -842,6 +862,13 @@ static int cmd_start(int argc, char *argv[]) { } return status; #else + int pfd[2] = {-1, -1}; + if(socketpair(AF_UNIX, SOCK_STREAM, 0, pfd)) { + fprintf(stderr, "Could not create umbilical socket: %s\n", strerror(errno)); + free(nargv); + return 1; + } + pid_t pid = fork(); if(pid == -1) { fprintf(stderr, "Could not fork: %s\n", strerror(errno)); @@ -849,8 +876,15 @@ static int cmd_start(int argc, char *argv[]) { return 1; } - if(!pid) + if(!pid) { + close(pfd[0]); + char buf[100] = ""; + snprintf(buf, sizeof buf, "%d", pfd[1]); + setenv("TINC_UMBILICAL", buf, true); exit(execvp(c, nargv)); + } else { + close(pfd[1]); + } free(nargv); @@ -858,12 +892,33 @@ static int cmd_start(int argc, char *argv[]) { #ifdef SIGINT signal(SIGINT, SIG_IGN); #endif + + // Pass all log messages from the umbilical to stderr. + // A nul-byte right before closure means tincd started succesfully. + bool failure = true; + char buf[1024]; + ssize_t len; + + while((len = read(pfd[0], buf, sizeof buf)) > 0) { + failure = buf[len - 1]; + if(!failure) + len--; + write(2, buf, len); + } + + if(len) + failure = true; + + close(pfd[0]); + + // Make sure the child process is really gone. result = waitpid(pid, &status, 0); + #ifdef SIGINT signal(SIGINT, SIG_DFL); #endif - if(result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) { + if(failure || result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) { fprintf(stderr, "Error starting %s\n", c); return 1; } @@ -934,6 +989,65 @@ static int cmd_reload(int argc, char *argv[]) { } +static int dump_invitations(void) { + char dname[PATH_MAX]; + snprintf(dname, sizeof dname, "%s" SLASH "invitations", confbase); + DIR *dir = opendir(dname); + if(!dir) { + if(errno == ENOENT) { + fprintf(stderr, "No outstanding invitations.\n"); + return 0; + } + + fprintf(stderr, "Cannot not read directory %s: %s\n", dname, strerror(errno)); + return 1; + } + + struct dirent *ent; + bool found = false; + + while((ent = readdir(dir))) { + char buf[MAX_STRING_SIZE]; + if(b64decode(ent->d_name, buf, 24) != 18) + continue; + + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ent->d_name); + FILE *f = fopen(fname, "r"); + if(!f) { + fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno)); + fclose(f); + continue; + } + + buf[0] = 0; + if(!fgets(buf, sizeof buf, f)) { + fprintf(stderr, "Invalid invitation file %s", fname); + fclose(f); + continue; + } + fclose(f); + + char *eol = buf + strlen(buf); + while(strchr("\t \r\n", *--eol)) + *eol = 0; + if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) { + fprintf(stderr, "Invalid invitation file %s", fname); + continue; + } + + found = true; + printf("%s %s\n", ent->d_name, buf + 7); + } + + closedir(dir); + + if(!found) + fprintf(stderr, "No outstanding invitations.\n"); + + return 0; +} + static int cmd_dump(int argc, char *argv[]) { bool only_reachable = false; @@ -954,6 +1068,9 @@ static int cmd_dump(int argc, char *argv[]) { return 1; } + if(!strcasecmp(argv[1], "invitations")) + return dump_invitations(); + if(!connect_tincd(true)) return 1; @@ -1316,6 +1433,29 @@ char *get_my_name(bool verbose) { return NULL; } +ecdsa_t *get_pubkey(FILE *f) { + char buf[4096]; + char *value; + while(fgets(buf, sizeof buf, f)) { + int len = strcspn(buf, "\t ="); + value = buf + len; + value += strspn(value, "\t "); + if(*value == '=') { + value++; + value += strspn(value, "\t "); + } + if(!rstrip(value)) + continue; + buf[len] = 0; + if(strcasecmp(buf, "Ed25519PublicKey")) + continue; + if(*value) + return ecdsa_set_base64_public_key(value); + } + + return NULL; +} + const var_t variables[] = { /* Server configuration */ {"AddressFamily", VAR_SERVER}, @@ -1358,8 +1498,17 @@ const var_t variables[] = { {"ScriptsInterpreter", VAR_SERVER}, {"StrictSubnets", VAR_SERVER}, {"TunnelServer", VAR_SERVER}, + {"UDPDiscovery", VAR_SERVER}, + {"UDPDiscoveryKeepaliveInterval", VAR_SERVER}, + {"UDPDiscoveryInterval", VAR_SERVER}, + {"UDPDiscoveryTimeout", VAR_SERVER}, + {"MTUInfoInterval", VAR_SERVER}, + {"UDPInfoInterval", VAR_SERVER}, {"UDPRcvBuf", VAR_SERVER}, {"UDPSndBuf", VAR_SERVER}, + {"UPnP", VAR_SERVER}, + {"UPnPDiscoverWait", VAR_SERVER}, + {"UPnPRefreshPeriod", VAR_SERVER}, {"VDEGroup", VAR_SERVER}, {"VDEPort", VAR_SERVER}, /* Host configuration */ @@ -1519,11 +1668,11 @@ static int cmd_config(int argc, char *argv[]) { } // Open the right configuration file. - char *filename; + char filename[PATH_MAX]; if(node) - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, node); + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, node); else - filename = tinc_conf; + snprintf(filename, sizeof filename, "%s", tinc_conf); FILE *f = fopen(filename, "r"); if(!f) { @@ -1531,11 +1680,11 @@ static int cmd_config(int argc, char *argv[]) { return 1; } - char *tmpfile = NULL; + char tmpfile[PATH_MAX]; FILE *tf = NULL; if(action >= -1) { - xasprintf(&tmpfile, "%s.config.tmp", filename); + snprintf(tmpfile, sizeof tmpfile, "%s.config.tmp", filename); tf = fopen(tmpfile, "w"); if(!tf) { fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno)); @@ -1598,6 +1747,11 @@ static int cmd_config(int argc, char *argv[]) { } set = true; continue; + // Add + } else if(action > 0) { + // Check if we've already seen this variable with the same value + if(!strcasecmp(bvalue, value)) + found = true; } } @@ -1630,7 +1784,7 @@ static int cmd_config(int argc, char *argv[]) { } // Add new variable if necessary. - if(action > 0 || (action == 0 && !set)) { + if((action > 0 && !found)|| (action == 0 && !set)) { if(fprintf(tf, "%s = %s\n", variable, value) < 0) { fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno)); return 1; @@ -1679,7 +1833,7 @@ static int cmd_config(int argc, char *argv[]) { } static bool try_bind(int port) { - struct addrinfo *ai = NULL; + struct addrinfo *ai = NULL, *aip; struct addrinfo hint = { .ai_flags = AI_PASSIVE, .ai_family = AF_UNSPEC, @@ -1687,24 +1841,30 @@ static bool try_bind(int port) { .ai_protocol = IPPROTO_TCP, }; + bool success = true; char portstr[16]; snprintf(portstr, sizeof portstr, "%d", port); if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai) return false; - while(ai) { + for(aip = ai; aip; aip = aip->ai_next) { int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); - if(!fd) - return false; + if(!fd) { + success = false; + break; + } + int result = bind(fd, ai->ai_addr, ai->ai_addrlen); closesocket(fd); - if(result) - return false; - ai = ai->ai_next; + if(result) { + success = false; + break; + } } - return true; + freeaddrinfo(ai); + return success; } int check_port(char *name) { @@ -1716,11 +1876,11 @@ int check_port(char *name) { for(int i = 0; i < 100; i++) { int port = 0x1000 + (rand() & 0x7fff); if(try_bind(port)) { - char *filename; - xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name); + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name); FILE *f = fopen(filename, "a"); - free(filename); if(!f) { + fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); fprintf(stderr, "Please change tinc's Port manually.\n"); return 0; } @@ -1800,14 +1960,19 @@ static int cmd_init(int argc, char *argv[]) { fprintf(f, "Name = %s\n", name); fclose(f); - if(!rsa_keygen(2048, false) || !ed25519_keygen(false)) +#ifndef DISABLE_LEGACY + if(!rsa_keygen(2048, false)) + return 1; +#endif + + if(!ed25519_keygen(false)) return 1; check_port(name); #ifndef HAVE_MINGW - char *filename; - xasprintf(&filename, "%s" SLASH "tinc-up", confbase); + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "tinc-up", confbase); if(access(filename, F_OK)) { FILE *f = fopenmask(filename, "w", 0777); if(!f) { @@ -1824,7 +1989,11 @@ static int cmd_init(int argc, char *argv[]) { } static int cmd_generate_keys(int argc, char *argv[]) { +#ifdef DISABLE_LEGACY + if(argc > 1) { +#else if(argc > 2) { +#endif fprintf(stderr, "Too many arguments!\n"); return 1; } @@ -1832,9 +2001,18 @@ static int cmd_generate_keys(int argc, char *argv[]) { if(!name) name = get_my_name(false); - return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true)); +#ifndef DISABLE_LEGACY + if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true)) + return 1; +#endif + + if(!ed25519_keygen(true)) + return 1; + + return 0; } +#ifndef DISABLE_LEGACY static int cmd_generate_rsa_keys(int argc, char *argv[]) { if(argc > 2) { fprintf(stderr, "Too many arguments!\n"); @@ -1846,6 +2024,7 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) { return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true); } +#endif static int cmd_generate_ed25519_keys(int argc, char *argv[]) { if(argc > 1) { @@ -1903,12 +2082,12 @@ static int cmd_edit(int argc, char *argv[]) { return 1; } - char *filename = NULL; + char filename[PATH_MAX] = ""; if(strncmp(argv[1], "hosts" SLASH, 6)) { for(int i = 0; conffiles[i]; i++) { if(!strcmp(argv[1], conffiles[i])) { - xasprintf(&filename, "%s" SLASH "%s", confbase, argv[1]); + snprintf(filename, sizeof filename, "%s" SLASH "%s", confbase, argv[1]); break; } } @@ -1916,8 +2095,8 @@ static int cmd_edit(int argc, char *argv[]) { argv[1] += 6; } - if(!filename) { - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, argv[1]); + if(!*filename) { + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, argv[1]); char *dash = strchr(argv[1], '-'); if(dash) { *dash++ = 0; @@ -1935,6 +2114,7 @@ static int cmd_edit(int argc, char *argv[]) { xasprintf(&command, "edit \"%s\"", filename); #endif int result = system(command); + free(command); if(result) return result; @@ -1946,8 +2126,8 @@ static int cmd_edit(int argc, char *argv[]) { } static int export(const char *name, FILE *out) { - char *filename; - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name); + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name); FILE *in = fopen(filename, "r"); if(!in) { fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno)); @@ -2034,7 +2214,7 @@ static int cmd_import(int argc, char *argv[]) { char buf[4096]; char name[4096]; - char *filename = NULL; + char filename[PATH_MAX] = ""; int count = 0; bool firstline = true; @@ -2050,8 +2230,7 @@ static int cmd_import(int argc, char *argv[]) { if(out) fclose(out); - free(filename); - xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name); + snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name); if(!force && !access(filename, F_OK)) { fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename); @@ -2105,27 +2284,29 @@ static int cmd_exchange_all(int argc, char *argv[]) { } static int switch_network(char *name) { + if(strcmp(name, ".")) { + if(!check_netname(name, false)) { + fprintf(stderr, "Invalid character in netname!\n"); + return 1; + } + + if(!check_netname(name, true)) + fprintf(stderr, "Warning: unsafe character in netname!\n"); + } + if(fd >= 0) { close(fd); fd = -1; } - free(confbase); - confbase = NULL; - free(pidfilename); - pidfilename = NULL; - free(logfilename); - logfilename = NULL; - free(unixsocketname); - unixsocketname = NULL; + free_names(); + netname = strcmp(name, ".") ? xstrdup(name) : NULL; + make_names(false); + free(tinc_conf); free(hosts_dir); free(prompt); - free(netname); - netname = strcmp(name, ".") ? xstrdup(name) : NULL; - - make_names(); xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase); xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase); xasprintf(&prompt, "%s> ", identname); @@ -2158,11 +2339,10 @@ static int cmd_network(int argc, char *argv[]) { continue; } - char *fname; - xasprintf(&fname, "%s/%s/tinc.conf", confdir, ent->d_name); + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, "%s/%s/tinc.conf", confdir, ent->d_name); if(!access(fname, R_OK)) printf("%s\n", ent->d_name); - free(fname); } closedir(dir); @@ -2170,6 +2350,240 @@ static int cmd_network(int argc, char *argv[]) { return 0; } +static int cmd_fsck(int argc, char *argv[]) { + if(argc > 1) { + fprintf(stderr, "Too many arguments!\n"); + return 1; + } + + return fsck(orig_argv[0]); +} + +static void *readfile(FILE *in, size_t *len) { + size_t count = 0; + size_t alloced = 4096; + char *buf = xmalloc(alloced); + + while(!feof(in)) { + size_t read = fread(buf + count, 1, alloced - count, in); + if(!read) + break; + count += read; + if(count >= alloced) { + alloced *= 2; + buf = xrealloc(buf, alloced); + } + } + + if(len) + *len = count; + + return buf; +} + +static int cmd_sign(int argc, char *argv[]) { + if(argc > 2) { + fprintf(stderr, "Too many arguments!\n"); + return 1; + } + + if(!name) { + name = get_my_name(true); + if(!name) + return 1; + } + + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase); + FILE *fp = fopen(fname, "r"); + if(!fp) { + fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno)); + return 1; + } + + ecdsa_t *key = ecdsa_read_pem_private_key(fp); + + if(!key) { + fprintf(stderr, "Could not read private key from %s\n", fname); + fclose(fp); + return 1; + } + + fclose(fp); + + FILE *in; + + if(argc == 2) { + in = fopen(argv[1], "rb"); + if(!in) { + fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno)); + ecdsa_free(key); + return 1; + } + } else { + in = stdin; + } + + size_t len; + char *data = readfile(in, &len); + if(in != stdin) + fclose(in); + if(!data) { + fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno)); + ecdsa_free(key); + return 1; + } + + // Ensure we sign our name and current time as well + long t = time(NULL); + char *trailer; + xasprintf(&trailer, " %s %ld", name, t); + int trailer_len = strlen(trailer); + + data = xrealloc(data, len + trailer_len); + memcpy(data + len, trailer, trailer_len); + free(trailer); + + char sig[87]; + if(!ecdsa_sign(key, data, len + trailer_len, sig)) { + fprintf(stderr, "Error generating signature\n"); + free(data); + ecdsa_free(key); + return 1; + } + b64encode(sig, sig, 64); + ecdsa_free(key); + + fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig); + fwrite(data, len, 1, stdout); + + free(data); + return 0; +} + +static int cmd_verify(int argc, char *argv[]) { + if(argc < 2) { + fprintf(stderr, "Not enough arguments!\n"); + return 1; + } + + if(argc > 3) { + fprintf(stderr, "Too many arguments!\n"); + return 1; + } + + char *node = argv[1]; + if(!strcmp(node, ".")) { + if(!name) { + name = get_my_name(true); + if(!name) + return 1; + } + node = name; + } else if(!strcmp(node, "*")) { + node = NULL; + } else { + if(!check_id(node)) { + fprintf(stderr, "Invalid node name\n"); + return 1; + } + } + + FILE *in; + + if(argc == 3) { + in = fopen(argv[2], "rb"); + if(!in) { + fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno)); + return 1; + } + } else { + in = stdin; + } + + size_t len; + char *data = readfile(in, &len); + if(in != stdin) + fclose(in); + if(!data) { + fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno)); + return 1; + } + + char *newline = memchr(data, '\n', len); + if(!newline || (newline - data > MAX_STRING_SIZE - 1)) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + *newline++ = '\0'; + size_t skip = newline - data; + + char signer[MAX_STRING_SIZE] = ""; + char sig[MAX_STRING_SIZE] = ""; + long t = 0; + + if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) { + fprintf(stderr, "Invalid input\n"); + return 1; + } + + if(node && strcmp(node, signer)) { + fprintf(stderr, "Signature is not made by %s\n", node); + return 1; + } + + if(!node) + node = signer; + + char *trailer; + xasprintf(&trailer, " %s %ld", signer, t); + int trailer_len = strlen(trailer); + + data = xrealloc(data, len + trailer_len); + memcpy(data + len, trailer, trailer_len); + free(trailer); + + newline = data + skip; + + char fname[PATH_MAX]; + snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node); + FILE *fp = fopen(fname, "r"); + if(!fp) { + fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno)); + free(data); + return 1; + } + + ecdsa_t *key = get_pubkey(fp); + if(!key) { + rewind(fp); + key = ecdsa_read_pem_public_key(fp); + } + if(!key) { + fprintf(stderr, "Could not read public key from %s\n", fname); + fclose(fp); + free(data); + return 1; + } + + fclose(fp); + + if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) { + fprintf(stderr, "Invalid signature\n"); + free(data); + ecdsa_free(key); + return 1; + } + + ecdsa_free(key); + + fwrite(newline, len - (newline - data), 1, stdout); + + free(data); + return 0; +} + static const struct { const char *command; int (*function)(int argc, char *argv[]); @@ -2180,6 +2594,7 @@ static const struct { {"restart", cmd_restart}, {"reload", cmd_reload}, {"dump", cmd_dump}, + {"list", cmd_dump}, {"purge", cmd_purge}, {"debug", cmd_debug}, {"retry", cmd_retry}, @@ -2196,7 +2611,9 @@ static const struct { {"set", cmd_config}, {"init", cmd_init}, {"generate-keys", cmd_generate_keys}, +#ifndef DISABLE_LEGACY {"generate-rsa-keys", cmd_generate_rsa_keys}, +#endif {"generate-ed25519-keys", cmd_generate_ed25519_keys}, {"help", cmd_help}, {"version", cmd_version}, @@ -2210,6 +2627,9 @@ static const struct { {"invite", cmd_invite}, {"join", cmd_join}, {"network", cmd_network}, + {"fsck", cmd_fsck}, + {"sign", cmd_sign}, + {"verify", cmd_verify}, {NULL, NULL}, }; @@ -2444,7 +2864,7 @@ int main(int argc, char *argv[]) { if(!parse_options(argc, argv)) return 1; - make_names(); + make_names(false); xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase); xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase); diff --git a/src/tincctl.h b/src/tincctl.h index e636887..6628f2b 100644 --- a/src/tincctl.h +++ b/src/tincctl.h @@ -1,6 +1,6 @@ /* tincctl.h -- header for tincctl.c. - Copyright (C) 2011-2013 Guus Sliepen + Copyright (C) 2011-2016 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #define __TINC_TINCCTL_H__ extern bool tty; +extern bool force; extern char line[4096]; extern int fd; extern char buffer[4096]; @@ -49,6 +50,7 @@ extern bool sendline(int fd, char *format, ...); extern bool recvline(int fd, char *line, size_t len); extern int check_port(char *name); extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms); +extern ecdsa_t *get_pubkey(FILE *f); #endif diff --git a/src/tincd.c b/src/tincd.c index 15cddb1..4da9bd5 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -1,7 +1,7 @@ /* tincd.c -- the main file for tincd Copyright (C) 1998-2005 Ivo Timmermans - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2008 Max Rijevski 2009 Michael Tokarev 2010 Julien Muchembled @@ -43,8 +43,6 @@ #include #endif -#include - #include "conf.h" #include "control.h" #include "crypto.h" @@ -85,6 +83,9 @@ static const char *switchuser = NULL; /* If nonzero, write log entries to a separate file. */ bool use_logfile = false; +/* If nonzero, use syslog instead of stderr in no-detach mode. */ +bool use_syslog = false; + char **g_argv; /* a copy of the cmdline arguments */ static int status = 1; @@ -101,6 +102,7 @@ static struct option const long_options[] = { {"chroot", no_argument, NULL, 'R'}, {"user", required_argument, NULL, 'U'}, {"logfile", optional_argument, NULL, 4}, + {"syslog", no_argument, NULL, 's'}, {"pidfile", required_argument, NULL, 5}, {"option", required_argument, NULL, 'o'}, {NULL, 0, NULL, 0} @@ -125,6 +127,7 @@ static void usage(bool status) { " -L, --mlock Lock tinc into main memory.\n" #endif " --logfile[=FILENAME] Write log entries to a logfile.\n" + " -s --syslog Use syslog instead of stderr with --no-detach.\n" " --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n" " --bypass-security Disables meta protocol security, for debugging.\n" " -o, --option[HOST.]KEY=VALUE Set global/host configuration value.\n" @@ -146,7 +149,7 @@ static bool parse_options(int argc, char **argv) { cmdline_conf = list_alloc((list_action_t)free_config); - while((r = getopt_long(argc, argv, "c:DLd::n:o:RU:", long_options, &option_index)) != EOF) { + while((r = getopt_long(argc, argv, "c:DLd::n:so:RU:", long_options, &option_index)) != EOF) { switch (r) { case 0: /* long option */ break; @@ -181,6 +184,11 @@ static bool parse_options(int argc, char **argv) { netname = xstrdup(optarg); break; + case 's': /* syslog */ + use_logfile = false; + use_syslog = true; + break; + case 'o': /* option */ cfg = parse_config_line(optarg, NULL, ++lineno); if (!cfg) @@ -216,6 +224,7 @@ static bool parse_options(int argc, char **argv) { break; case 4: /* write log entries to a file */ + use_syslog = false; use_logfile = true; if(!optarg && optind < argc && *argv[optind] != '-') optarg = argv[optind++]; @@ -252,11 +261,14 @@ static bool parse_options(int argc, char **argv) { netname = NULL; } - if(netname && (strpbrk(netname, "\\/") || *netname == '.')) { + if(netname && !check_netname(netname, false)) { fprintf(stderr, "Invalid character in netname!\n"); return false; } + if(netname && !check_netname(netname, true)) + fprintf(stderr, "Warning: unsafe character in netname!\n"); + return true; } @@ -328,12 +340,13 @@ int main(int argc, char **argv) { if(!parse_options(argc, argv)) return 1; - make_names(); + make_names(true); + chdir(confbase); if(show_version) { printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE, - VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR); - printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n" + BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR); + printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n" "See the AUTHORS file for a complete list.\n\n" "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" "and you are welcome to redistribute it under certain conditions;\n" @@ -352,6 +365,18 @@ int main(int argc, char **argv) { logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError())); return 1; } +#else + // Check if we got an umbilical fd from the process that started us + char *umbstr = getenv("TINC_UMBILICAL"); + if(umbstr) { + umbilical = atoi(umbstr); + if(fcntl(umbilical, F_GETFL) < 0) + umbilical = 0; +#ifdef FD_CLOEXEC + if(umbilical) + fcntl(umbilical, F_SETFD, FD_CLOEXEC); +#endif + } #endif openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR); @@ -455,6 +480,12 @@ int main2(int argc, char **argv) { logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready"); + if(umbilical) { // snip! + write(umbilical, "", 1); + close(umbilical); + umbilical = 0; + } + try_outgoing_connections(); status = main_loop(); diff --git a/src/upnp.c b/src/upnp.c new file mode 100644 index 0000000..abd2f92 --- /dev/null +++ b/src/upnp.c @@ -0,0 +1,164 @@ +/* + upnp.c -- UPnP-IGD client + Copyright (C) 2015 Guus Sliepen , + + 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 "upnp.h" + +#include + +#include "miniupnpc/miniupnpc.h" +#include "miniupnpc/upnpcommands.h" +#include "miniupnpc/upnperrors.h" + +#include "system.h" +#include "logger.h" +#include "names.h" +#include "net.h" +#include "netutl.h" +#include "utils.h" + +static bool upnp_tcp; +static bool upnp_udp; +static int upnp_discover_wait = 5; +static int upnp_refresh_period = 60; + +// Unfortunately, libminiupnpc devs don't seem to care about API compatibility, +// and there are slight changes to function signatures between library versions. +// Well, at least they publish a "MINIUPNPC_API_VERSION" constant, so we got that going for us, which is nice. +// Differences between API versions are documented in "apiversions.txt" in the libminiupnpc distribution. + +#ifndef MINIUPNPC_API_VERSION +#define MINIUPNPC_API_VERSION 0 +#endif + +static struct UPNPDev *upnp_discover(int delay, int *error) { +#if MINIUPNPC_API_VERSION <= 13 + +#if MINIUPNPC_API_VERSION < 8 +#warning "The version of libminiupnpc you're building against seems to be too old. Expect trouble." +#endif + + return upnpDiscover(delay, NULL, NULL, false, false, error); + +#elif MINIUPNPC_API_VERSION <= 14 + + return upnpDiscover(delay, NULL NULL, false, false, 2, error); + +#else + +#if MINIUPNPC_API_VERSION > 15 +#warning "The version of libminiupnpc you're building against seems to be too recent. Expect trouble." +#endif + + return upnpDiscover(delay, NULL, NULL, UPNP_LOCAL_PORT_ANY, false, 2, error); + +#endif +} + +static void upnp_add_mapping(struct UPNPUrls *urls, struct IGDdatas *data, const char *myaddr, int socket, const char *proto) { + // Extract the port from the listening socket. + // Note that we can't simply use listen_socket[].sa because this won't have the port + // if we're running with Port=0 (dynamically assigned port). + sockaddr_t sa; + socklen_t salen = sizeof sa; + if (getsockname(socket, &sa.sa, &salen)) { + logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket address: [%d] %s", sockerrno, sockstrerror(sockerrno)); + return; + } + char *port; + sockaddr2str(&sa, NULL, &port); + if (!port) { + logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket port"); + return; + } + + // Use a lease twice as long as the refresh period so that the mapping won't expire before we refresh. + char lease_duration[16]; + snprintf(lease_duration, sizeof lease_duration, "%d", upnp_refresh_period * 2); + + int error = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, port, port, myaddr, identname, proto, NULL, lease_duration); + if (error == 0) { + logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Successfully set port mapping (%s:%s %s for %s seconds)", myaddr, port, proto, lease_duration); + } else { + logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Failed to set port mapping (%s:%s %s for %s seconds): [%d] %s", myaddr, port, proto, lease_duration, error, strupnperror(error)); + } + + free(port); +} + +static void upnp_refresh() { + logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Discovering IGD devices"); + + int error; + struct UPNPDev *devices = upnp_discover(upnp_discover_wait * 1000, &error); + if (!devices) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] Unable to find IGD devices: [%d] %s", error, strupnperror(error)); + freeUPNPDevlist(devices); + return; + } + + struct UPNPUrls urls; + struct IGDdatas data; + char myaddr[64]; + int result = UPNP_GetValidIGD(devices, &urls, &data, myaddr, sizeof myaddr); + if (result <= 0) { + logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] No IGD found"); + freeUPNPDevlist(devices); + return; + } + logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] IGD found: [%d] %s (local address: %s, service type: %s)", result, urls.controlURL, myaddr, data.first.servicetype); + + for (int i = 0; i < listen_sockets; i++) { + if (upnp_tcp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].tcp.fd, "TCP"); + if (upnp_udp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].udp.fd, "UDP"); + } + + FreeUPNPUrls(&urls); + freeUPNPDevlist(devices); +} + +static void *upnp_thread(void *data) { + while (true) { + time_t start = time(NULL); + upnp_refresh(); + + // Make sure we'll stick to the refresh period no matter how long upnp_refresh() takes. + time_t refresh_time = start + upnp_refresh_period; + time_t now = time(NULL); + if (now < refresh_time) sleep(refresh_time - now); + } + + // TODO: we don't have a clean thread shutdown procedure, so we can't remove the mapping. + // this is probably not a concern as long as the UPnP device honors the lease duration, + // but considering how bug-riddled these devices often are, that's a big "if". + return NULL; +} + +void upnp_init(bool tcp, bool udp) { + upnp_tcp = tcp; + upnp_udp = udp; + + get_config_int(lookup_config(config_tree, "UPnPDiscoverWait"), &upnp_discover_wait); + get_config_int(lookup_config(config_tree, "UPnPRefreshPeriod"), &upnp_refresh_period); + + pthread_t thread; + int error = pthread_create(&thread, NULL, upnp_thread, NULL); + if (error) { + logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread: [%d] %s", error, strerror(error)); + } +} diff --git a/src/gcrypt/ecdsagen.c b/src/upnp.h similarity index 57% rename from src/gcrypt/ecdsagen.c rename to src/upnp.h index 2d4912d..dd0531b 100644 --- a/src/gcrypt/ecdsagen.c +++ b/src/upnp.h @@ -1,6 +1,6 @@ /* - ecdsagen.c -- ECDSA key generation and export - Copyright (C) 2011-2013 Guus Sliepen + upnp.h -- UPnP-IGD client + Copyright (C) 2015 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,25 +17,11 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "../system.h" +#ifndef __UPNP_H__ +#define __UPNP_H__ -#include "../ecdsagen.h" -#include "../utils.h" -#include "../xalloc.h" +#include "system.h" -// Generate ECDSA key +extern void upnp_init(bool, bool); -ecdsa_t *ecdsa_generate(void) { - logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented"); - return NULL; -} - -// Write PEM ECDSA keys - -bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) { - return false; -} - -bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) { - return false; -} +#endif diff --git a/src/utils.c b/src/utils.c index 65ba4b9..fadfd05 100644 --- a/src/utils.c +++ b/src/utils.c @@ -158,7 +158,7 @@ int b64encode_urlsafe(const void *src, char *dst, int length) { const char *winerror(int err) { static char buf[1024], *ptr; - ptr = buf + sprintf(buf, "(%d) ", err); + ptr = buf + snprintf(buf, sizeof buf, "(%d) ", err); if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) { @@ -191,6 +191,22 @@ bool check_id(const char *id) { return true; } +bool check_netname(const char *netname, bool strict) { + if(!netname || !*netname || *netname == '.') + return false; + + for(const char *c = netname; *c; c++) { + if(iscntrl(*c)) + return false; + if(*c == '/' || *c == '\\') + return false; + if(strict && strchr(" $%<>:`\"|?*", *c)) + return false; + } + + return true; +} + /* Windows doesn't define HOST_NAME_MAX. */ #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 diff --git a/src/utils.h b/src/utils.h index c3364ce..5c387bd 100644 --- a/src/utils.h +++ b/src/utils.h @@ -51,6 +51,7 @@ extern const char *winerror(int); extern unsigned int bitfield_to_int(const void *bitfield, size_t size); extern bool check_id(const char *); +extern bool check_netname(const char *, bool strict); char *replace_name(const char *name); #endif /* __TINC_UTILS_H__ */ diff --git a/src/version.c b/src/version.c index fc62c8a..325a6f0 100644 --- a/src/version.c +++ b/src/version.c @@ -18,7 +18,14 @@ */ #include "version.h" +#include "version_git.h" +#include "../config.h" /* This file is always rebuilt (even if there are no changes) so that the following is updated */ const char* const BUILD_DATE = __DATE__; const char* const BUILD_TIME = __TIME__; +#ifdef GIT_DESCRIPTION +const char* const BUILD_VERSION = GIT_DESCRIPTION; +#else +const char* const BUILD_VERSION = VERSION; +#endif diff --git a/src/version.h b/src/version.h index d3e4a1f..9cbecb6 100644 --- a/src/version.h +++ b/src/version.h @@ -22,5 +22,6 @@ extern const char* const BUILD_DATE; extern const char* const BUILD_TIME; +extern const char* const BUILD_VERSION; #endif /* __TINC_VERSION_H__ */ diff --git a/systemd/Makefile.am b/systemd/Makefile.am new file mode 100644 index 0000000..a1bfe12 --- /dev/null +++ b/systemd/Makefile.am @@ -0,0 +1,4 @@ +if WITH_SYSTEMD +systemddir = @systemd_path@ +dist_systemd_DATA = tinc.service tinc@.service +endif diff --git a/m4/Makefile.in b/systemd/Makefile.in similarity index 73% rename from m4/Makefile.in rename to systemd/Makefile.in index 4097869..4bc2d27 100644 --- a/m4/Makefile.in +++ b/systemd/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -13,8 +13,19 @@ # PARTICULAR PURPOSE. @SET_MAKE@ + VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -77,18 +88,19 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = m4 -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README +subdir = systemd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_systemd_DATA_DIST) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -112,7 +124,38 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac +am__dist_systemd_DATA_DIST = tinc.service tinc@.service +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(systemddir)" +DATA = $(dist_systemd_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -147,6 +190,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -204,15 +248,18 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -EXTRA_DIST = README *.m4 +@WITH_SYSTEMD_TRUE@systemddir = @systemd_path@ +@WITH_SYSTEMD_TRUE@dist_systemd_DATA = tinc.service tinc@.service all: all-am .SUFFIXES: @@ -225,10 +272,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu systemd/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu m4/Makefile -.PRECIOUS: Makefile + $(AUTOMAKE) --gnu systemd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -246,6 +292,27 @@ $(top_srcdir)/configure: $(am__configure_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): +install-dist_systemdDATA: $(dist_systemd_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_systemd_DATA)'; test -n "$(systemddir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemddir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemddir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemddir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemddir)" || exit $$?; \ + done + +uninstall-dist_systemdDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_systemd_DATA)'; test -n "$(systemddir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemddir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: @@ -285,8 +352,11 @@ distdir: $(DISTFILES) done check-am: all-am check: check-am -all-am: Makefile +all-am: Makefile $(DATA) installdirs: + for dir in "$(DESTDIR)$(systemddir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done install: install-am install-exec: install-exec-am install-data: install-data-am @@ -337,7 +407,7 @@ info: info-am info-am: -install-data-am: +install-data-am: install-dist_systemdDATA install-dvi: install-dvi-am @@ -381,20 +451,23 @@ ps: ps-am ps-am: -uninstall-am: +uninstall-am: uninstall-dist_systemdDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags-am uninstall uninstall-am + install-data-am install-dist_systemdDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-dist_systemdDATA + +.PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/systemd/tinc.service b/systemd/tinc.service new file mode 100644 index 0000000..d911fa7 --- /dev/null +++ b/systemd/tinc.service @@ -0,0 +1,20 @@ +# This is a mostly empty service, but allows commands like stop, start, reload +# to propagate to all tinc@ service instances. + +[Unit] +Description=Tinc VPN +Documentation=info:tinc +Documentation=man:tinc(8) man:tinc.conf(5) +Documentation=http://tinc-vpn.org/docs/ +After=network.target +Wants=network.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/true +ExecReload=/bin/true +WorkingDirectory=/etc/tinc + +[Install] +WantedBy=multi-user.target diff --git a/systemd/tinc@.service b/systemd/tinc@.service new file mode 100644 index 0000000..78ef25b --- /dev/null +++ b/systemd/tinc@.service @@ -0,0 +1,19 @@ +[Unit] +Description=Tinc net %i +Documentation=info:tinc +Documentation=man:tinc(8) man:tinc.conf(5) +Documentation=http://tinc-vpn.org/docs/ +PartOf=tinc.service +ReloadPropagatedFrom=tinc.service + +[Service] +Type=simple +WorkingDirectory=/etc/tinc/%i +ExecStart=/usr/sbin/tincd -n %i -D +ExecReload=/usr/sbin/tinc -n %i reload +Restart=on-failure +RestartSec=5 +TimeoutStopSec=5 + +[Install] +WantedBy=tinc.service diff --git a/test-driver b/test-driver index d306056..8e575b0 100755 --- a/test-driver +++ b/test-driver @@ -3,7 +3,7 @@ scriptversion=2013-07-13.22; # UTC -# Copyright (C) 2011-2013 Free Software Foundation, Inc. +# Copyright (C) 2011-2014 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -106,11 +106,14 @@ trap "st=143; $do_exit" 15 # Test script is run here. "$@" >$log_file 2>&1 estatus=$? + if test $enable_hard_errors = no && test $estatus -eq 99; then - estatus=1 + tweaked_estatus=1 +else + tweaked_estatus=$estatus fi -case $estatus:$expect_failure in +case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; @@ -119,6 +122,12 @@ case $estatus:$expect_failure in *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac +# Report the test outcome and exit status in the logs, so that one can +# know whether the test passed or failed simply by looking at the '.log' +# file, without the need of also peaking into the corresponding '.trs' +# file (automake bug#11814). +echo "$res $test_name (exit status: $estatus)" >>$log_file + # Report outcome to console. echo "${col}${res}${std}: $test_name" diff --git a/test/Makefile.am b/test/Makefile.am index 5457b2f..df8e2c3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -4,6 +4,7 @@ TESTS = \ executables.test \ import-export.test \ invite-join.test \ + invite-tinc-up.test \ ns-ping.test \ ping.test \ sptps-basic.test \ diff --git a/test/Makefile.in b/test/Makefile.in index cdea11e..885674d 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,19 +89,18 @@ build_triplet = @build@ host_triplet = @host@ check_PROGRAMS = pong$(EXEEXT) subdir = test -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(dist_check_SCRIPTS) $(top_srcdir)/depcomp \ - $(top_srcdir)/test-driver ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_check_link_flag.m4 \ $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_check_SCRIPTS) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -111,7 +120,7 @@ AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -355,6 +364,8 @@ am__set_b = \ *) \ b='$*';; \ esac +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ + $(top_srcdir)/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -389,6 +400,7 @@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ +MINIUPNPC_LIBS = @MINIUPNPC_LIBS@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ @@ -446,10 +458,12 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemd_path = @systemd_path@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ @@ -460,6 +474,7 @@ TESTS = \ executables.test \ import-export.test \ invite-join.test \ + invite-tinc-up.test \ ns-ping.test \ ping.test \ sptps-basic.test \ @@ -484,7 +499,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -616,7 +630,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ - else \ + elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ @@ -896,6 +910,8 @@ uninstall-am: mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am +.PRECIOUS: Makefile + clean-local: -for pid in *.test.?/pid; do ../src/tinc --pidfile="$$pid" stop; done diff --git a/test/invite-join.test b/test/invite-join.test index dbe6f8a..c1bd1b8 100755 --- a/test/invite-join.test +++ b/test/invite-join.test @@ -24,7 +24,7 @@ $tinc $c1 invite bar | $tinc $c2 join # Test equivalence of host config files cmp $d1/hosts/foo $d2/hosts/foo -test "`grep ^ECDSAPublicKey $d1/hosts/bar`" = "`grep ^ECDSAPublicKey $d2/hosts/bar`" +test "`grep ^Ed25519PublicKey $d1/hosts/bar`" = "`grep ^Ed25519PublicKey $d2/hosts/bar`" # Test Mode, Broadcast and ConnectTo statements diff --git a/test/invite-tinc-up.test b/test/invite-tinc-up.test new file mode 100755 index 0000000..bc5d45b --- /dev/null +++ b/test/invite-tinc-up.test @@ -0,0 +1,51 @@ +#!/bin/sh + +. ./testlib.sh + +# Initialize one node + +$tinc $c1 <$d1/invitation-created <\$INVITATION_FILE +echo Ifconfig = 93.184.216.34/24 >>\$INVITATION_FILE +echo Route = 2606:2800:220:1::/64 2606:2800:220:1:248:1893:25c8:1946 >>\$INVITATION_FILE +echo Route = 1.2.3.4 1234:: >>\$INVITATION_FILE +$tinc $c1 export >>\$INVITATION_FILE +EOF + +chmod u+x $d1/invitation-created + +$tinc $c1 invite bar | $tinc $c2 --batch join + +# Test equivalence of host config files + +cmp $d1/hosts/foo $d2/hosts/foo +test "`grep ^Ed25519PublicKey $d1/hosts/bar`" = "`grep ^Ed25519PublicKey $d2/hosts/bar`" + +# Check if the tinc-up.invitation file is created and contains the right commands + +test -f $d2/tinc-up.invitation + +fgrep -q "93.184.216.34/24" $d2/tinc-up.invitation +fgrep -q "2606:2800:220:1::/64" $d2/tinc-up.invitation +fgrep -q "2606:2800:220:1:248:1893:25c8:1946" $d2/tinc-up.invitation +fgrep -q "1234::" $d2/tinc-up.invitation && exit 1 + +# Check that no tinc-up is created and that tinc-up.invitation is not executable + +test -x $d2/tinc-up.invitation && exit 1 +test -f $d2/tinc-up && exit 1 + +$tinc $c1 stop diff --git a/test/variables.test b/test/variables.test index 4cf9d5e..5fe6046 100755 --- a/test/variables.test +++ b/test/variables.test @@ -38,7 +38,6 @@ $tinc $c1 add Subnet 2 $tinc $c1 add Subnet 3 test "`$tinc $c1 get Subnet`" = "1 2 -2 3" $tinc $c1 del Subnet 2 test "`$tinc $c1 get Subnet`" = "1 @@ -65,7 +64,6 @@ $tinc $c1 add bar.Subnet 2 $tinc $c1 add bar.Subnet 3 test "`$tinc $c1 get bar.Subnet`" = "1 2 -2 3" $tinc $c1 del bar.Subnet 2 test "`$tinc $c1 get bar.Subnet`" = "1