Import Upstream version 1.1~pre3
This commit is contained in:
parent
02de1cd2f1
commit
34d5939212
136 changed files with 13943 additions and 4867 deletions
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 1998-2010 Ivo Timmermans, Guus Sliepen and others.
|
||||
Copyright (C) 1998-2012 Ivo Timmermans, Guus Sliepen and others.
|
||||
See the AUTHORS file for a complete list.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
9
INSTALL
9
INSTALL
|
@ -1,8 +1,8 @@
|
|||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
|
@ -226,6 +226,11 @@ order to use an ANSI C compiler:
|
|||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
|
|
114
Makefile.in
114
Makefile.in
|
@ -1,9 +1,9 @@
|
|||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -15,6 +15,23 @@
|
|||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
|
@ -42,7 +59,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
|
@ -60,6 +78,11 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
|||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||
|
@ -72,9 +95,11 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
|||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d "$(distdir)" \
|
||||
|| { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr "$(distdir)"; }; }
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
|
@ -103,6 +128,8 @@ am__relativize = \
|
|||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
|
@ -152,6 +179,7 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
|
@ -214,7 +242,7 @@ all: config.h
|
|||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
|
@ -250,10 +278,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
|||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f stamp-h1; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
|
||||
else :; fi
|
||||
@if test ! -f $@; then rm -f stamp-h1; else :; fi
|
||||
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
|
@ -435,13 +461,10 @@ distdir: $(DISTFILES)
|
|||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
$(am__make_dryrun) \
|
||||
|| test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
|
@ -473,7 +496,11 @@ dist-gzip: distdir
|
|||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
|
@ -481,7 +508,7 @@ dist-lzma: distdir
|
|||
$(am__remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
|
@ -512,6 +539,8 @@ distcheck: dist
|
|||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
|
@ -521,7 +550,7 @@ distcheck: dist
|
|||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
chmod -R a-w $(distdir); chmod u+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
|
@ -531,6 +560,7 @@ distcheck: dist
|
|||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
|
@ -559,8 +589,16 @@ distcheck: dist
|
|||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@$(am__cd) '$(distuninstallcheck_dir)' \
|
||||
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
|
@ -591,10 +629,15 @@ install-am: all-am
|
|||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
@ -681,17 +724,18 @@ uninstall-am:
|
|||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
|
||||
dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \
|
||||
distclean distclean-generic distclean-hdr distclean-tags \
|
||||
distcleancheck distdir distuninstallcheck dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
|
||||
pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
|
||||
dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
|
||||
distcheck distclean distclean-generic distclean-hdr \
|
||||
distclean-tags distcleancheck distdir distuninstallcheck dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs installdirs-am \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \
|
||||
uninstall uninstall-am
|
||||
|
||||
|
||||
ChangeLog:
|
||||
|
|
70
NEWS
70
NEWS
|
@ -1,4 +1,28 @@
|
|||
Version 1.1pre2 Juli 17 2011
|
||||
Version 1.1pre3 October 14 2012
|
||||
|
||||
* New experimental protocol:
|
||||
* Uses 521 bit ECDSA keys for authentication.
|
||||
* Uses AES-256-CTR and HMAC-SHA256.
|
||||
* Always provides perfect forward secrecy.
|
||||
* Used for both meta-connections and VPN packets.
|
||||
* VPN packets are encrypted end-to-end.
|
||||
|
||||
* Many improvements to tincctl:
|
||||
* "config" command shows/adds/changes configuration variables.
|
||||
* "export" and "import" commands help exchange configuration files.
|
||||
* "init" command sets up initial configuration files.
|
||||
* "info" command shows details about a node, subnet or address.
|
||||
* "log" command shows live log messages.
|
||||
* Without a command it acts as a shell, with history and TAB completion.
|
||||
* Improved starting/stopping tincd.
|
||||
* Improved graph output.
|
||||
|
||||
* When trying to directly send UDP packets to a node for which multiple
|
||||
addresses are known, all of them are tried.
|
||||
|
||||
* Many small fixes, code cleanups and documentation updates.
|
||||
|
||||
Version 1.1pre2 July 17 2011
|
||||
|
||||
* .cookie files are renamed to .pid files, which are compatible with 1.0.x.
|
||||
|
||||
|
@ -28,6 +52,50 @@ Version 1.1pre1 June 25 2011
|
|||
Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
|
||||
version of tinc.
|
||||
|
||||
Version 1.0.19 June 25 2012
|
||||
|
||||
* Allow :: notation in IPv6 Subnets.
|
||||
|
||||
* Add support for systemd style socket activation.
|
||||
|
||||
* Allow environment variables to be used for the Name option.
|
||||
|
||||
* Add basic support for SOCKS proxies, HTTP proxies, and proxying through an
|
||||
external command.
|
||||
|
||||
Version 1.0.18 March 25 2012
|
||||
|
||||
* Fixed IPv6 in switch mode by turning off DecrementTTL by default.
|
||||
|
||||
* Allow a port number to be specified in BindToAddress, which also allows tinc
|
||||
to listen on multiple ports.
|
||||
|
||||
* Add support for multicast communication with UML/QEMU/KVM.
|
||||
|
||||
Version 1.0.17 March 10 2012
|
||||
|
||||
* The DeviceType option can now be used to select dummy, raw socket, UML and
|
||||
VDE devices without needing to recompile tinc.
|
||||
|
||||
* Allow multiple BindToAddress statements.
|
||||
|
||||
* Decrement TTL value of IPv4 and IPv6 packets.
|
||||
|
||||
* Add LocalDiscovery option allowing tinc to detect peers that are behind the
|
||||
same NAT.
|
||||
|
||||
* Accept Subnets passed with the -o option when StrictSubnets = yes.
|
||||
|
||||
* Disabling old RSA keys when generating new ones now also works properly on
|
||||
Windows.
|
||||
|
||||
Version 1.0.16 July 23 2011
|
||||
|
||||
* Fixed a performance issue with TCP communication under Windows.
|
||||
|
||||
* Fixed code that, during network outages, would cause tinc to exit when it
|
||||
thought two nodes with identical Names were on the VPN.
|
||||
|
||||
Version 1.0.15 June 24 2011
|
||||
|
||||
* Improved logging to file.
|
||||
|
|
88
README
88
README
|
@ -1,7 +1,7 @@
|
|||
This is the README file for tinc version 1.1pre2. Installation
|
||||
This is the README file for tinc version 1.1pre3. Installation
|
||||
instructions may be found in the INSTALL file.
|
||||
|
||||
tinc is Copyright (C) 1998-2011 by:
|
||||
tinc is Copyright (C) 1998-2012 by:
|
||||
|
||||
Ivo Timmermans,
|
||||
Guus Sliepen <guus@tinc-vpn.org>,
|
||||
|
@ -29,82 +29,66 @@ protocol is not fixed yet.
|
|||
Security statement
|
||||
------------------
|
||||
|
||||
This version uses an experimental and unfinished cryptographic protocol. Use
|
||||
it at your own risk.
|
||||
This version uses an experimental and unfinished cryptographic protocol. Use it
|
||||
at your own risk.
|
||||
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
Version 1.1pre2 is compatible with 1.0pre8, 1.0 and later, but not with older
|
||||
Version 1.1pre3 is compatible with 1.0pre8, 1.0 and later, but not with older
|
||||
versions of tinc.
|
||||
|
||||
When the ExperimentalProtocol option is used, tinc is still compatible with
|
||||
1.0.X and 1.1pre2 itself, but not with any other 1.1preX version.
|
||||
1.0.X and 1.1pre3 itself, but not with any other 1.1preX version.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Either OpenSSL (http://www.openssl.org/) or libgcrypt
|
||||
(http://www.gnupg.org/download/#libgcrypt).
|
||||
|
||||
The zlib library is used for optional compression. You can find it at
|
||||
http://www.gzip.org/zlib/.
|
||||
|
||||
The lzo library is also used for optional compression. You can find it at
|
||||
http://www.oberhumer.com/opensource/lzo/.
|
||||
|
||||
Since 1.1, the libevent library is used for the main event loop. You can find
|
||||
it at http://monkey.org/~provos/libevent/.
|
||||
|
||||
In order to compile tinc, you will need a GNU C compiler environment. Please
|
||||
ensure you have the latest stable versions of all the required libraries.
|
||||
ensure you have the latest stable versions of all the required libraries:
|
||||
|
||||
- OpenSSL (http://www.openssl.org/) version 1.0.0 or later.
|
||||
- Libevent (http://monkey.org/~provos/libevent/)
|
||||
|
||||
The following libraries are used by default, but can be disabled if necessary:
|
||||
|
||||
- zlib (http://www.gzip.org/zlib/)
|
||||
- lzo (http://www.oberhumer.com/opensource/lzo/)
|
||||
- ncurses (http://invisible-island.net/ncurses/)
|
||||
- readline (ftp://ftp.gnu.org/pub/gnu/readline/)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
This version of tinc supports multiple virtual networks at once. To
|
||||
use this feature, you may supply a netname via the -n or --net
|
||||
options. The standard locations for the config files will then be
|
||||
/etc/tinc/<net>/.
|
||||
Tinc is a peer-to-peer VPN daemon that supports VPNs with an arbitrary number
|
||||
of nodes. Instead of configuring tunnels, you give tinc the location and
|
||||
public key of a few nodes in the VPN. After making the initial connections to
|
||||
those nodes, tinc will learn about all other nodes on the VPN, and will make
|
||||
connections automatically. When direct connections are not possible, data will
|
||||
be forwarded by intermediate nodes.
|
||||
|
||||
tincd regenerates its encryption key pairs. It does this on the first
|
||||
activity after the keys have expired. This period is adjustable in the
|
||||
configuration file, and the default time is 3600 seconds (one hour).
|
||||
By default, nodes authenticate each other using 2048 bit RSA (or 521 bit
|
||||
ECDSA*) keys. Traffic is encrypted using Blowfish in CBC mode (or AES-256 in
|
||||
CTR mode*), authenticated using HMAC-SHA1 (or HMAC-SHA-256*), and is protected
|
||||
against replay attacks.
|
||||
|
||||
This version supports multiple subnets at once. They are also sorted
|
||||
on subnet mask size. This means that it is possible to have
|
||||
overlapping subnets on the VPN, as long as their subnet mask sizes
|
||||
differ.
|
||||
*) When using the ExperimentalProtocol option.
|
||||
|
||||
Since pre5, tinc can operate in several routing modes. The default mode,
|
||||
"router", works exactly like the older version, and uses Subnet lines to
|
||||
determine the destination of packets. The other two modes, "switch" and "hub",
|
||||
allow the tinc daemons to work together like a single network switch or hub.
|
||||
This is useful for bridging networks. The latter modes only work properly on
|
||||
Linux, FreeBSD and Windows.
|
||||
Tinc fully supports IPv6.
|
||||
|
||||
The algorithms used for encryption and generating message authentication codes
|
||||
can now be changed in the configuration files. All cipher and digest algorithms
|
||||
supported by OpenSSL can be used. Useful ciphers are "blowfish" (default),
|
||||
"bf-ofb", "des", "des3", etcetera. Useful digests are "sha1" (default), "md5",
|
||||
etcetera.
|
||||
|
||||
Support for routing IPv6 packets has been added. Just add Subnet lines with
|
||||
IPv6 addresses (without using :: abbreviations) and use ifconfig or ip (from
|
||||
the iproute package) to give the virtual network interface corresponding IPv6
|
||||
addresses. tinc does not provide autoconfiguration for IPv6 hosts, if you need
|
||||
it use radvd or zebra.
|
||||
|
||||
It is also possible to make tunnels to other tinc daemons over IPv6 networks,
|
||||
if the operating system supports IPv6. tinc will automatically use both IPv6
|
||||
and IPv4 when available, but this can be changed by adding the option
|
||||
"AddressFamily = ipv4" or "AddressFamily = ipv6" to the tinc.conf file.
|
||||
Tinc can operate in several routing modes. In the default mode, "router", every
|
||||
node is associated with one or more IPv4 and/or IPv6 Subnets. The other two
|
||||
modes, "switch" and "hub", let the tinc daemons work together to form a virtual
|
||||
Ethernet network switch or hub.
|
||||
|
||||
Normally, when started tinc will detach and run in the background. In a native
|
||||
Windows environment this means tinc will intall itself as a service, which will
|
||||
restart after reboots. To prevent tinc from detaching or running as a service,
|
||||
use the -D option.
|
||||
|
||||
The status of the VPN can be queried using the "tincctl" tool, which connects
|
||||
to a running tinc daemon via a control connection. The same tool also makes it
|
||||
easy to start and stop tinc, and to change its configuration.
|
||||
|
|
7
THANKS
7
THANKS
|
@ -3,12 +3,14 @@ We would like to thank the following people for their contributions to tinc:
|
|||
* Alexander Reil and Gemeinde Berg
|
||||
* Allesandro Gatti
|
||||
* Andreas van Cranenburgh
|
||||
* Anthony G. Basile
|
||||
* Armijn Hemel
|
||||
* Brandon Black
|
||||
* Cris van Pelt
|
||||
* Delf Eldkraft
|
||||
* dnk
|
||||
* Enrique Zanardi
|
||||
* Erik Tews
|
||||
* Flynn Marquardt
|
||||
* Grzegorz Dymarek
|
||||
* Hans Bayle
|
||||
|
@ -26,13 +28,17 @@ We would like to thank the following people for their contributions to tinc:
|
|||
* Mark Glines
|
||||
* Markus Goetz
|
||||
* Martin Kihlgren
|
||||
* Martin Schürrer
|
||||
* Matias Carrasco
|
||||
* Max Rijevski
|
||||
* Menno Smits
|
||||
* Mesar Hameed
|
||||
* Michael Tokarev
|
||||
* Miles Nordin
|
||||
* Nick Hibma
|
||||
* Nick Patavalis
|
||||
* Paul Littlefield
|
||||
* Philipp Babel
|
||||
* Robert van der Meulen
|
||||
* Rumko
|
||||
* Scott Lamb
|
||||
|
@ -40,6 +46,7 @@ We would like to thank the following people for their contributions to tinc:
|
|||
* Teemu Kiviniemi
|
||||
* Timothy Redaelli
|
||||
* Tonnerre Lombard
|
||||
* Vil Brekin
|
||||
* Wessel Dankers
|
||||
* Wouter van Heyst
|
||||
|
||||
|
|
79
aclocal.m4
vendored
79
aclocal.m4
vendored
|
@ -1,7 +1,8 @@
|
|||
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -13,8 +14,8 @@
|
|||
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
|
||||
[m4_warning([this file was generated for autoconf 2.68.
|
||||
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
|
||||
[m4_warning([this file was generated for autoconf 2.69.
|
||||
You have another version of autoconf. It may work, but is not guaranteed to.
|
||||
If you have problems, you may need to regenerate the build system entirely.
|
||||
To do so, use the procedure documented by the package, typically `autoreconf'.])])
|
||||
|
@ -143,12 +144,15 @@ AC_DEFUN([AM_PATH_LIBGCRYPT],
|
|||
AC_SUBST(LIBGCRYPT_LIBS)
|
||||
])
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
|
@ -158,7 +162,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
|
|||
[am__api_version='1.11'
|
||||
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
||||
dnl require some minimum version. Point them to the right macro.
|
||||
m4_if([$1], [1.11.1], [],
|
||||
m4_if([$1], [1.11.6], [],
|
||||
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||
])
|
||||
|
||||
|
@ -174,19 +178,21 @@ m4_define([_AM_AUTOCONF_VERSION], [])
|
|||
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.11.1])dnl
|
||||
[AM_AUTOMAKE_VERSION([1.11.6])dnl
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
|
@ -268,14 +274,14 @@ AC_CONFIG_COMMANDS_PRE(
|
|||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
|
||||
# 2010, 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 10
|
||||
# serial 12
|
||||
|
||||
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
|
||||
# written in clear, in which case automake, when reading aclocal.m4,
|
||||
|
@ -315,6 +321,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
|
|||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
|
@ -379,7 +386,7 @@ AC_CACHE_CHECK([dependency style of $depcc],
|
|||
break
|
||||
fi
|
||||
;;
|
||||
msvisualcpp | msvcmsys)
|
||||
msvc7 | msvc7msys | msvisualcpp | msvcmsys)
|
||||
# This compiler won't grok `-c -o', but also, the minuso test has
|
||||
# not run yet. These depmodes are late enough in the game, and
|
||||
# so weak that their functioning should not be impacted.
|
||||
|
@ -444,10 +451,13 @@ AC_DEFUN([AM_DEP_TRACK],
|
|||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
am__nodep='_no'
|
||||
fi
|
||||
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
AC_SUBST([AMDEPBACKSLASH])dnl
|
||||
_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
|
||||
AC_SUBST([am__nodep])dnl
|
||||
_AM_SUBST_NOTMAKE([am__nodep])dnl
|
||||
])
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
@ -669,12 +679,15 @@ for _am_header in $config_headers :; do
|
|||
done
|
||||
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
|
@ -714,8 +727,8 @@ AC_SUBST([am__leading_dot])])
|
|||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
|
||||
# Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
|
||||
# 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -735,7 +748,7 @@ AC_DEFUN([AM_MAINTAINER_MODE],
|
|||
[disable], [m4_define([am_maintainer_other], [enable])],
|
||||
[m4_define([am_maintainer_other], [enable])
|
||||
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
|
||||
AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
|
||||
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
||||
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
|
||||
AC_ARG_ENABLE([maintainer-mode],
|
||||
[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
|
||||
|
@ -846,12 +859,15 @@ else
|
|||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
|
||||
# Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check for `mkdir -p'.
|
||||
|
@ -874,13 +890,14 @@ esac
|
|||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
|
||||
# Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
# serial 5
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
|
@ -888,13 +905,13 @@ AC_DEFUN([_AM_MANGLE_OPTION],
|
|||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# ------------------------------
|
||||
# --------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ----------------------------------
|
||||
# ------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
@ -970,12 +987,14 @@ Check your system clock])
|
|||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 1
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
|
@ -998,13 +1017,13 @@ fi
|
|||
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
# serial 3
|
||||
|
||||
# _AM_SUBST_NOTMAKE(VARIABLE)
|
||||
# ---------------------------
|
||||
|
@ -1013,13 +1032,13 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
|||
AC_DEFUN([_AM_SUBST_NOTMAKE])
|
||||
|
||||
# AM_SUBST_NOTMAKE(VARIABLE)
|
||||
# ---------------------------
|
||||
# --------------------------
|
||||
# Public sister of _AM_SUBST_NOTMAKE.
|
||||
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -1041,10 +1060,11 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
|||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility.
|
||||
AM_MISSING_PROG([AMTAR], [tar])
|
||||
[# Always define AMTAR for backward compatibility. Yes, it's still used
|
||||
# in the wild :-( We should find a proper way to deprecate it ...
|
||||
AC_SUBST([AMTAR], ['$${TAR-tar}'])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
|
||||
[am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
|
@ -1118,4 +1138,5 @@ m4_include([m4/curses.m4])
|
|||
m4_include([m4/libevent.m4])
|
||||
m4_include([m4/lzo.m4])
|
||||
m4_include([m4/openssl.m4])
|
||||
m4_include([m4/readline.m4])
|
||||
m4_include([m4/zlib.m4])
|
||||
|
|
49
config.guess
vendored
49
config.guess
vendored
|
@ -2,9 +2,9 @@
|
|||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
# 2011 Free Software Foundation, Inc.
|
||||
# 2011, 2012 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2011-05-11'
|
||||
timestamp='2012-02-10'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
|
@ -17,9 +17,7 @@ timestamp='2011-05-11'
|
|||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
|
@ -57,8 +55,8 @@ GNU config.guess ($timestamp)
|
|||
|
||||
Originally written by Per Bothner.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
|
||||
Software Foundation, Inc.
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
|
@ -145,7 +143,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
|||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
*:NetBSD:*:*)
|
||||
# NetBSD (nbsd) targets should (where applicable) match one or
|
||||
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
|
||||
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
|
||||
# switched to ELF, *-*-netbsd* would select the old
|
||||
# object file format. This provides both forward
|
||||
|
@ -792,13 +790,12 @@ EOF
|
|||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:FreeBSD:*:*)
|
||||
case ${UNAME_MACHINE} in
|
||||
pc98)
|
||||
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
UNAME_PROCESSOR=`/usr/bin/uname -p`
|
||||
case ${UNAME_PROCESSOR} in
|
||||
amd64)
|
||||
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
*)
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
|
||||
esac
|
||||
exit ;;
|
||||
i*:CYGWIN*:*)
|
||||
|
@ -807,6 +804,9 @@ EOF
|
|||
*:MINGW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw32
|
||||
exit ;;
|
||||
i*:MSYS*:*)
|
||||
echo ${UNAME_MACHINE}-pc-msys
|
||||
exit ;;
|
||||
i*:windows32*:*)
|
||||
# uname -m includes "-pc" on this system.
|
||||
echo ${UNAME_MACHINE}-mingw32
|
||||
|
@ -861,6 +861,13 @@ EOF
|
|||
i*86:Minix:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-minix
|
||||
exit ;;
|
||||
aarch64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
alpha:Linux:*:*)
|
||||
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
|
||||
EV5) UNAME_MACHINE=alphaev5 ;;
|
||||
|
@ -895,13 +902,16 @@ EOF
|
|||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo cris-axis-linux-gnu
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo crisv32-axis-linux-gnu
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo frv-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
hexagon:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
LIBC=gnu
|
||||
|
@ -943,7 +953,7 @@ EOF
|
|||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
;;
|
||||
or32:Linux:*:*)
|
||||
echo or32-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
padre:Linux:*:*)
|
||||
echo sparc-unknown-linux-gnu
|
||||
|
@ -978,13 +988,13 @@ EOF
|
|||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
tile*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-tilera-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
vax:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-dec-linux-gnu
|
||||
exit ;;
|
||||
x86_64:Linux:*:*)
|
||||
echo x86_64-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit ;;
|
||||
xtensa*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
|
@ -1315,6 +1325,9 @@ EOF
|
|||
i*86:AROS:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-aros
|
||||
exit ;;
|
||||
x86_64:VMkernel:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-esx
|
||||
exit ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
|
|
33
config.h.in
33
config.h.in
|
@ -6,6 +6,12 @@
|
|||
/* Support for tunemu */
|
||||
#undef ENABLE_TUNEMU
|
||||
|
||||
/* Support for UML */
|
||||
#undef ENABLE_UML
|
||||
|
||||
/* Support for VDE */
|
||||
#undef ENABLE_VDE
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
|
@ -52,6 +58,12 @@
|
|||
/* DragonFly */
|
||||
#undef HAVE_DRAGONFLY
|
||||
|
||||
/* Define to 1 if you have the `ECDH_compute_key' function. */
|
||||
#undef HAVE_ECDH_COMPUTE_KEY
|
||||
|
||||
/* Define to 1 if you have the `ECDSA_verify' function. */
|
||||
#undef HAVE_ECDSA_VERIFY
|
||||
|
||||
/* Define to 1 if you have the <event.h> header file. */
|
||||
#undef HAVE_EVENT_H
|
||||
|
||||
|
@ -88,6 +100,9 @@
|
|||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the <libvdeplug_dyn.h> header file. */
|
||||
#undef HAVE_LIBVDEPLUG_DYN_H
|
||||
|
||||
/* Linux */
|
||||
#undef HAVE_LINUX
|
||||
|
||||
|
@ -148,6 +163,9 @@
|
|||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#undef HAVE_NETINET_TCP_H
|
||||
|
||||
/* Define to 1 if you have the <netpacket/packet.h> header file. */
|
||||
#undef HAVE_NETPACKET_PACKET_H
|
||||
|
||||
/* Define to 1 if you have the <net/ethernet.h> header file. */
|
||||
#undef HAVE_NET_ETHERNET_H
|
||||
|
||||
|
@ -175,6 +193,12 @@
|
|||
/* OpenBSD */
|
||||
#undef HAVE_OPENBSD
|
||||
|
||||
/* Define to 1 if you have the <openssl/ecdh.h> header file. */
|
||||
#undef HAVE_OPENSSL_ECDH_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/ec.h> header file. */
|
||||
#undef HAVE_OPENSSL_EC_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/engine.h> header file. */
|
||||
#undef HAVE_OPENSSL_ENGINE_H
|
||||
|
||||
|
@ -205,6 +229,15 @@
|
|||
/* Define to 1 if you have the `RAND_pseudo_bytes' function. */
|
||||
#undef HAVE_RAND_PSEUDO_BYTES
|
||||
|
||||
/* have readline support */
|
||||
#undef HAVE_READLINE
|
||||
|
||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
||||
#undef HAVE_READLINE_HISTORY_H
|
||||
|
||||
/* Define to 1 if you have the <readline/readline.h> header file. */
|
||||
#undef HAVE_READLINE_READLINE_H
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
|
|
74
config.sub
vendored
74
config.sub
vendored
|
@ -2,9 +2,9 @@
|
|||
# Configuration validation subroutine script.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
# 2011 Free Software Foundation, Inc.
|
||||
# 2011, 2012 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2011-03-23'
|
||||
timestamp='2012-04-18'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
|
@ -21,9 +21,7 @@ timestamp='2011-03-23'
|
|||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
|
@ -76,8 +74,8 @@ version="\
|
|||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
|
||||
Software Foundation, Inc.
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
|
@ -132,6 +130,10 @@ case $maybe_os in
|
|||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
android-linux)
|
||||
os=-linux-android
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
|
||||
;;
|
||||
*)
|
||||
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
|
||||
if [ $basic_machine != $1 ]
|
||||
|
@ -223,6 +225,12 @@ case $os in
|
|||
-isc*)
|
||||
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
|
||||
;;
|
||||
-lynx*178)
|
||||
os=-lynxos178
|
||||
;;
|
||||
-lynx*5)
|
||||
os=-lynxos5
|
||||
;;
|
||||
-lynx*)
|
||||
os=-lynxos
|
||||
;;
|
||||
|
@ -247,17 +255,22 @@ case $basic_machine in
|
|||
# Some are omitted here because they have special meanings below.
|
||||
1750a | 580 \
|
||||
| a29k \
|
||||
| aarch64 | aarch64_be \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
|
||||
| be32 | be64 \
|
||||
| bfin \
|
||||
| c4x | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| epiphany \
|
||||
| fido | fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| hexagon \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k | iq2000 \
|
||||
| le32 | le64 \
|
||||
| lm32 \
|
||||
| m32c | m32r | m32rle | m68000 | m68k | m88k \
|
||||
| maxq | mb | microblaze | mcore | mep | metag \
|
||||
|
@ -291,7 +304,7 @@ case $basic_machine in
|
|||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle \
|
||||
| pyramid \
|
||||
| rx \
|
||||
| rl78 | rx \
|
||||
| score \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
|
@ -300,7 +313,7 @@ case $basic_machine in
|
|||
| spu \
|
||||
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
|
||||
| ubicom32 \
|
||||
| v850 | v850e \
|
||||
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
|
||||
| we32k \
|
||||
| x86 | xc16x | xstormy16 | xtensa \
|
||||
| z8k | z80)
|
||||
|
@ -315,8 +328,7 @@ case $basic_machine in
|
|||
c6x)
|
||||
basic_machine=tic6x-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | picochip)
|
||||
# Motorola 68HC11/12.
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
|
@ -329,7 +341,10 @@ case $basic_machine in
|
|||
strongarm | thumb | xscale)
|
||||
basic_machine=arm-unknown
|
||||
;;
|
||||
|
||||
xgate)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
xscaleeb)
|
||||
basic_machine=armeb-unknown
|
||||
;;
|
||||
|
@ -352,11 +367,13 @@ case $basic_machine in
|
|||
# Recognize the basic CPU types with company name.
|
||||
580-* \
|
||||
| a29k-* \
|
||||
| aarch64-* | aarch64_be-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* | avr32-* \
|
||||
| be32-* | be64-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* \
|
||||
| clipper-* | craynv-* | cydra-* \
|
||||
|
@ -365,8 +382,10 @@ case $basic_machine in
|
|||
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| hexagon-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| le32-* | le64-* \
|
||||
| lm32-* \
|
||||
| m32c-* | m32r-* | m32rle-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
|
@ -400,7 +419,7 @@ case $basic_machine in
|
|||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
|
||||
| pyramid-* \
|
||||
| romp-* | rs6000-* | rx-* \
|
||||
| rl78-* | romp-* | rs6000-* | rx-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
|
||||
|
@ -408,10 +427,11 @@ case $basic_machine in
|
|||
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
|
||||
| tahoe-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tile-* | tilegx-* \
|
||||
| tile*-* \
|
||||
| tron-* \
|
||||
| ubicom32-* \
|
||||
| v850-* | v850e-* | vax-* \
|
||||
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
|
||||
| vax-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* \
|
||||
| xstormy16-* | xtensa*-* \
|
||||
|
@ -711,7 +731,6 @@ case $basic_machine in
|
|||
i370-ibm* | ibm*)
|
||||
basic_machine=i370-ibm
|
||||
;;
|
||||
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
||||
i*86v32)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-sysv32
|
||||
|
@ -808,10 +827,18 @@ case $basic_machine in
|
|||
ms1-*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
|
||||
;;
|
||||
msys)
|
||||
basic_machine=i386-pc
|
||||
os=-msys
|
||||
;;
|
||||
mvs)
|
||||
basic_machine=i370-ibm
|
||||
os=-mvs
|
||||
;;
|
||||
nacl)
|
||||
basic_machine=le32-unknown
|
||||
os=-nacl
|
||||
;;
|
||||
ncr3000)
|
||||
basic_machine=i486-ncr
|
||||
os=-sysv4
|
||||
|
@ -1120,13 +1147,8 @@ case $basic_machine in
|
|||
basic_machine=t90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
# This must be matched before tile*.
|
||||
tilegx*)
|
||||
basic_machine=tilegx-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
tile*)
|
||||
basic_machine=tile-unknown
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
tx39)
|
||||
|
@ -1336,7 +1358,7 @@ case $os in
|
|||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* | -cegcc* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
|
@ -1521,6 +1543,9 @@ case $basic_machine in
|
|||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
hexagon-*)
|
||||
os=-elf
|
||||
;;
|
||||
tic54x-*)
|
||||
os=-coff
|
||||
;;
|
||||
|
@ -1548,9 +1573,6 @@ case $basic_machine in
|
|||
;;
|
||||
m68000-sun)
|
||||
os=-sunos3
|
||||
# This also exists in the configure program, but was not the
|
||||
# default.
|
||||
# os=-sunos4
|
||||
;;
|
||||
m68*-cisco)
|
||||
os=-aout
|
||||
|
|
459
configure
vendored
459
configure
vendored
|
@ -1,11 +1,9 @@
|
|||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.68.
|
||||
# Generated by GNU Autoconf 2.69.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
#
|
||||
#
|
||||
# This configure script is free software; the Free Software Foundation
|
||||
|
@ -134,6 +132,31 @@ export LANGUAGE
|
|||
# CDPATH.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
# Use a proper internal environment variable to ensure we don't fall
|
||||
# into an infinite loop, continuously re-executing ourselves.
|
||||
if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
|
||||
_as_can_reexec=no; export _as_can_reexec;
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
# Preserve -v and -x to the replacement shell.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
case $- in # ((((
|
||||
*v*x* | *x*v* ) as_opts=-vx ;;
|
||||
*v* ) as_opts=-v ;;
|
||||
*x* ) as_opts=-x ;;
|
||||
* ) as_opts= ;;
|
||||
esac
|
||||
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
|
||||
# Admittedly, this is quite paranoid, since all the known shells bail
|
||||
# out after a failed `exec'.
|
||||
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
|
||||
as_fn_exit 255
|
||||
fi
|
||||
# We don't want this to propagate to other subprocesses.
|
||||
{ _as_can_reexec=; unset _as_can_reexec;}
|
||||
if test "x$CONFIG_SHELL" = x; then
|
||||
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
|
||||
emulate sh
|
||||
|
@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
|
|||
else
|
||||
exitcode=1; echo positional parameters were not saved.
|
||||
fi
|
||||
test x\$exitcode = x0 || exit 1"
|
||||
test x\$exitcode = x0 || exit 1
|
||||
test -x / || exit 1"
|
||||
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
|
||||
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
|
||||
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
|
||||
|
@ -212,21 +236,25 @@ IFS=$as_save_IFS
|
|||
|
||||
|
||||
if test "x$CONFIG_SHELL" != x; then :
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
# Preserve -v and -x to the replacement shell.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
export CONFIG_SHELL
|
||||
case $- in # ((((
|
||||
# We cannot yet assume a decent shell, so we have to provide a
|
||||
# neutralization value for shells without unset; and this also
|
||||
# works around shells that cannot unset nonexistent variables.
|
||||
# Preserve -v and -x to the replacement shell.
|
||||
BASH_ENV=/dev/null
|
||||
ENV=/dev/null
|
||||
(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
|
||||
case $- in # ((((
|
||||
*v*x* | *x*v* ) as_opts=-vx ;;
|
||||
*v* ) as_opts=-v ;;
|
||||
*x* ) as_opts=-x ;;
|
||||
* ) as_opts= ;;
|
||||
esac
|
||||
exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
|
||||
esac
|
||||
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
|
||||
# Admittedly, this is quite paranoid, since all the known shells bail
|
||||
# out after a failed `exec'.
|
||||
$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
|
||||
exit 255
|
||||
fi
|
||||
|
||||
if test x$as_have_required = xno; then :
|
||||
|
@ -328,6 +356,14 @@ $as_echo X"$as_dir" |
|
|||
|
||||
|
||||
} # as_fn_mkdir_p
|
||||
|
||||
# as_fn_executable_p FILE
|
||||
# -----------------------
|
||||
# Test if FILE is an executable regular file.
|
||||
as_fn_executable_p ()
|
||||
{
|
||||
test -f "$1" && test -x "$1"
|
||||
} # as_fn_executable_p
|
||||
# as_fn_append VAR VALUE
|
||||
# ----------------------
|
||||
# Append the text in VALUE to the end of the definition contained in VAR. Take
|
||||
|
@ -449,6 +485,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
|
|||
chmod +x "$as_me.lineno" ||
|
||||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
|
||||
|
||||
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
|
||||
# already done that, so ensure we don't try to do so again and fall
|
||||
# in an infinite loop. This has already happened in practice.
|
||||
_as_can_reexec=no; export _as_can_reexec
|
||||
# Don't try to exec as it changes $[0], causing all sort of problems
|
||||
# (the dirname of $[0] is not the place where we might find the
|
||||
# original and so on. Autoconf is especially sensitive to this).
|
||||
|
@ -483,16 +523,16 @@ if (echo >conf$$.file) 2>/dev/null; then
|
|||
# ... but there are two gotchas:
|
||||
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
|
||||
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
|
||||
# In both cases, we have to default to `cp -p'.
|
||||
# In both cases, we have to default to `cp -pR'.
|
||||
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
elif ln conf$$.file conf$$ 2>/dev/null; then
|
||||
as_ln_s=ln
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
|
||||
rmdir conf$$.dir 2>/dev/null
|
||||
|
@ -504,28 +544,8 @@ else
|
|||
as_mkdir_p=false
|
||||
fi
|
||||
|
||||
if test -x / >/dev/null 2>&1; then
|
||||
as_test_x='test -x'
|
||||
else
|
||||
if ls -dL / >/dev/null 2>&1; then
|
||||
as_ls_L_option=L
|
||||
else
|
||||
as_ls_L_option=
|
||||
fi
|
||||
as_test_x='
|
||||
eval sh -c '\''
|
||||
if test -d "$1"; then
|
||||
test -d "$1/.";
|
||||
else
|
||||
case $1 in #(
|
||||
-*)set "./$1";;
|
||||
esac;
|
||||
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
|
||||
???[sx]*):;;*)false;;esac;fi
|
||||
'\'' sh
|
||||
'
|
||||
fi
|
||||
as_executable_p=$as_test_x
|
||||
as_test_x='test -x'
|
||||
as_executable_p=as_fn_executable_p
|
||||
|
||||
# Sed expression to map a string onto a valid CPP name.
|
||||
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
|
@ -607,9 +627,14 @@ INCLUDES
|
|||
LIBGCRYPT_LIBS
|
||||
LIBGCRYPT_CFLAGS
|
||||
LIBGCRYPT_CONFIG
|
||||
READLINE_LIBS
|
||||
CURSES_LIBS
|
||||
TUNEMU_FALSE
|
||||
TUNEMU_TRUE
|
||||
VDE_FALSE
|
||||
VDE_TRUE
|
||||
UML_FALSE
|
||||
UML_TRUE
|
||||
host_os
|
||||
host_vendor
|
||||
host_cpu
|
||||
|
@ -626,6 +651,7 @@ MAINTAINER_MODE_TRUE
|
|||
am__fastdepCC_FALSE
|
||||
am__fastdepCC_TRUE
|
||||
CCDEPMODE
|
||||
am__nodep
|
||||
AMDEPBACKSLASH
|
||||
AMDEP_FALSE
|
||||
AMDEP_TRUE
|
||||
|
@ -708,6 +734,8 @@ ac_user_opts='
|
|||
enable_option_checking
|
||||
enable_dependency_tracking
|
||||
enable_maintainer_mode
|
||||
enable_uml
|
||||
enable_vde
|
||||
enable_tunemu
|
||||
with_windows2000
|
||||
with_libgcrypt
|
||||
|
@ -715,6 +743,10 @@ enable_curses
|
|||
with_curses
|
||||
with_curses_include
|
||||
with_curses_lib
|
||||
enable_readline
|
||||
with_readline
|
||||
with_readline_include
|
||||
with_readline_lib
|
||||
with_libevent
|
||||
with_libevent_include
|
||||
with_libevent_lib
|
||||
|
@ -1196,8 +1228,6 @@ target=$target_alias
|
|||
if test "x$host_alias" != x; then
|
||||
if test "x$build_alias" = x; then
|
||||
cross_compiling=maybe
|
||||
$as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
|
||||
If a cross compiler is detected then cross compile mode will be used" >&2
|
||||
elif test "x$build_alias" != "x$host_alias"; then
|
||||
cross_compiling=yes
|
||||
fi
|
||||
|
@ -1363,23 +1393,30 @@ Optional Features:
|
|||
--enable-dependency-tracking do not reject slow dependency extractors
|
||||
--enable-maintainer-mode enable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer
|
||||
--enable-tunemu enable support for the tunemu driver
|
||||
--disable-uml enable support for User Mode Linux
|
||||
--disable-vde enable support for Virtual Distributed Ethernet
|
||||
--disable-tunemu enable support for the tunemu driver
|
||||
--disable-curses disable curses support
|
||||
--disable-readline disable readline support
|
||||
--disable-zlib disable zlib compression support
|
||||
--disable-lzo disable lzo compression support
|
||||
--enable-jumbograms enable support for jumbograms (packets up to 9000
|
||||
--disable-jumbograms enable support for jumbograms (packets up to 9000
|
||||
bytes)
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--with-windows2000 compile with support for Windows 2000. This disables
|
||||
--without-windows2000 compile with support for Windows 2000. This disables
|
||||
support for tunneling over existing IPv6 networks.
|
||||
--with-libgcrypt enable use of libgcrypt instead of OpenSSL]
|
||||
--with-curses=DIR curses base directory, or:
|
||||
--with-curses-include=DIR
|
||||
curses headers directory
|
||||
--with-curses-lib=DIR curses library directory
|
||||
--with-readline=DIR readline base directory, or:
|
||||
--with-readline-include=DIR
|
||||
readline headers directory
|
||||
--with-readline-lib=DIR readline library directory
|
||||
--with-libevent=DIR libevent base directory, or:
|
||||
--with-libevent-include=DIR
|
||||
libevent headers directory
|
||||
|
@ -1475,9 +1512,9 @@ test -n "$ac_init_help" && exit $ac_status
|
|||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
configure
|
||||
generated by GNU Autoconf 2.68
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This configure script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it.
|
||||
_ACEOF
|
||||
|
@ -1804,7 +1841,7 @@ $as_echo "$ac_try_echo"; } >&5
|
|||
test ! -s conftest.err
|
||||
} && test -s conftest$ac_exeext && {
|
||||
test "$cross_compiling" = yes ||
|
||||
$as_test_x conftest$ac_exeext
|
||||
test -x conftest$ac_exeext
|
||||
}; then :
|
||||
ac_retval=0
|
||||
else
|
||||
|
@ -1940,7 +1977,7 @@ This file contains any messages produced by compilers while
|
|||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by $as_me, which was
|
||||
generated by GNU Autoconf 2.68. Invocation command line was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
|
||||
|
@ -2310,7 +2347,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_CC="${ac_tool_prefix}gcc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -2350,7 +2387,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_CC="gcc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -2403,7 +2440,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_CC="${ac_tool_prefix}cc"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -2444,7 +2481,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
|
||||
ac_prog_rejected=yes
|
||||
continue
|
||||
|
@ -2502,7 +2539,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -2546,7 +2583,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_CC="$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -2992,8 +3029,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|||
/* end confdefs.h. */
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
struct stat;
|
||||
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
|
||||
struct buf { int x; };
|
||||
FILE * (*rcsopen) (struct buf *, struct stat *, int);
|
||||
|
@ -3233,7 +3269,7 @@ do
|
|||
for ac_prog in grep ggrep; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
|
||||
{ test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
|
||||
as_fn_executable_p "$ac_path_GREP" || continue
|
||||
# Check for GNU ac_path_GREP and select it if it is found.
|
||||
# Check for GNU $ac_path_GREP
|
||||
case `"$ac_path_GREP" --version 2>&1` in
|
||||
|
@ -3299,7 +3335,7 @@ do
|
|||
for ac_prog in egrep; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
|
||||
{ test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
|
||||
as_fn_executable_p "$ac_path_EGREP" || continue
|
||||
# Check for GNU ac_path_EGREP and select it if it is found.
|
||||
# Check for GNU $ac_path_EGREP
|
||||
case `"$ac_path_EGREP" --version 2>&1` in
|
||||
|
@ -3606,7 +3642,7 @@ case $as_dir/ in #((
|
|||
# by default.
|
||||
for ac_prog in ginstall scoinst install; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
|
||||
if test $ac_prog = install &&
|
||||
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
|
||||
# AIX install. It has an incompatible calling convention.
|
||||
|
@ -3775,7 +3811,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -3815,7 +3851,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_STRIP="strip"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -3866,7 +3902,7 @@ do
|
|||
test -z "$as_dir" && as_dir=.
|
||||
for ac_prog in mkdir gmkdir; do
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
{ test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
|
||||
as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
|
||||
case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
|
||||
'mkdir (GNU coreutils) '* | \
|
||||
'mkdir (coreutils) '* | \
|
||||
|
@ -3919,7 +3955,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_AWK="$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -4035,6 +4071,7 @@ fi
|
|||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
am__nodep='_no'
|
||||
fi
|
||||
if test "x$enable_dependency_tracking" != xno; then
|
||||
AMDEP_TRUE=
|
||||
|
@ -4067,7 +4104,7 @@ fi
|
|||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=tinc
|
||||
VERSION=1.1pre2
|
||||
VERSION=1.1pre3
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
@ -4097,11 +4134,11 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
|
|||
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
# Always define AMTAR for backward compatibility.
|
||||
# Always define AMTAR for backward compatibility. Yes, it's still used
|
||||
# in the wild :-( We should find a proper way to deprecate it ...
|
||||
AMTAR='$${TAR-tar}'
|
||||
|
||||
AMTAR=${AMTAR-"${am_missing_run}tar"}
|
||||
|
||||
am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
|
||||
am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
|
||||
|
||||
|
||||
|
||||
|
@ -4119,6 +4156,7 @@ else
|
|||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
|
@ -4178,7 +4216,7 @@ else
|
|||
break
|
||||
fi
|
||||
;;
|
||||
msvisualcpp | msvcmsys)
|
||||
msvc7 | msvc7msys | msvisualcpp | msvcmsys)
|
||||
# This compiler won't grok `-c -o', but also, the minuso test has
|
||||
# not run yet. These depmodes are late enough in the game, and
|
||||
# so weak that their functioning should not be impacted.
|
||||
|
@ -4414,7 +4452,7 @@ main ()
|
|||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
|
||||
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
|
||||
do
|
||||
CC="$ac_save_CC $ac_arg"
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
|
@ -4611,7 +4649,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -4651,7 +4689,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_RANLIB="ranlib"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -4829,13 +4867,70 @@ $as_echo "#define HAVE_MINGW 1" >>confdefs.h
|
|||
;;
|
||||
esac
|
||||
|
||||
# Check whether --enable-uml was given.
|
||||
if test "${enable_uml+set}" = set; then :
|
||||
enableval=$enable_uml; if test "x$enable_uml" = "xyes"; then :
|
||||
|
||||
$as_echo "#define ENABLE_UML 1" >>confdefs.h
|
||||
|
||||
uml=true
|
||||
|
||||
else
|
||||
uml=false
|
||||
fi
|
||||
|
||||
else
|
||||
uml=false
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-vde was given.
|
||||
if test "${enable_vde+set}" = set; then :
|
||||
enableval=$enable_vde; if test "x$enable_vde" = "xyes"; then :
|
||||
for ac_header in libvdeplug_dyn.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "libvdeplug_dyn.h" "ac_cv_header_libvdeplug_dyn_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_libvdeplug_dyn_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBVDEPLUG_DYN_H 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
as_fn_error $? "VDE plug header files not found." "$LINENO" 5; break
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
|
||||
$as_echo "#define ENABLE_VDE 1" >>confdefs.h
|
||||
|
||||
vde=true
|
||||
|
||||
else
|
||||
vde=false
|
||||
fi
|
||||
|
||||
else
|
||||
vde=false
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-tunemu was given.
|
||||
if test "${enable_tunemu+set}" = set; then :
|
||||
enableval=$enable_tunemu;
|
||||
enableval=$enable_tunemu; if test "x$enable_tunemu" = "xyes"; then :
|
||||
|
||||
$as_echo "#define ENABLE_TUNEMU 1" >>confdefs.h
|
||||
|
||||
tunemu=true
|
||||
|
||||
else
|
||||
tunemu=false
|
||||
fi
|
||||
|
||||
else
|
||||
tunemu=false
|
||||
|
||||
fi
|
||||
|
||||
|
@ -4843,13 +4938,32 @@ fi
|
|||
|
||||
# Check whether --with-windows2000 was given.
|
||||
if test "${with_windows2000+set}" = set; then :
|
||||
withval=$with_windows2000;
|
||||
withval=$with_windows2000; if test "x$with_windows2000" = "xyes"; then :
|
||||
|
||||
$as_echo "#define WITH_WINDOWS2000 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test "$uml" = true; then
|
||||
UML_TRUE=
|
||||
UML_FALSE='#'
|
||||
else
|
||||
UML_TRUE='#'
|
||||
UML_FALSE=
|
||||
fi
|
||||
|
||||
if test "$vde" = true; then
|
||||
VDE_TRUE=
|
||||
VDE_FALSE='#'
|
||||
else
|
||||
VDE_TRUE='#'
|
||||
VDE_FALSE=
|
||||
fi
|
||||
|
||||
if test "$tunemu" = true; then
|
||||
TUNEMU_TRUE=
|
||||
TUNEMU_FALSE='#'
|
||||
|
@ -5078,7 +5192,7 @@ fi
|
|||
|
||||
done
|
||||
|
||||
for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h
|
||||
for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"have.h\"
|
||||
|
@ -5135,11 +5249,11 @@ else
|
|||
int
|
||||
main ()
|
||||
{
|
||||
/* FIXME: Include the comments suggested by Paul. */
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* Ultrix mips cc rejects this. */
|
||||
/* Ultrix mips cc rejects this sort of thing. */
|
||||
typedef int charset[2];
|
||||
const charset cs;
|
||||
const charset cs = { 0, 0 };
|
||||
/* SunOS 4.1.1 cc rejects this. */
|
||||
char const *const *pcpcc;
|
||||
char **ppc;
|
||||
|
@ -5156,8 +5270,9 @@ main ()
|
|||
++pcpcc;
|
||||
ppc = (char**) pcpcc;
|
||||
pcpcc = (char const *const *) ppc;
|
||||
{ /* SCO 3.2v4 cc rejects this. */
|
||||
char *t;
|
||||
{ /* SCO 3.2v4 cc rejects this sort of thing. */
|
||||
char tx;
|
||||
char *t = &tx;
|
||||
char const *s = 0 ? (char *) 0 : (char const *) 0;
|
||||
|
||||
*t++ = 0;
|
||||
|
@ -5173,10 +5288,10 @@ main ()
|
|||
iptr p = 0;
|
||||
++p;
|
||||
}
|
||||
{ /* AIX XL C 1.02.0.0 rejects this saying
|
||||
{ /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
|
||||
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
|
||||
struct s { int j; const int *ap[3]; };
|
||||
struct s *b; b->j = 5;
|
||||
struct s { int j; const int *ap[3]; } bx;
|
||||
struct s *b = &bx; b->j = 5;
|
||||
}
|
||||
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
|
||||
const int foo = 10;
|
||||
|
@ -5925,6 +6040,111 @@ fi
|
|||
|
||||
|
||||
|
||||
# Check whether --enable-readline was given.
|
||||
if test "${enable_readline+set}" = set; then :
|
||||
enableval=$enable_readline;
|
||||
fi
|
||||
|
||||
if test "x$enable_readline" != "xno"; then :
|
||||
|
||||
|
||||
$as_echo "#define HAVE_READLINE 1" >>confdefs.h
|
||||
|
||||
readline=true
|
||||
|
||||
# Check whether --with-readline was given.
|
||||
if test "${with_readline+set}" = set; then :
|
||||
withval=$with_readline; readline="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-readline-include was given.
|
||||
if test "${with_readline_include+set}" = set; then :
|
||||
withval=$with_readline_include; readline_include="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-readline-lib was given.
|
||||
if test "${with_readline_lib+set}" = set; then :
|
||||
withval=$with_readline_lib; readline_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
for ac_header in readline/readline.h readline/history.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
as_fn_error $? "\"readline header files not found.\"" "$LINENO" 5; break
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
|
||||
$as_echo_n "checking for readline in -lreadline... " >&6; }
|
||||
if ${ac_cv_lib_readline_readline+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lreadline $CURSES_LIBS
|
||||
$LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char readline ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return readline ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_readline_readline=yes
|
||||
else
|
||||
ac_cv_lib_readline_readline=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
|
||||
$as_echo "$ac_cv_lib_readline_readline" >&6; }
|
||||
if test "x$ac_cv_lib_readline_readline" = xyes; then :
|
||||
READLINE_LIBS="-lreadline"
|
||||
else
|
||||
as_fn_error $? "\"readline library not found.\"" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --with-libevent was given.
|
||||
if test "${with_libevent+set}" = set; then :
|
||||
|
@ -6326,7 +6546,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -6369,7 +6589,7 @@ do
|
|||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_ac_pt_LIBGCRYPT_CONFIG="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
|
@ -6596,7 +6816,7 @@ if test "${with_openssl_lib+set}" = set; then :
|
|||
fi
|
||||
|
||||
|
||||
for ac_header in openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h
|
||||
for ac_header in openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h openssl/ecdh.h openssl/ec.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
|
@ -6657,7 +6877,7 @@ else
|
|||
fi
|
||||
|
||||
|
||||
for ac_func in RAND_pseudo_bytes EVP_EncryptInit_ex
|
||||
for ac_func in RAND_pseudo_bytes EVP_EncryptInit_ex ECDH_compute_key ECDSA_verify
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||
|
@ -6688,9 +6908,12 @@ fi
|
|||
|
||||
# Check whether --enable-jumbograms was given.
|
||||
if test "${enable_jumbograms+set}" = set; then :
|
||||
enableval=$enable_jumbograms;
|
||||
enableval=$enable_jumbograms; if test "x$enable_jumbograms" = "xyes"; then :
|
||||
|
||||
$as_echo "#define ENABLE_JUMBOGRAMS 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
@ -6829,6 +7052,14 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
|
|||
as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${UML_TRUE}" && test -z "${UML_FALSE}"; then
|
||||
as_fn_error $? "conditional \"UML\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${VDE_TRUE}" && test -z "${VDE_FALSE}"; then
|
||||
as_fn_error $? "conditional \"VDE\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${TUNEMU_TRUE}" && test -z "${TUNEMU_FALSE}"; then
|
||||
as_fn_error $? "conditional \"TUNEMU\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
@ -7131,16 +7362,16 @@ if (echo >conf$$.file) 2>/dev/null; then
|
|||
# ... but there are two gotchas:
|
||||
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
|
||||
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
|
||||
# In both cases, we have to default to `cp -p'.
|
||||
# In both cases, we have to default to `cp -pR'.
|
||||
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
elif ln conf$$.file conf$$ 2>/dev/null; then
|
||||
as_ln_s=ln
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
as_ln_s='cp -pR'
|
||||
fi
|
||||
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
|
||||
rmdir conf$$.dir 2>/dev/null
|
||||
|
@ -7200,28 +7431,16 @@ else
|
|||
as_mkdir_p=false
|
||||
fi
|
||||
|
||||
if test -x / >/dev/null 2>&1; then
|
||||
as_test_x='test -x'
|
||||
else
|
||||
if ls -dL / >/dev/null 2>&1; then
|
||||
as_ls_L_option=L
|
||||
else
|
||||
as_ls_L_option=
|
||||
fi
|
||||
as_test_x='
|
||||
eval sh -c '\''
|
||||
if test -d "$1"; then
|
||||
test -d "$1/.";
|
||||
else
|
||||
case $1 in #(
|
||||
-*)set "./$1";;
|
||||
esac;
|
||||
case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
|
||||
???[sx]*):;;*)false;;esac;fi
|
||||
'\'' sh
|
||||
'
|
||||
fi
|
||||
as_executable_p=$as_test_x
|
||||
|
||||
# as_fn_executable_p FILE
|
||||
# -----------------------
|
||||
# Test if FILE is an executable regular file.
|
||||
as_fn_executable_p ()
|
||||
{
|
||||
test -f "$1" && test -x "$1"
|
||||
} # as_fn_executable_p
|
||||
as_test_x='test -x'
|
||||
as_executable_p=as_fn_executable_p
|
||||
|
||||
# Sed expression to map a string onto a valid CPP name.
|
||||
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
|
@ -7243,7 +7462,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by $as_me, which was
|
||||
generated by GNU Autoconf 2.68. Invocation command line was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
CONFIG_HEADERS = $CONFIG_HEADERS
|
||||
|
@ -7309,10 +7528,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
|||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
config.status
|
||||
configured by $0, generated by GNU Autoconf 2.68,
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This config.status script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it."
|
||||
|
||||
|
@ -7403,7 +7622,7 @@ fi
|
|||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
if \$ac_cs_recheck; then
|
||||
set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
|
||||
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
|
||||
shift
|
||||
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
|
||||
CONFIG_SHELL='$SHELL'
|
||||
|
|
50
configure.in
50
configure.in
|
@ -4,7 +4,7 @@ AC_PREREQ(2.61)
|
|||
AC_INIT
|
||||
AC_CONFIG_SRCDIR([src/tincd.c])
|
||||
AC_GNU_SOURCE
|
||||
AM_INIT_AUTOMAKE(tinc, 1.1pre2)
|
||||
AM_INIT_AUTOMAKE(tinc, 1.1pre3)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
|
@ -73,18 +73,49 @@ case $host_os in
|
|||
;;
|
||||
esac
|
||||
|
||||
AC_ARG_ENABLE(uml,
|
||||
AS_HELP_STRING([--disable-uml], [enable support for User Mode Linux]),
|
||||
[ AS_IF([test "x$enable_uml" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_UML, 1, [Support for UML])
|
||||
uml=true
|
||||
],
|
||||
[uml=false])
|
||||
],
|
||||
[uml=false]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(vde,
|
||||
AS_HELP_STRING([--disable-vde], [enable support for Virtual Distributed Ethernet]),
|
||||
[ AS_IF([test "x$enable_vde" = "xyes"],
|
||||
[ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break])
|
||||
AC_DEFINE(ENABLE_VDE, 1, [Support for VDE])
|
||||
vde=true
|
||||
],
|
||||
[vde=false])
|
||||
],
|
||||
[vde=false]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(tunemu,
|
||||
AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]),
|
||||
AS_HELP_STRING([--disable-tunemu], [enable support for the tunemu driver]),
|
||||
[ AS_IF([test "x$enable_tunemu" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
|
||||
tunemu=true
|
||||
]
|
||||
],
|
||||
[tunemu=false])
|
||||
],
|
||||
[tunemu=false]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(windows2000,
|
||||
AS_HELP_STRING([--with-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]),
|
||||
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])]
|
||||
AS_HELP_STRING([--without-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]),
|
||||
[ AS_IF([test "x$with_windows2000" = "xyes"],
|
||||
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])])
|
||||
]
|
||||
)
|
||||
|
||||
AM_CONDITIONAL(UML, test "$uml" = true)
|
||||
AM_CONDITIONAL(VDE, test "$vde" = true)
|
||||
AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
|
||||
|
||||
AC_CACHE_SAVE
|
||||
|
@ -101,7 +132,7 @@ dnl We do this in multiple stages, because unlike Linux all the other operating
|
|||
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
|
||||
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
|
||||
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
|
||||
[], [], [#include "have.h"]
|
||||
)
|
||||
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
|
||||
|
@ -151,6 +182,7 @@ dnl These are defined in files in m4/
|
|||
AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
|
||||
|
||||
tinc_CURSES
|
||||
tinc_READLINE
|
||||
tinc_LIBEVENT
|
||||
tinc_ZLIB
|
||||
tinc_LZO
|
||||
|
@ -166,8 +198,10 @@ fi
|
|||
|
||||
dnl Check if support for jumbograms is requested
|
||||
AC_ARG_ENABLE(jumbograms,
|
||||
AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
|
||||
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ]
|
||||
AS_HELP_STRING([--disable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
|
||||
[ AS_IF([test "x$enable_jumbograms" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ])
|
||||
]
|
||||
)
|
||||
|
||||
AC_SUBST(INCLUDES)
|
||||
|
|
190
depcomp
190
depcomp
|
@ -1,10 +1,10 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
scriptversion=2012-03-27.16; # UTC
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
|
||||
# Software Foundation, Inc.
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
|
||||
# 2011, 2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -28,7 +28,7 @@ scriptversion=2009-04-28.21; # UTC
|
|||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
|
@ -40,11 +40,11 @@ as side-effects.
|
|||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by `PROGRAMS ARGS'.
|
||||
object Object file output by `PROGRAMS ARGS'.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputing dependencies.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
|
@ -57,6 +57,12 @@ EOF
|
|||
;;
|
||||
esac
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
|
@ -90,10 +96,24 @@ if test "$depmode" = msvcmsys; then
|
|||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u="sed s,\\\\\\\\,/,g"
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
|
@ -148,20 +168,21 @@ gcc)
|
|||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
tr ' ' "$nl" < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well.
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
|
@ -193,18 +214,15 @@ sgi)
|
|||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> "$depfile"
|
||||
tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
|
@ -216,10 +234,17 @@ sgi)
|
|||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts `$object:' at the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
|
@ -249,12 +274,11 @@ aix)
|
|||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Each line is of the form 'foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
# '$object: dependent.h' and one to simply 'dependent.h:'.
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
|
@ -265,23 +289,26 @@ aix)
|
|||
;;
|
||||
|
||||
icc)
|
||||
# Intel's C compiler understands `-MD -MF file'. However on
|
||||
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
|
||||
# However on
|
||||
# $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# ICC 7.0 will fill foo.d with something like
|
||||
# foo.o: sub/foo.c
|
||||
# foo.o: sub/foo.h
|
||||
# which is wrong. We want:
|
||||
# which is wrong. We want
|
||||
# sub/foo.o: sub/foo.c
|
||||
# sub/foo.o: sub/foo.h
|
||||
# sub/foo.c:
|
||||
# sub/foo.h:
|
||||
# ICC 7.1 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using \ :
|
||||
# and will wrap long lines using '\':
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
|
||||
# tcc 0.9.26 (FIXME still under development at the moment of writing)
|
||||
# will emit a similar output, but also prepend the continuation lines
|
||||
# with horizontal tabulation characters.
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
|
@ -290,15 +317,21 @@ icc)
|
|||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Each line is of the form 'foo.o: dependent.h',
|
||||
# or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
|
||||
sed -e 's/$/ :/' >> "$depfile"
|
||||
# '$object: dependent.h' and one to simply 'dependent.h:'.
|
||||
sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
|
||||
< "$tmpdepfile" > "$depfile"
|
||||
sed '
|
||||
s/[ '"$tab"'][ '"$tab"']*/ /g
|
||||
s/^ *//
|
||||
s/ *\\*$//
|
||||
s/^[^:]*: *//
|
||||
/^$/d
|
||||
/:$/d
|
||||
s/$/ :/
|
||||
' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
|
@ -334,7 +367,7 @@ hp2)
|
|||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add `dependent.h:' lines.
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
|
@ -349,9 +382,9 @@ hp2)
|
|||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
|
@ -397,14 +430,59 @@ tru64)
|
|||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test "$stat" = 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
@ -422,7 +500,7 @@ dashmstdout)
|
|||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
|
@ -442,15 +520,14 @@ dashmstdout)
|
|||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for `:'
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
tr ' ' "$nl" < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
|
@ -503,9 +580,10 @@ makedepend)
|
|||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
|
@ -525,7 +603,7 @@ cpp)
|
|||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
|
@ -594,8 +672,8 @@ msvisualcpp)
|
|||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
|
|
@ -23,16 +23,16 @@ texi2html: tinc.texi
|
|||
texi2html -split=chapter tinc.texi
|
||||
|
||||
tincd.8.html: tincd.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tincctl.8.html: tincctl.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tinc-gui.8.html: tinc-gui.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tinc.conf.5.html: tinc.conf.5
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
substitute = sed \
|
||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||
|
@ -41,18 +41,18 @@ substitute = sed \
|
|||
-e s,'@localstatedir\@',"$(localstatedir)",g
|
||||
|
||||
tincd.8: tincd.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tincctl.8: tincctl.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc-gui.8: tinc-gui.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc.conf.5: tinc.conf.5.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tincinclude.texi: tincinclude.texi.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc.texi: tincinclude.texi
|
||||
|
|
148
doc/Makefile.in
148
doc/Makefile.in
|
@ -1,9 +1,9 @@
|
|||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -15,6 +15,23 @@
|
|||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
|
@ -38,7 +55,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
|
@ -59,6 +77,11 @@ TEXI2PDF = $(TEXI2DVI) --pdf --batch
|
|||
MAKEINFOHTML = $(MAKEINFO) --html
|
||||
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
|
||||
DVIPS = dvips
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man5dir)" \
|
||||
"$(DESTDIR)$(man8dir)"
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
|
@ -82,6 +105,12 @@ am__nobase_list = $(am__nobase_strip_setup); \
|
|||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
man5dir = $(mandir)/man5
|
||||
man8dir = $(mandir)/man8
|
||||
NROFF = nroff
|
||||
|
@ -140,6 +169,7 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
|
@ -304,9 +334,7 @@ uninstall-html-am:
|
|||
|
||||
uninstall-info-am:
|
||||
@$(PRE_UNINSTALL)
|
||||
@if test -d '$(DESTDIR)$(infodir)' && \
|
||||
(install-info --version && \
|
||||
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
|
||||
@if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
|
||||
list='$(INFO_DEPS)'; \
|
||||
for file in $$list; do \
|
||||
relfile=`echo "$$file" | sed 's|^.*/||'`; \
|
||||
|
@ -379,11 +407,18 @@ maintainer-clean-aminfo:
|
|||
done
|
||||
install-man5: $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
|
||||
@list=''; test -n "$(man5dir)" || exit 0; \
|
||||
{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.5[a-z]*$$/p'; \
|
||||
@list1=''; \
|
||||
list2='$(man_MANS)'; \
|
||||
test -n "$(man5dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.5[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
|
@ -412,16 +447,21 @@ uninstall-man5:
|
|||
sed -n '/\.5[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
test -z "$$files" || { \
|
||||
echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
|
||||
dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
|
||||
install-man8: $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
|
||||
@list=''; test -n "$(man8dir)" || exit 0; \
|
||||
{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.8[a-z]*$$/p'; \
|
||||
@list1=''; \
|
||||
list2='$(man_MANS)'; \
|
||||
test -n "$(man8dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.8[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
|
@ -450,9 +490,7 @@ uninstall-man8:
|
|||
sed -n '/\.8[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
test -z "$$files" || { \
|
||||
echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(man8dir)" && rm -f $$files; }
|
||||
dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
|
||||
tags: TAGS
|
||||
TAGS:
|
||||
|
||||
|
@ -523,10 +561,15 @@ install-am: all-am
|
|||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
@ -565,8 +608,11 @@ install-dvi: install-dvi-am
|
|||
|
||||
install-dvi-am: $(DVIS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)"
|
||||
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
|
@ -581,18 +627,22 @@ install-html: install-html-am
|
|||
|
||||
install-html-am: $(HTMLS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)"
|
||||
@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
$(am__strip_dir) \
|
||||
if test -d "$$d$$p"; then \
|
||||
d2=$$d$$p; \
|
||||
if test -d "$$d2"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
|
||||
echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
|
||||
else \
|
||||
list2="$$list2 $$d$$p"; \
|
||||
list2="$$list2 $$d2"; \
|
||||
fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
|
||||
|
@ -604,9 +654,12 @@ install-info: install-info-am
|
|||
|
||||
install-info-am: $(INFO_DEPS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
|
||||
fi; \
|
||||
for file in $$list; do \
|
||||
case $$file in \
|
||||
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
|
@ -624,8 +677,7 @@ install-info-am: $(INFO_DEPS)
|
|||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
|
||||
@$(POST_INSTALL)
|
||||
@if (install-info --version && \
|
||||
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
|
||||
@if $(am__can_run_installinfo); then \
|
||||
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
|
||||
for file in $$list; do \
|
||||
relfile=`echo "$$file" | sed 's|^.*/||'`; \
|
||||
|
@ -639,8 +691,11 @@ install-pdf: install-pdf-am
|
|||
|
||||
install-pdf-am: $(PDFS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)"
|
||||
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
|
@ -652,8 +707,11 @@ install-ps: install-ps-am
|
|||
|
||||
install-ps-am: $(PSS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)"
|
||||
@list='$(PSS)'; test -n "$(psdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
|
@ -713,31 +771,31 @@ texi2html: tinc.texi
|
|||
texi2html -split=chapter tinc.texi
|
||||
|
||||
tincd.8.html: tincd.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tincctl.8.html: tincctl.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tinc-gui.8.html: tinc-gui.8
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tinc.conf.5.html: tinc.conf.5
|
||||
w3mman2html $< > $@
|
||||
w3mman2html $? > $@
|
||||
|
||||
tincd.8: tincd.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tincctl.8: tincctl.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc-gui.8: tinc-gui.8.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc.conf.5: tinc.conf.5.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tincinclude.texi: tincinclude.texi.in
|
||||
$(substitute) $< > $@
|
||||
$(substitute) $? > $@
|
||||
|
||||
tinc.texi: tincinclude.texi
|
||||
|
||||
|
|
Binary file not shown.
1948
doc/texinfo.tex
1948
doc/texinfo.tex
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
.Dd 2010-01-16
|
||||
.Dd 2012-09-27
|
||||
.Dt TINC.CONF 5
|
||||
.\" Manual page created by:
|
||||
.\" Ivo Timmermans
|
||||
|
@ -14,22 +14,12 @@ The files in the
|
|||
directory contain runtime and security information for the tinc daemon.
|
||||
|
||||
.Sh NETWORKS
|
||||
It is perfectly ok for you to run more than one tinc daemon.
|
||||
However, in its default form,
|
||||
you will soon notice that you can't use two different configuration files without the
|
||||
.Fl c
|
||||
option.
|
||||
|
||||
.Pp
|
||||
We have thought of another way of dealing with this: network names.
|
||||
This means that you call
|
||||
.Nm
|
||||
with the
|
||||
To distinguish multiple instances of tinc running on one computer,
|
||||
you can use the
|
||||
.Fl n
|
||||
option, which will assign a name to this daemon.
|
||||
|
||||
option to assign a network name to each tinc daemon.
|
||||
.Pp
|
||||
The effect of this is that the daemon will set its configuration root to
|
||||
The effect of this option is that the daemon will set its configuration root to
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
|
||||
where
|
||||
.Ar NETNAME
|
||||
|
@ -37,14 +27,14 @@ is your argument to the
|
|||
.Fl n
|
||||
option.
|
||||
You'll notice that messages appear in syslog as coming from
|
||||
.Nm tincd. Ns Ar NETNAME .
|
||||
|
||||
.Nm tincd. Ns Ar NETNAME ,
|
||||
and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name.
|
||||
.Pp
|
||||
However, it is not strictly necessary that you call tinc with the
|
||||
It is recommended that you use network names even if you run only one instance of tinc.
|
||||
However, you can choose not to use the
|
||||
.Fl n
|
||||
option.
|
||||
In this case, the network name would just be empty,
|
||||
and it will be used as such.
|
||||
In this case, the network name would just be empty, and
|
||||
.Nm tinc
|
||||
now looks for files in
|
||||
.Pa @sysconfdir@/tinc/ ,
|
||||
|
@ -55,12 +45,6 @@ the configuration file should be
|
|||
and the host configuration files are now expected to be in
|
||||
.Pa @sysconfdir@/tinc/hosts/ .
|
||||
|
||||
.Pp
|
||||
But it is highly recommended that you use this feature of
|
||||
.Nm tinc ,
|
||||
because it will be so much clearer whom your daemon talks to.
|
||||
Hence, we will assume that you use it.
|
||||
|
||||
.Sh NAMES
|
||||
Each tinc daemon should have a name that is unique in the network which it will be part of.
|
||||
The name will be used by other tinc daemons for identification.
|
||||
|
@ -72,25 +56,38 @@ file.
|
|||
To make things easy,
|
||||
choose something that will give unique and easy to remember names to your tinc daemon(s).
|
||||
You could try things like hostnames, owner surnames or location names.
|
||||
However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-9) and underscores (_) in the name.
|
||||
|
||||
.Sh INITIAL CONFIGURATION
|
||||
If you have not configured tinc yet, you can easily create a basic configuration using the following command:
|
||||
.Bd -literal -offset indent
|
||||
.Nm tincctl Fl n Ar NETNAME Li init Ar NAME
|
||||
.Ed
|
||||
|
||||
.Pp
|
||||
You can further change the configuration as needed either by manually editing the configuration files,
|
||||
or by using
|
||||
.Xr tincctl 8 .
|
||||
|
||||
.Sh PUBLIC/PRIVATE KEYS
|
||||
You should use
|
||||
.Ic tincd -K
|
||||
to generate public/private keypairs.
|
||||
It will generate two keys.
|
||||
The private key should be stored in a separate file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv
|
||||
\-\- where
|
||||
.Ar NETNAME
|
||||
stands for the network (see
|
||||
.Sx NETWORKS )
|
||||
above.
|
||||
The public key should be stored in the host configuration file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME
|
||||
\-\- where
|
||||
.Va NAME
|
||||
stands for the name of the local tinc daemon (see
|
||||
.Sx NAMES ) .
|
||||
The
|
||||
.Nm tincctl Li init
|
||||
command will have generated both RSA and ECDSA public/private keypairs.
|
||||
The private keys should be stored in files named
|
||||
.Pa rsa_key.priv
|
||||
and
|
||||
.Pa ecdsa_key.priv
|
||||
in the directory
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /
|
||||
The public keys should be stored in the host configuration file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME .
|
||||
|
||||
The RSA keys are used for backwards compatibility with tinc version 1.0.
|
||||
If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files,
|
||||
but you will need to create ECDSA keys using the following command:
|
||||
.Bd -literal -offset indent
|
||||
.Nm tincctl Fl n Ar NETNAME Li generate-ecdsa-keys
|
||||
.Ed
|
||||
|
||||
.Sh SERVER CONFIGURATION
|
||||
The server configuration of the daemon is done in the file
|
||||
|
@ -117,6 +114,11 @@ Although all configuration options for the local host listed in this document ca
|
|||
it is recommended to put host specific configuration options in the host configuration file,
|
||||
as this makes it easy to exchange with other nodes.
|
||||
|
||||
.Pp
|
||||
You can edit the config file manually, but it is recommended that you use
|
||||
.Xr tincctl 8
|
||||
to change configuration variables for you.
|
||||
|
||||
.Pp
|
||||
Here are all valid variables, listed in alphabetical order.
|
||||
The default value is given between parentheses.
|
||||
|
@ -129,14 +131,24 @@ If
|
|||
is selected, then depending on the operating system both IPv4 and IPv6 or just
|
||||
IPv6 listening sockets will be created.
|
||||
|
||||
.It Va BindToAddress Li = Ar address Bq experimental
|
||||
.It Va BindToAddress Li = Ar address Op Ar port
|
||||
If your computer has more than one IPv4 or IPv6 address,
|
||||
.Nm tinc
|
||||
will by default listen on all of them for incoming connections.
|
||||
It is possible to bind only to a single address with this variable.
|
||||
|
||||
Multiple
|
||||
.Va BindToAddress
|
||||
variables may be specified,
|
||||
in which case listening sockets for each specified address are made.
|
||||
.Pp
|
||||
This option may not work on all platforms.
|
||||
If no
|
||||
.Ar port
|
||||
is specified, the socket will be bound to the port specified by the
|
||||
.Va Port
|
||||
option, or to port 655 if neither is given.
|
||||
To only bind to a specific port but not to a specific address, use
|
||||
.Li *
|
||||
for the
|
||||
.Ar address .
|
||||
|
||||
.It Va BindToInterface Li = Ar interface Bq experimental
|
||||
If your computer has more than one network interface,
|
||||
|
@ -146,6 +158,28 @@ It is possible to bind only to a single interface with this variable.
|
|||
|
||||
.Pp
|
||||
This option may not work on all platforms.
|
||||
Also, on some platforms it will not actually bind to an interface,
|
||||
but rather to the address that the interface has at the moment a socket is created.
|
||||
|
||||
.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
|
||||
This option selects the way broadcast packets are sent to other daemons.
|
||||
NOTE: all nodes in a VPN must use the same
|
||||
.Va Broadcast
|
||||
mode, otherwise routing loops can form.
|
||||
|
||||
.Bl -tag -width indent
|
||||
.It no
|
||||
Broadcast packets are never sent to other nodes.
|
||||
|
||||
.It mst
|
||||
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
|
||||
This ensures broadcast packets reach all nodes.
|
||||
|
||||
.It direct
|
||||
Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||
Broadcast packets received from other nodes are never forwarded.
|
||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||
.El
|
||||
|
||||
.It Va ConnectTo Li = Ar name
|
||||
Specifies which other tinc daemon to connect to on startup.
|
||||
|
@ -165,6 +199,16 @@ If you don't specify a host with
|
|||
won't try to connect to other daemons at all,
|
||||
and will instead just listen for incoming connections.
|
||||
|
||||
.It Va DecrementTTL Li = yes | no Po no Pc Bq experimental
|
||||
When enabled,
|
||||
.Nm tinc
|
||||
will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
|
||||
before forwarding a received packet to the virtual network device or to another node,
|
||||
and will drop packets that have a TTL value of zero,
|
||||
in which case it will send an ICMP Time Exceeded packet back.
|
||||
.Pp
|
||||
Do not use this option if you use switch mode and want to use IPv6.
|
||||
|
||||
.It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
|
||||
The virtual network device to use.
|
||||
.Nm tinc
|
||||
|
@ -177,30 +221,75 @@ instead of
|
|||
The info pages of the tinc package contain more information
|
||||
about configuring the virtual network device.
|
||||
|
||||
.It Va DeviceType Li = tun | tunnohead | tunifhead | tap Po only supported on BSD platforms Pc
|
||||
.It Va DeviceType Li = Ar type Pq platform dependent
|
||||
The type of the virtual network device.
|
||||
Tinc will normally automatically select the right type, and this option should not be used.
|
||||
However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
|
||||
using this option might help.
|
||||
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
|
||||
However, this option can be used to select one of the special interface types, if support for them is compiled in.
|
||||
.Bl -tag -width indent
|
||||
|
||||
.It tun
|
||||
.It dummy
|
||||
Use a dummy interface.
|
||||
No packets are ever read or written to a virtual network device.
|
||||
Useful for testing, or when setting up a node that only forwards packets for other nodes.
|
||||
|
||||
.It raw_socket
|
||||
Open a raw socket, and bind it to a pre-existing
|
||||
.Va Interface
|
||||
(eth0 by default).
|
||||
All packets are read from this interface.
|
||||
Packets received for the local node are written to the raw socket.
|
||||
However, at least on Linux, the operating system does not process IP packets destined for the local host.
|
||||
|
||||
.It multicast
|
||||
Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using
|
||||
.Va Device .
|
||||
Packets are read from and written to this multicast socket.
|
||||
This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address.
|
||||
Do NOT connect multiple
|
||||
.Nm tinc
|
||||
daemons to the same multicast address, this will very likely cause routing loops.
|
||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||
|
||||
.It uml Pq not compiled in by default
|
||||
Create a UNIX socket with the filename specified by
|
||||
.Va Device ,
|
||||
or
|
||||
.Pa @localstatedir@/run/ Ns Ar NETNAME Ns Pa .umlsocket
|
||||
if not specified.
|
||||
.Nm tinc
|
||||
will wait for a User Mode Linux instance to connect to this socket.
|
||||
|
||||
.It vde Pq not compiled in by default
|
||||
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
|
||||
using the UNIX socket specified by
|
||||
.Va Device ,
|
||||
or
|
||||
.Pa @localstatedir@/run/vde.ctl
|
||||
if not specified.
|
||||
.El
|
||||
|
||||
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
|
||||
it can be used to change the way packets are interpreted:
|
||||
|
||||
.Bl -tag -width indent
|
||||
|
||||
.It tun Pq BSD and Linux
|
||||
Set type to tun.
|
||||
Depending on the platform, this can either be with or without an address family header (see below).
|
||||
|
||||
.It tunnohead
|
||||
.It tunnohead Pq BSD
|
||||
Set type to tun without an address family header.
|
||||
Tinc will expect packets read from the virtual network device to start with an IP header.
|
||||
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
|
||||
|
||||
.It tunifhead
|
||||
.It tunifhead Pq BSD
|
||||
Set type to tun with an address family header.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with a four byte header containing the address family,
|
||||
followed by an IP header.
|
||||
This mode should support both IPv4 and IPv6 packets.
|
||||
|
||||
.It tap
|
||||
.It tap Pq BSD and Linux
|
||||
Set type to tap.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with an Ethernet header.
|
||||
|
@ -247,7 +336,7 @@ This is less efficient, but allows the kernel to apply its routing and firewall
|
|||
and can also help debugging.
|
||||
.El
|
||||
|
||||
.It Va GraphDumpFile Li = Ar filename Bq experimental
|
||||
.It Va GraphDumpFile Li = Ar filename
|
||||
If this option is present,
|
||||
.Nm tinc
|
||||
will dump the current network graph to the file
|
||||
|
@ -268,7 +357,7 @@ a lookup if your DNS server is not responding.
|
|||
|
||||
.Pp
|
||||
This does not affect resolving hostnames to IP addresses from the
|
||||
host configuration files.
|
||||
host configuration files, but whether hostnames should be resolved while logging.
|
||||
|
||||
.It Va IffOneQueue Li = yes | no Po no Pc Bq experimental
|
||||
(Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices.
|
||||
|
@ -286,6 +375,18 @@ This option controls the period the encryption keys used to encrypt the data are
|
|||
It is common practice to change keys at regular intervals to make it even harder for crackers,
|
||||
even though it is thought to be nearly impossible to crack a single key.
|
||||
|
||||
.It Va LocalDiscovery Li = yes | no Pq no
|
||||
When enabled,
|
||||
.Nm tinc
|
||||
will try to detect peers that are on the same local network.
|
||||
This will allow direct communication using LAN addresses, even if both peers are behind a NAT
|
||||
and they only ConnectTo a third node outside the NAT,
|
||||
which normally would prevent the peers from learning each other's LAN address.
|
||||
|
||||
.Pp
|
||||
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
|
||||
This feature may not work in all possible situations.
|
||||
|
||||
.It Va MACExpire Li = Ar seconds Pq 600
|
||||
This option controls the amount of time MAC addresses are kept before they are removed.
|
||||
This only has effect when
|
||||
|
@ -327,6 +428,19 @@ while no routing table is managed.
|
|||
.It Va Name Li = Ar name Bq required
|
||||
This is the name which identifies this tinc daemon.
|
||||
It must be unique for the virtual private network this daemon will connect to.
|
||||
The Name may only consist of alphanumeric and underscore characters.
|
||||
|
||||
If
|
||||
.Va Name
|
||||
starts with a
|
||||
.Li $ ,
|
||||
then the contents of the environment variable that follows will be used.
|
||||
In that case, invalid characters will be converted to underscores.
|
||||
If
|
||||
.Va Name
|
||||
is
|
||||
.Li $HOST ,
|
||||
but no such environment variable exist, the hostname will be read using the gethostnname() system call.
|
||||
|
||||
.It Va PingInterval Li = Ar seconds Pq 60
|
||||
The number of seconds of inactivity that
|
||||
|
@ -356,11 +470,46 @@ or
|
|||
specified in the configuration file.
|
||||
|
||||
.It Va ProcessPriority Li = low | normal | high
|
||||
When this option is used the priority of the tincd process will be adjusted.
|
||||
When this option is used the priority of the
|
||||
.Nm tincd
|
||||
process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
.It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental
|
||||
Use a proxy when making outgoing connections.
|
||||
The following proxy types are currently supported:
|
||||
.Bl -tag -width indent
|
||||
.It socks4 Ar address Ar port Op Ar username
|
||||
Connects to the proxy using the SOCKS version 4 protocol.
|
||||
Optionally, a
|
||||
.Ar username
|
||||
can be supplied which will be passed on to the proxy server.
|
||||
Only IPv4 connections can be proxied using SOCKS 4.
|
||||
.It socks5 Ar address Ar port Op Ar username Ar password
|
||||
Connect to the proxy using the SOCKS version 5 protocol.
|
||||
If a
|
||||
.Ar username
|
||||
and
|
||||
.Ar password
|
||||
are given, basic username/password authentication will be used,
|
||||
otherwise no authentication will be used.
|
||||
.It http Ar address Ar port
|
||||
Connects to the proxy and sends a HTTP CONNECT request.
|
||||
.It exec Ar command
|
||||
Executes the given
|
||||
.Ar command
|
||||
which should set up the outgoing connection.
|
||||
The environment variables
|
||||
.Ev NAME ,
|
||||
.Ev NODE ,
|
||||
.Ev REMOTEADDRES
|
||||
and
|
||||
.Ev REMOTEPORT
|
||||
are available.
|
||||
.El
|
||||
|
||||
.It Va ReplayWindow Li = Ar bytes Pq 16
|
||||
This is the size of the replay tracking window for each remote node, in bytes.
|
||||
vhis is the size of the replay tracking window for each remote node, in bytes.
|
||||
The window is a bitfield which tracks 1 packet per bit, so for example
|
||||
the default setting of 16 will track up to 128 packets in the window. In high
|
||||
bandwidth scenarios, setting this to a higher value can reduce packet loss from
|
||||
|
@ -406,7 +555,7 @@ Since host configuration files only contain public keys,
|
|||
no secrets are revealed by sending out this information.
|
||||
.Bl -tag -width indent
|
||||
|
||||
.It Va Address Li = Ar address Oo port Oc Bq recommended
|
||||
.It Va Address Li = Ar address Oo Ar port Oc Bq recommended
|
||||
The IP address or hostname of this tinc daemon on the real network.
|
||||
This will only be used when trying to make an outgoing connection to this tinc daemon.
|
||||
Optionally, a port can be specified to use for this address.
|
||||
|
@ -497,12 +646,11 @@ variables can be specified.
|
|||
Subnets can either be single MAC, IPv4 or IPv6 addresses,
|
||||
in which case a subnet consisting of only that single address is assumed,
|
||||
or they can be a IPv4 or IPv6 network address with a prefixlength.
|
||||
Shorthand notations are not supported.
|
||||
For example, IPv4 subnets must be in a form like 192.168.1.0/24,
|
||||
where 192.168.1.0 is the network address and 24 is the number of bits set in the netmask.
|
||||
Note that subnets like 192.168.1.1/24 are invalid!
|
||||
Read a networking HOWTO/FAQ/guide if you don't understand this.
|
||||
IPv6 subnets are notated like fec0:0:0:1:0:0:0:0/64.
|
||||
IPv6 subnets are notated like fec0:0:0:1::/64.
|
||||
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
||||
|
||||
.Pp
|
||||
|
@ -609,6 +757,10 @@ When a subnet becomes (un)reachable, this is set to the subnet.
|
|||
When a subnet becomes (un)reachable, this is set to the subnet weight.
|
||||
.El
|
||||
|
||||
.Pp
|
||||
Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command
|
||||
.Nm chmod Li a+x Pa script .
|
||||
|
||||
.Sh FILES
|
||||
The most important files are:
|
||||
.Bl -tag -width indent
|
||||
|
@ -636,8 +788,9 @@ its connection to the virtual network device.
|
|||
|
||||
.Sh SEE ALSO
|
||||
.Xr tincd 8 ,
|
||||
.Xr tincctl 8 ,
|
||||
.Pa http://www.tinc-vpn.org/ ,
|
||||
.Pa http://www.linuxdoc.org/LDP/nag2/ .
|
||||
.Pa http://www.tldp.org/LDP/nag2/ .
|
||||
|
||||
.Pp
|
||||
The full documentation for
|
||||
|
|
815
doc/tinc.info
815
doc/tinc.info
File diff suppressed because it is too large
Load diff
500
doc/tinc.texi
500
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-2011 Ivo Timmermans,
|
||||
Copyright @copyright{} 1998-2012 Ivo Timmermans,
|
||||
Guus Sliepen <guus@@tinc-vpn.org> and
|
||||
Wessel Dankers <wsl@@tinc-vpn.org>.
|
||||
|
||||
|
@ -39,7 +39,7 @@ permission notice identical to this one.
|
|||
@vskip 0pt plus 1filll
|
||||
This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
|
||||
|
||||
Copyright @copyright{} 1998-2011 Ivo Timmermans,
|
||||
Copyright @copyright{} 1998-2012 Ivo Timmermans,
|
||||
Guus Sliepen <guus@@tinc-vpn.org> and
|
||||
Wessel Dankers <wsl@@tinc-vpn.org>.
|
||||
|
||||
|
@ -187,7 +187,7 @@ packets.
|
|||
@cindex release
|
||||
For an up to date list of supported platforms, please check the list on
|
||||
our website:
|
||||
@uref{http://www.tinc-vpn.org/platforms}.
|
||||
@uref{http://www.tinc-vpn.org/platforms/}.
|
||||
|
||||
@c
|
||||
@c
|
||||
|
@ -262,7 +262,7 @@ alias char-major-10-200 tun
|
|||
@subsection Configuration of FreeBSD kernels
|
||||
|
||||
For FreeBSD version 4.1 and higher, tun and tap drivers are included in the default kernel configuration.
|
||||
Using tap devices is recommended.
|
||||
The tap driver can be loaded with @code{kldload if_tap}, or by adding @code{if_tap_load="YES"} to @file{/boot/loader.conf}.
|
||||
|
||||
|
||||
@c ==================================================================
|
||||
|
@ -276,6 +276,7 @@ which adds a tap device to OpenBSD which should work with tinc,
|
|||
but with recent versions of OpenBSD,
|
||||
a tun device can act as a tap device by setting the link0 option with ifconfig.
|
||||
|
||||
|
||||
@c ==================================================================
|
||||
@node Configuration of NetBSD kernels
|
||||
@subsection Configuration of NetBSD kernels
|
||||
|
@ -466,7 +467,7 @@ available. Make sure you install the development AND runtime versions
|
|||
of this package.
|
||||
|
||||
If you have to install libevent manually, you can get the source code
|
||||
from @url{http://monkey.org/~provos/libevent/}. Instructions on how to configure,
|
||||
from @url{http://libevent.org/}. Instructions on how to configure,
|
||||
build and install this package are included within the package. Please
|
||||
make sure you build development and runtime libraries (which is the
|
||||
default).
|
||||
|
@ -492,7 +493,7 @@ system startup scripts and sample configurations.
|
|||
If you cannot use one of the precompiled packages, or you want to compile tinc
|
||||
for yourself, you can use the source. The source is distributed under
|
||||
the GNU General Public License (GPL). Download the source from the
|
||||
@uref{http://www.tinc-vpn.org/download, download page}, which has
|
||||
@uref{http://www.tinc-vpn.org/download/, download page}, which has
|
||||
the checksums of these files listed; you may wish to check these with
|
||||
md5sum before continuing.
|
||||
|
||||
|
@ -533,7 +534,7 @@ The documentation that comes along with your distribution will tell you how to d
|
|||
|
||||
In order to build tinc on Darwin, you need to install the MacOS/X Developer Tools
|
||||
from @uref{http://developer.apple.com/tools/macosxtools.html} and
|
||||
a recent version of Fink from @uref{http://fink.sourceforge.net/}.
|
||||
a recent version of Fink from @uref{http://www.finkproject.org/}.
|
||||
|
||||
After installation use fink to download and install the following packages:
|
||||
autoconf25, automake, dlcompat, m4, openssl, zlib and lzo.
|
||||
|
@ -638,7 +639,6 @@ tinc 655/udp TINC
|
|||
* Multiple networks::
|
||||
* How connections work::
|
||||
* Configuration files::
|
||||
* Generating keypairs::
|
||||
* Network interfaces::
|
||||
* Example configuration::
|
||||
@end menu
|
||||
|
@ -661,13 +661,19 @@ you will not find the answers in this documentation.
|
|||
Make sure you have an adequate understanding of networks in general.
|
||||
@cindex Network Administrators Guide
|
||||
A good resource on networking is the
|
||||
@uref{http://www.linuxdoc.org/LDP/nag2/, Linux Network Administrators Guide}.
|
||||
@uref{http://www.tldp.org/LDP/nag2/, Linux Network Administrators Guide}.
|
||||
|
||||
If you have everything clearly pictured in your mind,
|
||||
proceed in the following order:
|
||||
First, generate the configuration files (@file{tinc.conf}, your host configuration file, @file{tinc-up} and perhaps @file{tinc-down}).
|
||||
Then generate the keypairs.
|
||||
Finally, distribute the host configuration files.
|
||||
First, create the initial configuration files and public/private keypairs using the following command:
|
||||
@example
|
||||
tincctl -n @var{NETNAME} init @var{NAME}
|
||||
@end example
|
||||
Second, use @samp{tincctl -n @var{NETNAME} config ...} to further configure tinc.
|
||||
Finally, export your host configuration file using @samp{tincctl -n @var{NETNAME} export} and send it to those
|
||||
people or computers you want tinc to connect to.
|
||||
They should send you their host configuration file back, which you can import using @samp{tincctl -n @var{NETNAME} import}.
|
||||
|
||||
These steps are described in the subsections below.
|
||||
|
||||
|
||||
|
@ -677,30 +683,29 @@ These steps are described in the subsections below.
|
|||
|
||||
@cindex multiple networks
|
||||
@cindex netname
|
||||
|
||||
In order to allow you to run more than one tinc daemon on one computer,
|
||||
for instance if your computer is part of more than one VPN,
|
||||
you can assign a @var{netname} to your VPN.
|
||||
It is not required if you only run one tinc daemon,
|
||||
it doesn't even have to be the same on all the sites of your VPN,
|
||||
it doesn't even have to be the same on all the nodes of your VPN,
|
||||
but it is recommended that you choose one anyway.
|
||||
|
||||
We will asume you use a netname throughout this document.
|
||||
This means that you call tincd with the -n argument,
|
||||
which will assign a netname to this daemon.
|
||||
This means that you call tincctl with the -n argument,
|
||||
which will specify the netname.
|
||||
|
||||
The effect of this is that the daemon will set its configuration
|
||||
root to @file{@value{sysconfdir}/tinc/@var{netname}/}, where @var{netname} is your argument to the -n
|
||||
option. You'll notice that it appears in syslog as @file{tinc.@var{netname}}.
|
||||
The effect of this option is that tinc will set its configuration
|
||||
root to @file{@value{sysconfdir}/tinc/@var{netname}/}, where @var{netname} is your argument to the -n option.
|
||||
You will also notice that log messages it appears in syslog as coming from @file{tinc.@var{netname}},
|
||||
and on Linux, unless specified otherwise, the name of the virtual network interface will be the same as the network name.
|
||||
|
||||
However, it is not strictly necessary that you call tinc with the -n
|
||||
option. In this case, the network name would just be empty, and it will
|
||||
be used as such. tinc now looks for files in @file{@value{sysconfdir}/tinc/}, instead of
|
||||
@file{@value{sysconfdir}/tinc/@var{netname}/}; the configuration file should be @file{@value{sysconfdir}/tinc/tinc.conf},
|
||||
and the host configuration files are now expected to be in @file{@value{sysconfdir}/tinc/hosts/}.
|
||||
|
||||
But it is highly recommended that you use this feature of tinc, because
|
||||
it will be so much clearer whom your daemon talks to. Hence, we will
|
||||
assume that you use it.
|
||||
option. If you don not use it, the network name will just be empty, and
|
||||
tinc will look for files in @file{@value{sysconfdir}/tinc/} instead of
|
||||
@file{@value{sysconfdir}/tinc/@var{netname}/};
|
||||
the configuration file will then be @file{@value{sysconfdir}/tinc/tinc.conf},
|
||||
and the host configuration files are expected to be in @file{@value{sysconfdir}/tinc/hosts/}.
|
||||
|
||||
|
||||
@c ==================================================================
|
||||
|
@ -727,6 +732,25 @@ If you wish, you can view a tinc daemon without a `ConnectTo' value as a server,
|
|||
and one which does specify such a value as a client.
|
||||
It does not matter if two tinc daemons have a `ConnectTo' value pointing to each other however.
|
||||
|
||||
Connections specified using `ConnectTo' are so-called meta-connections.
|
||||
Tinc daemons exchange information about all other daemon they know about via these meta-connections.
|
||||
After learning about all the daemons in the VPN,
|
||||
tinc will create other connections as necessary in order to communicate with them.
|
||||
For example, if there are three daemons named A, B and C, and A has @samp{ConnectTo = B} in its tinc.conf file,
|
||||
and C has @samp{ConnectTo = B} in its tinc.conf file, then A will learn about C from B,
|
||||
and will be able to exchange VPN packets with C without the need to have @samp{ConnectTo = C} in its tinc.conf file.
|
||||
|
||||
It could be that some daemons are located behind a Network Address Translation (NAT) device, or behind a firewall.
|
||||
In the above scenario with three daemons, if A and C are behind a NAT,
|
||||
B will automatically help A and C punch holes through their NAT,
|
||||
in a way similar to the STUN protocol, so that A and C can still communicate with each other directly.
|
||||
It is not always possible to do this however, and firewalls might also prevent direct communication.
|
||||
In that case, VPN packets between A and C will be forwarded by B.
|
||||
|
||||
In effect, all nodes in the VPN will be able to talk to each other, as long as
|
||||
their is a path of meta-connections between them, and whenever possible, two
|
||||
nodes will communicate with each other directly.
|
||||
|
||||
|
||||
@c ==================================================================
|
||||
@node Configuration files
|
||||
|
@ -755,7 +779,10 @@ listed in this document can also be put in
|
|||
put host specific configuration options in the host configuration file, as this
|
||||
makes it easy to exchange with other nodes.
|
||||
|
||||
In this section all valid variables are listed in alphabetical order.
|
||||
You can edit the config file manually, but it is recommended that you use
|
||||
tincctl to change configuration variables for you.
|
||||
|
||||
In the following two subsections all valid variables are listed in alphabetical order.
|
||||
The default value is given between parentheses,
|
||||
other comments are between square brackets.
|
||||
|
||||
|
@ -779,12 +806,15 @@ If any is selected, then depending on the operating system
|
|||
both IPv4 and IPv6 or just IPv6 listening sockets will be created.
|
||||
|
||||
@cindex BindToAddress
|
||||
@item BindToAddress = <@var{address}> [experimental]
|
||||
@item BindToAddress = <@var{address}> [<@var{port}>]
|
||||
If your computer has more than one IPv4 or IPv6 address, tinc
|
||||
will by default listen on all of them for incoming connections.
|
||||
It is possible to bind only to a single address with this variable.
|
||||
Multiple BindToAddress variables may be specified,
|
||||
in which case listening sockets for each specified address are made.
|
||||
|
||||
This option may not work on all platforms.
|
||||
If no @var{port} is specified, the socket will be bound to the port specified by the Port option,
|
||||
or to port 655 if neither is given.
|
||||
To only bind to a specific port but not to a specific address, use "*" for the @var{address}.
|
||||
|
||||
@cindex BindToInterface
|
||||
@item BindToInterface = <@var{interface}> [experimental]
|
||||
|
@ -794,6 +824,27 @@ possible to bind tinc to a single interface like eth0 or ppp0 with this
|
|||
variable.
|
||||
|
||||
This option may not work on all platforms.
|
||||
Also, on some platforms it will not actually bind to an interface,
|
||||
but rather to the address that the interface has at the moment a socket is created.
|
||||
|
||||
@cindex Broadcast
|
||||
@item Broadcast = <no | mst | direct> (mst) [experimental]
|
||||
This option selects the way broadcast packets are sent to other daemons.
|
||||
@emph{NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form.}
|
||||
|
||||
@table @asis
|
||||
@item no
|
||||
Broadcast packets are never sent to other nodes.
|
||||
|
||||
@item mst
|
||||
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
|
||||
This ensures broadcast packets reach all nodes.
|
||||
|
||||
@item direct
|
||||
Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||
Broadcast packets received from other nodes are never forwarded.
|
||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||
@end table
|
||||
|
||||
@cindex ConnectTo
|
||||
@item ConnectTo = <@var{name}>
|
||||
|
@ -807,6 +858,15 @@ If you don't specify a host with ConnectTo,
|
|||
tinc won't try to connect to other daemons at all,
|
||||
and will instead just listen for incoming connections.
|
||||
|
||||
@cindex DecrementTTL
|
||||
@item DecrementTTL = <yes | no> (no) [experimental]
|
||||
When enabled, tinc will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
|
||||
before forwarding a received packet to the virtual network device or to another node,
|
||||
and will drop packets that have a TTL value of zero,
|
||||
in which case it will send an ICMP Time Exceeded packet back.
|
||||
|
||||
Do not use this option if you use switch mode and want to use IPv6.
|
||||
|
||||
@cindex Device
|
||||
@item Device = <@var{device}> (@file{/dev/tap0}, @file{/dev/net/tun} or other depending on platform)
|
||||
The virtual network device to use.
|
||||
|
@ -817,32 +877,72 @@ Note that you can only use one device per daemon.
|
|||
See also @ref{Device files}.
|
||||
|
||||
@cindex DeviceType
|
||||
@item DeviceType = <tun|tunnohead|tunifhead|tap> (only supported on BSD platforms)
|
||||
@item DeviceType = <@var{type}> (platform dependent)
|
||||
The type of the virtual network device.
|
||||
Tinc will normally automatically select the right type, and this option should not be used.
|
||||
However, in case tinc does not seem to correctly interpret packets received from the virtual network device,
|
||||
using this option might help.
|
||||
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
|
||||
However, this option can be used to select one of the special interface types, if support for them is compiled in.
|
||||
|
||||
@table @asis
|
||||
@item tun
|
||||
@cindex dummy
|
||||
@item dummy
|
||||
Use a dummy interface.
|
||||
No packets are ever read or written to a virtual network device.
|
||||
Useful for testing, or when setting up a node that only forwards packets for other nodes.
|
||||
|
||||
@cindex raw_socket
|
||||
@item raw_socket
|
||||
Open a raw socket, and bind it to a pre-existing
|
||||
@var{Interface} (eth0 by default).
|
||||
All packets are read from this interface.
|
||||
Packets received for the local node are written to the raw socket.
|
||||
However, at least on Linux, the operating system does not process IP packets destined for the local host.
|
||||
|
||||
@cindex multicast
|
||||
@item multicast
|
||||
Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using @var{Device}.
|
||||
Packets are read from and written to this multicast socket.
|
||||
This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address.
|
||||
Do NOT connect multiple tinc daemons to the same multicast address, this will very likely cause routing loops.
|
||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||
|
||||
@cindex UML
|
||||
@item uml (not compiled in by default)
|
||||
Create a UNIX socket with the filename specified by
|
||||
@var{Device}, or @file{@value{localstatedir}/run/@var{netname}.umlsocket}
|
||||
if not specified.
|
||||
Tinc will wait for a User Mode Linux instance to connect to this socket.
|
||||
|
||||
@cindex VDE
|
||||
@item vde (not compiled in by default)
|
||||
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
|
||||
using the UNIX socket specified by
|
||||
@var{Device}, or @file{@value{localstatedir}/run/vde.ctl}
|
||||
if not specified.
|
||||
@end table
|
||||
|
||||
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
|
||||
it can be used to change the way packets are interpreted:
|
||||
|
||||
@table @asis
|
||||
@item tun (BSD and Linux)
|
||||
Set type to tun.
|
||||
Depending on the platform, this can either be with or without an address family header (see below).
|
||||
|
||||
@cindex tunnohead
|
||||
@item tunnohead
|
||||
@item tunnohead (BSD)
|
||||
Set type to tun without an address family header.
|
||||
Tinc will expect packets read from the virtual network device to start with an IP header.
|
||||
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
|
||||
|
||||
@cindex tunifhead
|
||||
@item tunifhead
|
||||
@item tunifhead (BSD)
|
||||
Set type to tun with an address family header.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with a four byte header containing the address family,
|
||||
followed by an IP header.
|
||||
This mode should support both IPv4 and IPv6 packets.
|
||||
|
||||
@item tap
|
||||
@item tap (BSD and Linux)
|
||||
Set type to tap.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with an Ethernet header.
|
||||
|
@ -891,7 +991,7 @@ and can also help debugging.
|
|||
@end table
|
||||
|
||||
@cindex GraphDumpFile
|
||||
@item GraphDumpFile = <@var{filename}> [experimental]
|
||||
@item GraphDumpFile = <@var{filename}>
|
||||
If this option is present,
|
||||
tinc will dump the current network graph to the file @var{filename}
|
||||
every minute, unless there were no changes to the graph.
|
||||
|
@ -908,7 +1008,7 @@ tinc's efficiency, even stopping the daemon for a few seconds everytime
|
|||
it does a lookup if your DNS server is not responding.
|
||||
|
||||
This does not affect resolving hostnames to IP addresses from the
|
||||
configuration file.
|
||||
configuration file, but whether hostnames should be resolved while logging.
|
||||
|
||||
@cindex Interface
|
||||
@item Interface = <@var{interface}>
|
||||
|
@ -917,6 +1017,16 @@ Depending on the operating system and the type of device this may or may not act
|
|||
Under Windows, this variable is used to select which network interface will be used.
|
||||
If you specified a Device, this variable is almost always already correctly set.
|
||||
|
||||
@cindex LocalDiscovery
|
||||
@item LocalDiscovery = <yes | no> (no)
|
||||
When enabled, tinc will try to detect peers that are on the same local network.
|
||||
This will allow direct communication using LAN addresses, even if both peers are behind a NAT
|
||||
and they only ConnectTo a third node outside the NAT,
|
||||
which normally would prevent the peers from learning each other's LAN address.
|
||||
|
||||
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
|
||||
This feature may not work in all possible situations.
|
||||
|
||||
@cindex Mode
|
||||
@item Mode = <router|switch|hub> (router)
|
||||
This option selects the way packets are routed to other daemons.
|
||||
|
@ -963,6 +1073,11 @@ This only has effect when Mode is set to "switch".
|
|||
This is a symbolic name for this connection.
|
||||
The name should consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _).
|
||||
|
||||
If Name starts with a $, then the contents of the environment variable that follows will be used.
|
||||
In that case, invalid characters will be converted to underscores.
|
||||
If Name is $HOST, but no such environment variable exist,
|
||||
the hostname will be read using the gethostnname() system call.
|
||||
|
||||
@cindex PingInterval
|
||||
@item PingInterval = <@var{seconds}> (60)
|
||||
The number of seconds of inactivity that tinc will wait before sending a
|
||||
|
@ -1000,6 +1115,33 @@ specified in the configuration file.
|
|||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
@cindex Proxy
|
||||
@item Proxy = socks4 | socks4 | http | exec @var{...} [experimental]
|
||||
Use a proxy when making outgoing connections.
|
||||
The following proxy types are currently supported:
|
||||
|
||||
@table @asis
|
||||
@cindex socks4
|
||||
@item socks4 <@var{address}> <@var{port}> [<@var{username}>]
|
||||
Connects to the proxy using the SOCKS version 4 protocol.
|
||||
Optionally, a @var{username} can be supplied which will be passed on to the proxy server.
|
||||
|
||||
@cindex socks5
|
||||
@item socks4 <@var{address}> <@var{port}> [<@var{username}> <@var{password}>]
|
||||
Connect to the proxy using the SOCKS version 5 protocol.
|
||||
If a @var{username} and @var{password} are given, basic username/password authentication will be used,
|
||||
otherwise no authentication will be used.
|
||||
|
||||
@cindex http
|
||||
@item http <@var{address}> <@var{port}>
|
||||
Connects to the proxy and sends a HTTP CONNECT request.
|
||||
|
||||
@cindex exec
|
||||
@item exec <@var{command}>
|
||||
Executes the given command which should set up the outgoing connection.
|
||||
The environment variables @env{NAME}, @env{NODE}, @env{REMOTEADDRES} and @env{REMOTEPORT} are available.
|
||||
@end table
|
||||
|
||||
@cindex ReplayWindow
|
||||
@item ReplayWindow = <bytes> (16)
|
||||
This is the size of the replay tracking window for each remote node, in bytes.
|
||||
|
@ -1132,19 +1274,18 @@ Multiple subnet lines can be specified for each daemon.
|
|||
Subnets can either be single MAC, IPv4 or IPv6 addresses,
|
||||
in which case a subnet consisting of only that single address is assumed,
|
||||
or they can be a IPv4 or IPv6 network address with a prefixlength.
|
||||
Shorthand notations are not supported.
|
||||
For example, IPv4 subnets must be in a form like 192.168.1.0/24,
|
||||
where 192.168.1.0 is the network address and 24 is the number of bits set in the netmask.
|
||||
Note that subnets like 192.168.1.1/24 are invalid!
|
||||
Read a networking HOWTO/FAQ/guide if you don't understand this.
|
||||
IPv6 subnets are notated like fec0:0:0:1:0:0:0:0/64.
|
||||
IPv6 subnets are notated like fec0:0:0:1::/64.
|
||||
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
||||
|
||||
@cindex CIDR notation
|
||||
Prefixlength is the number of bits set to 1 in the netmask part; for
|
||||
example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes
|
||||
/22. This conforms to standard CIDR notation as described in
|
||||
@uref{ftp://ftp.isi.edu/in-notes/rfc1519.txt, RFC1519}
|
||||
@uref{http://www.ietf.org/rfc/rfc1519.txt, RFC1519}
|
||||
|
||||
A Subnet can be given a weight to indicate its priority over identical Subnets
|
||||
owned by different nodes. The default weight is 10. Lower values indicate
|
||||
|
@ -1254,50 +1395,115 @@ When a subnet becomes (un)reachable, this is set to the subnet.
|
|||
@node How to configure
|
||||
@subsection How to configure
|
||||
|
||||
@subsubheading Step 1. Creating the main configuration file
|
||||
@subsubheading Step 1. Creating initial configuration files.
|
||||
|
||||
The main configuration file will be called @file{@value{sysconfdir}/tinc/@var{netname}/tinc.conf}.
|
||||
Adapt the following example to create a basic configuration file:
|
||||
The initial directory structure, configuration files and public/private keypairs are created using the following command:
|
||||
|
||||
@example
|
||||
Name = @var{yourname}
|
||||
Device = @file{/dev/tap0}
|
||||
tincctl -n @var{netname} init @var{name}
|
||||
@end example
|
||||
|
||||
Then, if you know to which other tinc daemon(s) yours is going to connect,
|
||||
add `ConnectTo' values.
|
||||
|
||||
@subsubheading Step 2. Creating your host configuration file
|
||||
|
||||
If you added a line containing `Name = yourname' in the main configuarion file,
|
||||
you will need to create a host configuration file @file{@value{sysconfdir}/tinc/@var{netname}/hosts/yourname}.
|
||||
Adapt the following example to create a host configuration file:
|
||||
(You will need to run this as root, or use "sudo".)
|
||||
This will create the configuration directory @file{@value{sysconfdir}/tinc/@var{netname}.},
|
||||
and inside it will create another directory named @file{hosts/}.
|
||||
In the configuration directory, it will create the file @file{tinc.conf} with the following contents:
|
||||
|
||||
@example
|
||||
Address = your.real.hostname.org
|
||||
Subnet = 192.168.1.0/24
|
||||
Name = @var{name}
|
||||
@end example
|
||||
|
||||
You can also use an IP address instead of a hostname.
|
||||
The `Subnet' specifies the address range that is local for @emph{your part of the VPN only}.
|
||||
If you have multiple address ranges you can specify more than one `Subnet'.
|
||||
You might also need to add a `Port' if you want your tinc daemon to run on a different port number than the default (655).
|
||||
It will also create private RSA and ECDSA keys, which will be stored in the files @file{rsa_key.priv} and @file{ecdsa_key.priv}.
|
||||
It will also create a host configuration file @file{hosts/@var{name}},
|
||||
which will contain the corresponding public RSA and ECDSA keys.
|
||||
|
||||
Finally, on UNIX operating systems, it will create an executable script @file{tinc-up},
|
||||
which will initially not do anything except warning that you should edit it.
|
||||
|
||||
@c ==================================================================
|
||||
@node Generating keypairs
|
||||
@section Generating keypairs
|
||||
@subsubheading Step 2. Modifying the initial configuration.
|
||||
|
||||
@cindex key generation
|
||||
Now that you have already created the main configuration file and your host configuration file,
|
||||
you can easily create a public/private keypair by entering the following command:
|
||||
Unless you want to use tinc in switch mode,
|
||||
you should now configure which range of addresses you will use on the VPN.
|
||||
Let's assume you will be part of a VPN which uses the address range 192.168.0.0/16,
|
||||
and you yourself have a smaller portion of that range: 192.168.2.0/24.
|
||||
Then you should run the following command:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} generate-keys
|
||||
tincctl -n @var{netname} config add subnet 192.168.2.0/24
|
||||
@end example
|
||||
|
||||
Tinc will generate a public and a private key and ask you where to put them.
|
||||
Just press enter to accept the defaults.
|
||||
This will add a Subnet statement to your host configuration file.
|
||||
Try opening the file @file{@value{sysconfdir}/tinc/@var{netname}/hosts/@var{name}} in an editor.
|
||||
You should now see a file containing the public RSA and ECDSA keys (which looks like a bunch of random characters),
|
||||
and the following line at the bottom:
|
||||
|
||||
@example
|
||||
Subnet = 192.168.2.0/24
|
||||
@end example
|
||||
|
||||
If you will use more than one address range, you can add more Subnets.
|
||||
For example, if you also use the IPv6 subnet fec0:0:0:2::/64, you can add it as well:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} config add subnet fec0:0:0:2::/24
|
||||
@end example
|
||||
|
||||
This will add another line to the file @file{hosts/@var{name}}.
|
||||
If you make a mistake, you can undo it by simply using @samp{config del} instead of @samp{config add}.
|
||||
|
||||
If you want other tinc daemons to create meta-connections to your daemon,
|
||||
you should add your public IP address or hostname to your host configuration file.
|
||||
For example, if your hostname is foo.example.org, run:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} config add address foo.example.org
|
||||
@end example
|
||||
|
||||
If you already know to which daemons your daemon should make meta-connections,
|
||||
you should configure that now as well.
|
||||
Suppose you want to connect to a daemon named "bar", run:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} config add connectto bar
|
||||
@end example
|
||||
|
||||
Note that you specify the Name of the other daemon here, not an IP address or hostname!
|
||||
When you start tinc, and it tries to make a connection to "bar",
|
||||
it will look for a host configuration file named @file{hosts/bar},
|
||||
and will read Address statements and public keys from that file.
|
||||
|
||||
@subsubheading Step 2. Exchanging configuration files.
|
||||
|
||||
If your daemon has a ConnectTo = bar statement in its @file{tinc.conf} file,
|
||||
or if bar has a ConnectTo your daemon, then you both need each other's host configuration files.
|
||||
You should send @file{hosts/@var{name}} to bar, and bar should send you his file which you should move to @file{hosts/bar}.
|
||||
If you are on a UNIX platform, you can easily send an email containing the necessary information using the following command
|
||||
(assuming the owner of bar has the email address bar@@example.org):
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} export | mail -s "My config file" bar@@example.org
|
||||
@end example
|
||||
|
||||
If the owner of bar does the same to send his host configuration file to you,
|
||||
you can probably pipe his email through the following command,
|
||||
or you can just start this command in a terminal and copy&paste the email:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} import
|
||||
@end example
|
||||
|
||||
If you are the owner of bar yourself, and you have SSH access to that computer,
|
||||
you can also swap the host configuration files using the following commands:
|
||||
|
||||
@example
|
||||
tincctl -n @var{netname} export | ssh bar.example.org tincctl -n @var{netname} import
|
||||
ssh bar.example.org tincctl -n @var{netname} export | tincctl -n @var{netname} import
|
||||
@end example
|
||||
|
||||
You should repeat this for all nodes you ConnectTo, or which ConnectTo you.
|
||||
However, remember that you do not need to ConnectTo all nodes in the VPN;
|
||||
it is only necessary to create one or a few meta-connections,
|
||||
after the connections are made tinc will learn about all the other nodes in the VPN,
|
||||
and will automatically make other connections as necessary.
|
||||
|
||||
|
||||
@c ==================================================================
|
||||
|
@ -1320,21 +1526,31 @@ You can configure the network interface by putting ordinary ifconfig, route, and
|
|||
to a script named @file{@value{sysconfdir}/tinc/@var{netname}/tinc-up}.
|
||||
When tinc starts, this script will be executed. When tinc exits, it will execute the script named
|
||||
@file{@value{sysconfdir}/tinc/@var{netname}/tinc-down}, but normally you don't need to create that script.
|
||||
You can manually open the script in an editor, or use the following command:
|
||||
|
||||
An example @file{tinc-up} script:
|
||||
@example
|
||||
tincctl -n @var{netname} edit tinc-up
|
||||
@end example
|
||||
|
||||
An example @file{tinc-up} script, that would be appropriate for the scenario in the previous section, is:
|
||||
|
||||
@example
|
||||
#!/bin/sh
|
||||
ifconfig $INTERFACE 192.168.1.1 netmask 255.255.0.0
|
||||
ifconfig $INTERFACE 192.168.2.1 netmask 255.255.0.0
|
||||
ip addr add fec0:0:0:2::/48 dev $INTERFACE
|
||||
@end example
|
||||
|
||||
This script gives the interface an IP address and a netmask.
|
||||
The kernel will also automatically add a route to this interface, so normally you don't need
|
||||
The first command gives the interface an IPv4 address and a netmask.
|
||||
The kernel will also automatically add an IPv4 route to this interface, so normally you don't need
|
||||
to add route commands to the @file{tinc-up} script.
|
||||
The kernel will also bring the interface up after this command.
|
||||
@cindex netmask
|
||||
The netmask is the mask of the @emph{entire} VPN network, not just your
|
||||
own subnet.
|
||||
The second command gives the interface an IPv6 address and netmask,
|
||||
which will also automatically add an IPv6 route.
|
||||
If you only want to use "ip addr" commands on Linux, don't forget that it doesn't bring the interface up, unlike ifconfig,
|
||||
so you need to add @samp{ip link set $INTERFACE up} in that case.
|
||||
|
||||
The exact syntax of the ifconfig and route commands differs from platform to platform.
|
||||
You can look up the commands for setting addresses and adding routes in @ref{Platform specific information},
|
||||
|
@ -1374,6 +1590,9 @@ the real interface is also shown as a comment, to give you an idea of
|
|||
how these example host is set up. All branches use the netname `company'
|
||||
for this particular VPN.
|
||||
|
||||
Each branch is set up using the @samp{tincctl init} and @samp{tincctl config} commands,
|
||||
here we just show the end results:
|
||||
|
||||
@subsubheading For Branch A
|
||||
|
||||
@emph{BranchA} would be configured like this:
|
||||
|
@ -1381,6 +1600,8 @@ for this particular VPN.
|
|||
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
|
||||
|
||||
@example
|
||||
#!/bin/sh
|
||||
|
||||
# Real interface of internal network:
|
||||
# ifconfig eth0 10.1.54.1 netmask 255.255.0.0
|
||||
|
||||
|
@ -1391,7 +1612,6 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
|
|||
|
||||
@example
|
||||
Name = BranchA
|
||||
Device = /dev/tap0
|
||||
@end example
|
||||
|
||||
On all hosts, @file{@value{sysconfdir}/tinc/company/hosts/BranchA} contains:
|
||||
|
@ -1405,9 +1625,9 @@ Address = 1.2.3.4
|
|||
-----END RSA PUBLIC KEY-----
|
||||
@end example
|
||||
|
||||
Note that the IP addresses of eth0 and tap0 are the same.
|
||||
Note that the IP addresses of eth0 and the VPN interface are the same.
|
||||
This is quite possible, if you make sure that the netmasks of the interfaces are different.
|
||||
It is in fact recommended to give both real internal network interfaces and tap interfaces the same IP address,
|
||||
It is in fact recommended to give both real internal network interfaces and VPN interfaces the same IP address,
|
||||
since that will make things a lot easier to remember and set up.
|
||||
|
||||
|
||||
|
@ -1416,6 +1636,8 @@ since that will make things a lot easier to remember and set up.
|
|||
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
|
||||
|
||||
@example
|
||||
#!/bin/sh
|
||||
|
||||
# Real interface of internal network:
|
||||
# ifconfig eth0 10.2.43.8 netmask 255.255.0.0
|
||||
|
||||
|
@ -1430,7 +1652,7 @@ ConnectTo = BranchA
|
|||
@end example
|
||||
|
||||
Note here that the internal address (on eth0) doesn't have to be the
|
||||
same as on the tap0 device. Also, ConnectTo is given so that this node will
|
||||
same as on the VPN interface. Also, ConnectTo is given so that this node will
|
||||
always try to connect to BranchA.
|
||||
|
||||
On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchB}:
|
||||
|
@ -1450,6 +1672,8 @@ Address = 2.3.4.5
|
|||
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
|
||||
|
||||
@example
|
||||
#!/bin/sh
|
||||
|
||||
# Real interface of internal network:
|
||||
# ifconfig eth0 10.3.69.254 netmask 255.255.0.0
|
||||
|
||||
|
@ -1461,7 +1685,6 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
|
|||
@example
|
||||
Name = BranchC
|
||||
ConnectTo = BranchA
|
||||
Device = /dev/tap1
|
||||
@end example
|
||||
|
||||
C already has another daemon that runs on port 655, so they have to
|
||||
|
@ -1486,6 +1709,8 @@ Port = 2000
|
|||
In @file{@value{sysconfdir}/tinc/company/tinc-up}:
|
||||
|
||||
@example
|
||||
#!/bin/sh
|
||||
|
||||
# Real interface of internal network:
|
||||
# ifconfig eth0 10.4.3.32 netmask 255.255.0.0
|
||||
|
||||
|
@ -1497,14 +1722,10 @@ and in @file{@value{sysconfdir}/tinc/company/tinc.conf}:
|
|||
@example
|
||||
Name = BranchD
|
||||
ConnectTo = BranchC
|
||||
Device = /dev/net/tun
|
||||
@end example
|
||||
|
||||
D will be connecting to C, which has a tincd running for this network on
|
||||
port 2000. It knows the port number from the host configuration file.
|
||||
Also note that since D uses the tun/tap driver, the network interface
|
||||
will not be called `tun' or `tap0' or something like that, but will
|
||||
have the same name as netname.
|
||||
|
||||
On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchD}:
|
||||
|
||||
|
@ -1519,16 +1740,11 @@ Address = 4.5.6.7
|
|||
|
||||
@subsubheading Key files
|
||||
|
||||
A, B, C and D all have generated a public/private keypair with the following command:
|
||||
A, B, C and D all have their own public/private keypairs:
|
||||
|
||||
@example
|
||||
tincctl -n company generate-keys
|
||||
@end example
|
||||
|
||||
The private key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
|
||||
the public key is put into the host configuration file in the @file{@value{sysconfdir}/tinc/company/hosts/} directory.
|
||||
During key generation, tinc automatically guesses the right filenames based on the -n option and
|
||||
the Name directive in the @file{tinc.conf} file (if it is available).
|
||||
The private RSA key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
|
||||
the private ECDSA key is stored in @file{@value{sysconfdir}/tinc/company/ecdsa_key.priv},
|
||||
and the public RSA and ECDSA keys are put into the host configuration file in the @file{@value{sysconfdir}/tinc/company/hosts/} directory.
|
||||
|
||||
@subsubheading Starting
|
||||
|
||||
|
@ -1545,7 +1761,7 @@ their daemons, tinc will try connecting until they are available.
|
|||
If everything else is done, you can start tinc by typing the following command:
|
||||
|
||||
@example
|
||||
tincd -n @var{netname}
|
||||
tincctl -n @var{netname} start
|
||||
@end example
|
||||
|
||||
@cindex daemon
|
||||
|
@ -1600,6 +1816,12 @@ Store a cookie in @var{filename} which allows tincctl to authenticate.
|
|||
If unspecified, the default is
|
||||
@file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
|
||||
|
||||
@item -o, --option=[@var{HOST}.]@var{KEY}=@var{VALUE}
|
||||
Without specifying a @var{HOST}, this will set server configuration variable @var{KEY} to @var{VALUE}.
|
||||
If specified as @var{HOST}.@var{KEY}=@var{VALUE},
|
||||
this will set the host configuration variable @var{KEY} of the host named @var{HOST} to @var{VALUE}.
|
||||
This option can be used more than once to specify multiple configuration variables.
|
||||
|
||||
@item -L, --mlock
|
||||
Lock tinc into main memory.
|
||||
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
|
||||
|
@ -1868,6 +2090,7 @@ tincctl -n @var{netname} reload
|
|||
|
||||
@menu
|
||||
* tincctl runtime options::
|
||||
* tincctl environment variables::
|
||||
* tincctl commands::
|
||||
* tincctl examples::
|
||||
* tincctl top::
|
||||
|
@ -1900,6 +2123,16 @@ Output version information and exit.
|
|||
|
||||
@end table
|
||||
|
||||
@c ==================================================================
|
||||
@node tincctl environment variables
|
||||
@section tincctl environment variables
|
||||
|
||||
@table @env
|
||||
@cindex NETNAME
|
||||
@item NETNAME
|
||||
If no netname is specified on the command line with the @option{-n} option,
|
||||
the value of this environment variable is used.
|
||||
@end table
|
||||
|
||||
@c ==================================================================
|
||||
@node tincctl commands
|
||||
|
@ -1908,8 +2141,43 @@ Output version information and exit.
|
|||
@c from the manpage
|
||||
@table @code
|
||||
|
||||
@item start
|
||||
Start @samp{tincd}.
|
||||
@item init [@var{name}]
|
||||
Create initial configuration files and RSA and ECDSA keypairs with default length.
|
||||
If no @var{name} for this node is given, it will be asked for.
|
||||
|
||||
@item config [get] @var{variable}
|
||||
Print the current value of configuration variable @var{variable}.
|
||||
If more than one variable with the same name exists,
|
||||
the value of each of them will be printed on a separate line.
|
||||
|
||||
@item config [set] @var{variable} @var{value}
|
||||
Set configuration variable @var{variable} to the given @var{value}.
|
||||
All previously existing configuration variables with the same name are removed.
|
||||
To set a variable for a specific host, use the notation @var{host}.@var{variable}.
|
||||
|
||||
@item config add @var{variable} @var{value}
|
||||
As above, but without removing any previously existing configuration variables.
|
||||
|
||||
@item config del @var{variable} [@var{value}]
|
||||
Remove configuration variables with the same name and @var{value}.
|
||||
If no @var{value} is given, all configuration variables with the same name will be removed.
|
||||
|
||||
@item edit @var{filename}
|
||||
Start an editor for the given configuration file.
|
||||
You do not need to specify the full path to the file.
|
||||
|
||||
@item export
|
||||
Export the host configuration file of the local node to standard output.
|
||||
|
||||
@item export-all
|
||||
Export all host configuration files to standard output.
|
||||
|
||||
@item import [--force]
|
||||
Import host configuration file(s) from standard input.
|
||||
Already existing host configuration files are not overwritten unless the option --force is used.
|
||||
|
||||
@item start [tincd options]
|
||||
Start @samp{tincd}, optionally with the given extra options.
|
||||
|
||||
@item stop
|
||||
Stop @samp{tincd}.
|
||||
|
@ -1943,8 +2211,15 @@ Dump a list of all known subnets in the VPN.
|
|||
@item dump connections
|
||||
Dump a list of all meta connections with ourself.
|
||||
|
||||
@item dump graph
|
||||
@item dump graph | digraph
|
||||
Dump a graph of the VPN in dotty format.
|
||||
Nodes are colored according to their reachability:
|
||||
red nodes are unreachable, orange nodes are indirectly reachable, green nodes are directly reachable.
|
||||
Black nodes are either directly or indirectly reachable, but direct reachability has not been tried yet.
|
||||
|
||||
@item info @var{node} | @var{subnet} | @var{address}
|
||||
Show information about a particular @var{node}, @var{subnet} or @var{address}.
|
||||
If an @var{address} is given, any matching subnet will be shown.
|
||||
|
||||
@item purge
|
||||
Purges all information remembered about unreachable nodes.
|
||||
|
@ -1952,6 +2227,10 @@ Purges all information remembered about unreachable nodes.
|
|||
@item debug @var{level}
|
||||
Sets debug level to @var{level}.
|
||||
|
||||
@item log [@var{level}]
|
||||
Capture log messages from a running tinc daemon.
|
||||
An optional debug level can be given that will be applied only for log messages sent to tincctl.
|
||||
|
||||
@item retry
|
||||
Forces tinc to try to connect to all uplinks immediately.
|
||||
Usually tinc attempts to do this itself,
|
||||
|
@ -1986,6 +2265,16 @@ tincctl -n vpn pcap | tcpdump -r -
|
|||
tincctl -n vpn top
|
||||
@end example
|
||||
|
||||
Example of configuring tinc using tincctl:
|
||||
|
||||
@example
|
||||
tincctl -n vpn init foo
|
||||
tincctl -n vpn config Subnet 192.168.1.0/24
|
||||
tincctl -n vpn config bar.Address bar.example.com
|
||||
tincctl -n vpn config ConnectTo bar
|
||||
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@@example.com
|
||||
@end example
|
||||
|
||||
@c ==================================================================
|
||||
@node tincctl top
|
||||
@section tincctl top
|
||||
|
@ -2531,7 +2820,6 @@ For IPv4 addresses:
|
|||
@tab @code{netsh interface ip set address} @var{interface} @code{static} @var{address} @var{netmask}
|
||||
@end multitable
|
||||
|
||||
|
||||
For IPv6 addresses:
|
||||
|
||||
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
|
||||
|
@ -2553,6 +2841,22 @@ For IPv6 addresses:
|
|||
@tab @code{netsh interface ipv6 add address} @var{interface} @code{static} @var{address}/@var{prefixlength}
|
||||
@end multitable
|
||||
|
||||
On some platforms, when running tinc in switch mode, the VPN interface must be set to tap mode with an ifconfig command:
|
||||
|
||||
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
|
||||
@item OpenBSD
|
||||
@tab @code{ifconfig} @var{interface} @code{link0}
|
||||
@end multitable
|
||||
|
||||
On Linux, it is possible to create a persistent tun/tap interface which will
|
||||
continue to exist even if tinc quit, although this is normally not required.
|
||||
It can be useful to set up a tun/tap interface owned by a non-root user, so
|
||||
tinc can be started without needing any root privileges at all.
|
||||
|
||||
@multitable {Darwin (MacOS/X)} {ifconfig route add -bla network address netmask netmask prefixlength interface}
|
||||
@item Linux
|
||||
@tab @code{ip tuntap add dev} @var{interface} @code{mode} @var{tun|tap} @code{user} @var{username}
|
||||
@end multitable
|
||||
|
||||
@c ==================================================================
|
||||
@node Routes
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.Dd 2011-06-25
|
||||
.Dd 2012-10-14
|
||||
.Dt TINCCTL 8
|
||||
.\" Manual page created by:
|
||||
.\" Scott Lamb
|
||||
|
@ -37,12 +37,58 @@ Display short list of options.
|
|||
.It Fl -version
|
||||
Output version information and exit.
|
||||
.El
|
||||
.Sh ENVIRONMENT VARIABLES
|
||||
.Bl -tag -width indent
|
||||
.It Ev NETNAME
|
||||
If no netname is specified on the command line with the
|
||||
.Fl n
|
||||
option, the value of this environment variable is used.
|
||||
.El
|
||||
.Sh COMMANDS
|
||||
.zZ
|
||||
.Bl -tag -width indent
|
||||
.It start
|
||||
.It init Op Ar name
|
||||
Create initial configuration files and RSA and ECDSA keypairs with default length.
|
||||
If no
|
||||
.Ar name
|
||||
for this node is given, it will be asked for.
|
||||
.It config Oo get Oc Ar variable
|
||||
Print the current value of configuration variable
|
||||
.Ar variable .
|
||||
If more than one variable with the same name exists,
|
||||
the value of each of them will be printed on a separate line.
|
||||
.It config Oo set Oc Ar variable Ar value
|
||||
Set configuration variable
|
||||
.Ar variable
|
||||
to the given
|
||||
.Ar value .
|
||||
All previously existing configuration variables with the same name are removed.
|
||||
To set a variable for a specific host, use the notation
|
||||
.Ar host Ns Li . Ns Ar variable .
|
||||
.It config add Ar variable Ar value
|
||||
As above, but without removing any previously existing configuration variables.
|
||||
.It config del Ar variable Op Ar value
|
||||
Remove configuration variables with the same name and
|
||||
.Ar value .
|
||||
If no
|
||||
.Ar value
|
||||
is given, all configuration variables with the same name will be removed.
|
||||
.It edit Ar filename
|
||||
Start an editor for the given configuration file.
|
||||
You do not need to specify the full path to the file.
|
||||
.It export
|
||||
Export the host configuration file of the local node to standard output.
|
||||
.It export-all
|
||||
Export all host configuration files to standard output.
|
||||
.It import Op Fl -force
|
||||
Import host configuration file(s) from standard input.
|
||||
Already existing host configuration files are not overwritten unless the option
|
||||
.Fl -force
|
||||
is used.
|
||||
.It start Op tincd options
|
||||
Start
|
||||
.Xr tincd 8 .
|
||||
.Xr tincd 8 ,
|
||||
optionally with the given extra options.
|
||||
.It stop
|
||||
Stop
|
||||
.Xr tincd 8 .
|
||||
|
@ -69,6 +115,7 @@ If
|
|||
is omitted, the default length will be 2048 bits.
|
||||
When saving keys to existing files, tinc will not delete the old keys;
|
||||
you have to remove them manually.
|
||||
|
||||
.It dump nodes
|
||||
Dump a list of all known nodes in the VPN.
|
||||
.It dump edges
|
||||
|
@ -77,15 +124,25 @@ Dump a list of all known connections in the VPN.
|
|||
Dump a list of all known subnets in the VPN.
|
||||
.It dump connections
|
||||
Dump a list of all meta connections with ourself.
|
||||
.It dump graph
|
||||
.It dump graph | digraph
|
||||
Dump a graph of the VPN in
|
||||
.Xr dotty 1
|
||||
format.
|
||||
Nodes are colored according to their reachability:
|
||||
red nodes are unreachable, orange nodes are indirectly reachable, green nodes are directly reachable.
|
||||
Black nodes are either directly or indirectly reachable, but direct reachability has not been tried yet.
|
||||
.It info Ar node | subnet | address
|
||||
Show information about a particular node, subnet or address.
|
||||
If an address is given, any matching subnet will be shown.
|
||||
.It purge
|
||||
Purges all information remembered about unreachable nodes.
|
||||
.It debug Ar N
|
||||
Sets debug level to
|
||||
.Ar N .
|
||||
.It log Op Ar N
|
||||
Capture log messages from a running tinc daemon.
|
||||
An optional debug level can be given that will be applied only for log messages sent to
|
||||
.Nm tincctl .
|
||||
.It retry
|
||||
Forces
|
||||
.Xr tincd 8
|
||||
|
@ -123,7 +180,16 @@ Examples of some commands:
|
|||
tincctl -n vpn dump graph | circo -Txlib
|
||||
tincctl -n vpn pcap | tcpdump -r -
|
||||
tincctl -n vpn top
|
||||
.Pp
|
||||
.Ed
|
||||
Example of configuring tinc using
|
||||
.Nm :
|
||||
.Bd -literal -offset indent
|
||||
tincctl -n vpn init foo
|
||||
tincctl -n vpn config Subnet 192.168.1.0/24
|
||||
tincctl -n vpn config bar.Address bar.example.com
|
||||
tincctl -n vpn config ConnectTo bar
|
||||
tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com
|
||||
.Sh TOP
|
||||
The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters.
|
||||
It displays a list of all the known nodes in the left-most column,
|
||||
|
@ -172,7 +238,7 @@ If you find any bugs, report them to tinc@tinc-vpn.org.
|
|||
.Xr tincd 8 ,
|
||||
.Xr tinc.conf 5 ,
|
||||
.Xr dotty 1 ,
|
||||
.Xr pcap-savefile 7 ,
|
||||
.Xr pcap-savefile 5 ,
|
||||
.Xr tcpdump 8 ,
|
||||
.Xr top 1 ,
|
||||
.Pa http://www.tinc-vpn.org/ ,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.Dd 2011-06-25
|
||||
.Dd 2012-02-22
|
||||
.Dt TINCD 8
|
||||
.\" Manual page created by:
|
||||
.\" Ivo Timmermans
|
||||
|
@ -8,11 +8,12 @@
|
|||
.Nd tinc VPN daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl cdDKnLRU
|
||||
.Op Fl cdDKnoLRU
|
||||
.Op Fl -config Ns = Ns Ar DIR
|
||||
.Op Fl -no-detach
|
||||
.Op Fl -debug Ns Op = Ns Ar LEVEL
|
||||
.Op Fl -net Ns = Ns Ar NETNAME
|
||||
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||
.Op Fl -mlock
|
||||
.Op Fl -logfile Ns Op = Ns Ar FILE
|
||||
.Op Fl -bypass-security
|
||||
|
@ -61,6 +62,22 @@ for
|
|||
.Ar NETNAME
|
||||
is the same as not specifying any
|
||||
.Ar NETNAME .
|
||||
.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||
Without specifying a
|
||||
.Ar HOST ,
|
||||
this will set server configuration variable
|
||||
.Ar KEY
|
||||
to
|
||||
.Ar VALUE .
|
||||
If specified as
|
||||
.Ar HOST.KEY=VALUE ,
|
||||
this will set the host configuration variable
|
||||
.Ar KEY
|
||||
of the host named
|
||||
.Ar HOST
|
||||
to
|
||||
.Ar VALUE .
|
||||
This option can be used more than once to specify multiple configuration variables.
|
||||
.It Fl L, -mlock
|
||||
Lock tinc into main memory.
|
||||
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -16,6 +16,23 @@
|
|||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
|
@ -41,7 +58,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
|
@ -69,10 +87,21 @@ am__nobase_list = $(am__nobase_strip_setup); \
|
|||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(bindir)"
|
||||
SCRIPTS = $(dist_bin_SCRIPTS)
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
|
@ -122,6 +151,7 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
|
@ -213,8 +243,11 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
|||
$(am__aclocal_m4_deps):
|
||||
install-dist_binSCRIPTS: $(dist_bin_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
|
||||
@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
|
||||
|
@ -242,9 +275,7 @@ uninstall-dist_binSCRIPTS:
|
|||
@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
|
||||
files=`for p in $$list; do echo "$$p"; done | \
|
||||
sed -e 's,.*/,,;$(transform)'`; \
|
||||
test -n "$$list" || exit 0; \
|
||||
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(bindir)" && rm -f $$files
|
||||
dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
|
||||
tags: TAGS
|
||||
TAGS:
|
||||
|
||||
|
@ -299,10 +330,15 @@ install-am: all-am
|
|||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
|
181
gui/tinc-gui
181
gui/tinc-gui
|
@ -1,12 +1,35 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# tinc-gui -- GUI for controlling a running tincd
|
||||
# Copyright (C) 2009-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import string
|
||||
import socket
|
||||
import wx
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
from wx.lib.mixins.listctrl import ColumnSorterMixin
|
||||
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
|
||||
|
||||
if platform.system == 'Windows':
|
||||
import _winreg
|
||||
|
||||
# Classes to interface with a running tinc daemon
|
||||
|
||||
REQ_STOP = 0
|
||||
|
@ -30,34 +53,32 @@ CONTROL = 18
|
|||
class Node:
|
||||
def parse(self, args):
|
||||
self.name = args[0]
|
||||
self.address = args[2]
|
||||
if args[3] != 'port':
|
||||
args.insert(3, 'port')
|
||||
args.insert(4, '')
|
||||
self.port = args[4]
|
||||
self.cipher = int(args[6])
|
||||
self.digest = int(args[8])
|
||||
self.maclength = int(args[10])
|
||||
self.compression = int(args[12])
|
||||
self.options = int(args[14], 0x10)
|
||||
self.status = int(args[16], 0x10)
|
||||
self.nexthop = args[18]
|
||||
self.via = args[20]
|
||||
self.distance = int(args[22])
|
||||
self.pmtu = int(args[24])
|
||||
self.minmtu = int(args[26])
|
||||
self.maxmtu = int(args[28][:-1])
|
||||
self.address = args[1]
|
||||
self.port = args[3]
|
||||
self.cipher = int(args[4])
|
||||
self.digest = int(args[5])
|
||||
self.maclength = int(args[6])
|
||||
self.compression = int(args[7])
|
||||
self.options = int(args[8], 0x10)
|
||||
self.status = int(args[9], 0x10)
|
||||
self.nexthop = args[10]
|
||||
self.via = args[11]
|
||||
self.distance = int(args[12])
|
||||
self.pmtu = int(args[13])
|
||||
self.minmtu = int(args[14])
|
||||
self.maxmtu = int(args[15])
|
||||
self.last_state_change = float(args[16])
|
||||
|
||||
self.subnets = {}
|
||||
|
||||
class Edge:
|
||||
def parse(self, args):
|
||||
self.fr = args[0]
|
||||
self.to = args[2]
|
||||
self.address = args[4]
|
||||
self.port = args[6]
|
||||
self.options = int(args[8], 16)
|
||||
self.weight = int(args[10])
|
||||
self.to = args[1]
|
||||
self.address = args[2]
|
||||
self.port = args[4]
|
||||
self.options = int(args[5], 16)
|
||||
self.weight = int(args[6])
|
||||
|
||||
class Subnet:
|
||||
def parse(self, args):
|
||||
|
@ -73,19 +94,16 @@ class Subnet:
|
|||
self.address = address
|
||||
self.prefixlen = '48'
|
||||
|
||||
self.owner = args[2]
|
||||
self.owner = args[1]
|
||||
|
||||
class Connection:
|
||||
def parse(self, args):
|
||||
self.name = args[0]
|
||||
self.address = args[2]
|
||||
if args[3] != 'port':
|
||||
args.insert(3, 'port')
|
||||
args.insert(4, '')
|
||||
self.port = args[4]
|
||||
self.options = int(args[6], 0x10)
|
||||
self.socket = int(args[8])
|
||||
self.status = int(args[10], 0x10)
|
||||
self.address = args[1]
|
||||
self.port = args[3]
|
||||
self.options = int(args[4], 0x10)
|
||||
self.socket = int(args[5])
|
||||
self.status = int(args[6], 0x10)
|
||||
self.weight = 123
|
||||
|
||||
class VPN:
|
||||
|
@ -132,34 +150,34 @@ class VPN:
|
|||
if resp[0] != '18':
|
||||
break
|
||||
if resp[1] == '3':
|
||||
if len(resp) < 3:
|
||||
if len(resp) < 19:
|
||||
continue
|
||||
node = self.nodes.get(resp[2]) or Node()
|
||||
node.parse(resp[2:])
|
||||
node.visited = True
|
||||
self.nodes[resp[2]] = node
|
||||
elif resp[1] == '4':
|
||||
if len(resp) < 5:
|
||||
if len(resp) < 9:
|
||||
continue
|
||||
edge = self.nodes.get((resp[2], resp[4])) or Edge()
|
||||
edge = self.nodes.get((resp[2], resp[3])) or Edge()
|
||||
edge.parse(resp[2:])
|
||||
edge.visited = True
|
||||
self.edges[(resp[2], resp[4])] = edge
|
||||
self.edges[(resp[2], resp[3])] = edge
|
||||
elif resp[1] == '5':
|
||||
if len(resp) < 5:
|
||||
if len(resp) < 4:
|
||||
continue
|
||||
subnet = self.subnets.get((resp[2], resp[4])) or Subnet()
|
||||
subnet = self.subnets.get((resp[2], resp[3])) or Subnet()
|
||||
subnet.parse(resp[2:])
|
||||
subnet.visited = True
|
||||
self.subnets[(resp[2], resp[4])] = subnet
|
||||
self.subnets[(resp[2], resp[3])] = subnet
|
||||
self.nodes[subnet.owner].subnets[resp[2]] = subnet
|
||||
elif resp[1] == '6':
|
||||
if len(resp) < 5:
|
||||
if len(resp) < 9:
|
||||
break
|
||||
connection = self.connections.get((resp[2], resp[4])) or Connection()
|
||||
connection = self.connections.get((resp[2], resp[3], resp[5])) or Connection()
|
||||
connection.parse(resp[2:])
|
||||
connection.visited = True
|
||||
self.connections[(resp[2], resp[4])] = connection
|
||||
self.connections[(resp[2], resp[3], resp[5])] = connection
|
||||
else:
|
||||
break
|
||||
|
||||
|
@ -198,27 +216,38 @@ class VPN:
|
|||
return int(resp[2])
|
||||
|
||||
def __init__(self, netname = None, pidfile = None):
|
||||
self.tincconf = VPN.confdir + '/'
|
||||
if platform.system == 'Windows':
|
||||
try:
|
||||
reg = _winreg.ConnectRegistry(None, HKEY_LOCAL_MACHINE)
|
||||
key = _winreg.OpenKey(reg, "SOFTWARE\\tinc")
|
||||
VPN.confdir = _winreg.QueryValue(key, None)
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
if netname:
|
||||
self.netname = netname
|
||||
self.tincconf += netname + '/'
|
||||
self.confbase = os.path.join(VPN.confdir, netname)
|
||||
else:
|
||||
self.confbase = VPN.confdir
|
||||
|
||||
self.tincconf += 'tinc.conf'
|
||||
self.tincconf = os.path.join(self.confbase, 'tinc.conf')
|
||||
|
||||
if pidfile is not None:
|
||||
if pidfile != None:
|
||||
self.pidfile = pidfile
|
||||
else:
|
||||
self.pidfile = VPN.piddir + 'tinc.'
|
||||
if platform.system == 'Windows':
|
||||
self.pidfile = os.path.join(self.confbase, 'pid')
|
||||
else:
|
||||
if netname:
|
||||
self.pidfile += netname + '.'
|
||||
self.pidfile += 'pid'
|
||||
self.pidfile = os.path.join(VPN.piddir, 'tinc.' + netname + '.pid')
|
||||
else:
|
||||
self.pidfile = os.path.join(VPN.piddir, 'tinc.pid')
|
||||
|
||||
# GUI starts here
|
||||
|
||||
argv0 = sys.argv[0]
|
||||
del sys.argv[0]
|
||||
net = None
|
||||
netname = None
|
||||
pidfile = None
|
||||
|
||||
def usage(exitcode = 0):
|
||||
|
@ -230,10 +259,10 @@ def usage(exitcode = 0):
|
|||
print('\nReport bugs to tinc@tinc-vpn.org.')
|
||||
sys.exit(exitcode)
|
||||
|
||||
while len(sys.argv):
|
||||
while sys.argv:
|
||||
if sys.argv[0] in ('-n', '--net'):
|
||||
del sys.argv[0]
|
||||
net = sys.argv[0]
|
||||
netname = sys.argv[0]
|
||||
elif sys.argv[0] in ('--pidfile'):
|
||||
del sys.argv[0]
|
||||
pidfile = sys.argv[0]
|
||||
|
@ -245,14 +274,20 @@ while len(sys.argv):
|
|||
|
||||
del sys.argv[0]
|
||||
|
||||
vpn = VPN(net, pidfile)
|
||||
if netname == None:
|
||||
netname = os.getenv("NETNAME")
|
||||
|
||||
if netname == ".":
|
||||
netname = None
|
||||
|
||||
vpn = VPN(netname, pidfile)
|
||||
vpn.connect()
|
||||
|
||||
class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin):
|
||||
def __init__(self, parent, style):
|
||||
wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
|
||||
ListCtrlAutoWidthMixin.__init__(self)
|
||||
ColumnSorterMixin.__init__(self, 14)
|
||||
ColumnSorterMixin.__init__(self, 16)
|
||||
|
||||
def GetListCtrl(self):
|
||||
return self
|
||||
|
@ -265,12 +300,12 @@ class SettingsPage(wx.Panel):
|
|||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
grid = wx.FlexGridSizer(cols = 2)
|
||||
grid.AddGrowableCol(0, 1)
|
||||
grid.AddGrowableCol(1, 1)
|
||||
|
||||
namelabel = wx.StaticText(self, -1, 'Name:')
|
||||
self.name = wx.TextCtrl(self, -1, vpn.name)
|
||||
grid.Add(namelabel)
|
||||
grid.Add(self.name)
|
||||
grid.Add(self.name, 1, wx.EXPAND)
|
||||
|
||||
portlabel = wx.StaticText(self, -1, 'Port:')
|
||||
self.port = wx.TextCtrl(self, -1, vpn.port)
|
||||
|
@ -293,7 +328,7 @@ class SettingsPage(wx.Panel):
|
|||
class ConnectionsPage(wx.Panel):
|
||||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
|
||||
self.list = SuperListCtrl(self, id)
|
||||
self.list.InsertColumn(0, 'Name')
|
||||
self.list.InsertColumn(1, 'Address')
|
||||
self.list.InsertColumn(2, 'Port')
|
||||
|
@ -323,6 +358,7 @@ class ConnectionsPage(wx.Panel):
|
|||
self.PopupMenu(self.ContextMenu(self.list.itemDataMap[event.GetIndex()]), event.GetPosition())
|
||||
|
||||
def refresh(self):
|
||||
sortstate = self.list.GetSortState()
|
||||
self.list.itemDataMap = {}
|
||||
i = 0
|
||||
|
||||
|
@ -337,11 +373,13 @@ class ConnectionsPage(wx.Panel):
|
|||
self.list.SetStringItem(i, 4, str(connection.weight))
|
||||
self.list.itemDataMap[i] = (connection.name, connection.address, connection.port, connection.options, connection.weight)
|
||||
self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContext)
|
||||
self.list.SetItemData(i, i)
|
||||
i += 1
|
||||
|
||||
while self.list.GetItemCount() > i:
|
||||
self.list.DeleteItem(self.list.GetItemCount() - 1)
|
||||
|
||||
self.list.SortListItems(sortstate[0], sortstate[1])
|
||||
|
||||
class NodesPage(wx.Panel):
|
||||
def __init__(self, parent, id):
|
||||
|
@ -362,6 +400,7 @@ class NodesPage(wx.Panel):
|
|||
self.list.InsertColumn(12, 'PMTU')
|
||||
self.list.InsertColumn(13, 'Min MTU')
|
||||
self.list.InsertColumn(14, 'Max MTU')
|
||||
self.list.InsertColumn(15, 'Since')
|
||||
|
||||
hbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
hbox.Add(self.list, 1, wx.EXPAND)
|
||||
|
@ -369,6 +408,7 @@ class NodesPage(wx.Panel):
|
|||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
sortstate = self.list.GetSortState()
|
||||
self.list.itemDataMap = {}
|
||||
i = 0
|
||||
|
||||
|
@ -383,25 +423,32 @@ class NodesPage(wx.Panel):
|
|||
self.list.SetStringItem(i, 4, str(node.digest))
|
||||
self.list.SetStringItem(i, 5, str(node.maclength))
|
||||
self.list.SetStringItem(i, 6, str(node.compression))
|
||||
self.list.SetStringItem(i, 7, str(node.options))
|
||||
self.list.SetStringItem(i, 8, str(node.status))
|
||||
self.list.SetStringItem(i, 7, format(node.options, "x"))
|
||||
self.list.SetStringItem(i, 8, format(node.status, "04x"))
|
||||
self.list.SetStringItem(i, 9, node.nexthop)
|
||||
self.list.SetStringItem(i, 10, node.via)
|
||||
self.list.SetStringItem(i, 11, str(node.distance))
|
||||
self.list.SetStringItem(i, 12, str(node.pmtu))
|
||||
self.list.SetStringItem(i, 13, str(node.minmtu))
|
||||
self.list.SetStringItem(i, 14, str(node.maxmtu))
|
||||
self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu)
|
||||
if node.last_state_change:
|
||||
since = time.strftime("%Y-%m-%d %H:%M", time.localtime(node.last_state_change))
|
||||
else:
|
||||
since = "never"
|
||||
self.list.SetStringItem(i, 15, since)
|
||||
self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu, since)
|
||||
self.list.SetItemData(i, i)
|
||||
i += 1
|
||||
|
||||
while self.list.GetItemCount() > i:
|
||||
self.list.DeleteItem(self.list.GetItemCount() - 1)
|
||||
|
||||
self.list.SortListItems(sortstate[0], sortstate[1])
|
||||
|
||||
class EdgesPage(wx.Panel):
|
||||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
|
||||
self.list = SuperListCtrl(self, id)
|
||||
self.list.InsertColumn(0, 'From')
|
||||
self.list.InsertColumn(1, 'To')
|
||||
self.list.InsertColumn(2, 'Address')
|
||||
|
@ -415,6 +462,7 @@ class EdgesPage(wx.Panel):
|
|||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
sortstate = self.list.GetSortState()
|
||||
self.list.itemDataMap = {}
|
||||
i = 0
|
||||
|
||||
|
@ -426,14 +474,17 @@ class EdgesPage(wx.Panel):
|
|||
self.list.SetStringItem(i, 1, edge.to)
|
||||
self.list.SetStringItem(i, 2, edge.address)
|
||||
self.list.SetStringItem(i, 3, edge.port)
|
||||
self.list.SetStringItem(i, 4, str(edge.options))
|
||||
self.list.SetStringItem(i, 4, format(edge.options, "x"))
|
||||
self.list.SetStringItem(i, 5, str(edge.weight))
|
||||
self.list.itemDataMap[i] = (edge.fr, edge.to, edge.address, edge.port, edge.options, edge.weight)
|
||||
self.list.SetItemData(i, i)
|
||||
i += 1
|
||||
|
||||
while self.list.GetItemCount() > i:
|
||||
self.list.DeleteItem(self.list.GetItemCount() - 1)
|
||||
|
||||
self.list.SortListItems(sortstate[0], sortstate[1])
|
||||
|
||||
class SubnetsPage(wx.Panel):
|
||||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
|
@ -447,6 +498,7 @@ class SubnetsPage(wx.Panel):
|
|||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
sortstate = self.list.GetSortState()
|
||||
self.list.itemDataMap = {}
|
||||
i = 0
|
||||
|
||||
|
@ -458,11 +510,14 @@ class SubnetsPage(wx.Panel):
|
|||
self.list.SetStringItem(i, 1, subnet.weight)
|
||||
self.list.SetStringItem(i, 2, subnet.owner)
|
||||
self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner)
|
||||
i = i + 1
|
||||
self.list.SetItemData(i, i)
|
||||
i += 1
|
||||
|
||||
while self.list.GetItemCount() > i:
|
||||
self.list.DeleteItem(self.list.GetItemCount() - 1)
|
||||
|
||||
self.list.SortListItems(sortstate[0], sortstate[1])
|
||||
|
||||
class StatusPage(wx.Panel):
|
||||
def __init__(self, parent, id):
|
||||
wx.Panel.__init__(self, parent, id)
|
||||
|
@ -493,7 +548,7 @@ class NetPage(wx.Notebook):
|
|||
|
||||
class MainWindow(wx.Frame):
|
||||
def OnQuit(self, event):
|
||||
self.Close(True)
|
||||
app.ExitMainLoop()
|
||||
|
||||
def OnTimer(self, event):
|
||||
vpn.refresh()
|
||||
|
|
9
have.h
9
have.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
have.h -- include headers which are known to exist
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2003-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2003-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,6 +42,7 @@
|
|||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
@ -199,4 +200,10 @@
|
|||
#include <event.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#define SLASH "\\"
|
||||
#else
|
||||
#define SLASH "/"
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_SYSTEM_H__ */
|
||||
|
|
29
install-sh
29
install-sh
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
scriptversion=2011-01-19.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
|
@ -156,6 +156,10 @@ while test $# -ne 0; do
|
|||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
@ -186,6 +190,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
|||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
|
@ -200,7 +208,11 @@ if test $# -eq 0; then
|
|||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
|
@ -228,9 +240,9 @@ fi
|
|||
|
||||
for src
|
||||
do
|
||||
# Protect names starting with `-'.
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $src in
|
||||
-*) src=./$src;;
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
|
@ -252,12 +264,7 @@ do
|
|||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dst=$dst_arg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
|
@ -385,7 +392,7 @@ do
|
|||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
-*) prefix='./';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
|
@ -403,7 +410,7 @@ do
|
|||
|
||||
for d
|
||||
do
|
||||
test -z "$d" && continue
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -15,6 +15,23 @@
|
|||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
|
@ -39,7 +56,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
|
@ -48,6 +66,11 @@ CONFIG_CLEAN_FILES =
|
|||
CONFIG_CLEAN_VPATH_FILES =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
|
@ -97,6 +120,7 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
|
@ -236,10 +260,15 @@ install-am: all-am
|
|||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
|
|
@ -35,7 +35,7 @@ AC_DEFUN([tinc_OPENSSL],
|
|||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS(openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h,
|
||||
AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h openssl/ecdh.h openssl/ec.h],
|
||||
[],
|
||||
[AC_MSG_ERROR([OpenSSL header files not found.]); break]
|
||||
)
|
||||
|
@ -45,7 +45,7 @@ AC_DEFUN([tinc_OPENSSL],
|
|||
[AC_MSG_ERROR([OpenSSL libraries not found.])]
|
||||
)
|
||||
|
||||
AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex], ,
|
||||
AC_CHECK_FUNCS([RAND_pseudo_bytes EVP_EncryptInit_ex ECDH_compute_key ECDSA_verify], ,
|
||||
[AC_MSG_ERROR([Missing OpenSSL functionality, make sure you have installed the latest version.]); break],
|
||||
)
|
||||
|
||||
|
|
42
m4/readline.m4
Normal file
42
m4/readline.m4
Normal file
|
@ -0,0 +1,42 @@
|
|||
dnl Check to find the readline headers/libraries
|
||||
|
||||
AC_DEFUN([tinc_READLINE],
|
||||
[
|
||||
AC_ARG_ENABLE([readline],
|
||||
AS_HELP_STRING([--disable-readline], [disable readline support]))
|
||||
AS_IF([test "x$enable_readline" != "xno"], [
|
||||
AC_DEFINE(HAVE_READLINE, 1, [have readline support])
|
||||
readline=true
|
||||
AC_ARG_WITH(readline,
|
||||
AS_HELP_STRING([--with-readline=DIR], [readline base directory, or:]),
|
||||
[readline="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(readline-include,
|
||||
AS_HELP_STRING([--with-readline-include=DIR], [readline headers directory]),
|
||||
[readline_include="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(readline-lib,
|
||||
AS_HELP_STRING([--with-readline-lib=DIR], [readline library directory]),
|
||||
[readline_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS([readline/readline.h readline/history.h],
|
||||
[],
|
||||
[AC_MSG_ERROR("readline header files not found."); break]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(readline, readline,
|
||||
[READLINE_LIBS="-lreadline"],
|
||||
[AC_MSG_ERROR("readline library not found.")],
|
||||
[$CURSES_LIBS]
|
||||
)
|
||||
])
|
||||
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
])
|
53
missing
53
missing
|
@ -1,10 +1,10 @@
|
|||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
scriptversion=2012-01-06.13; # UTC
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
|
||||
# 2008, 2009 Free Software Foundation, Inc.
|
||||
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
|
||||
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -84,7 +84,6 @@ Supported PROGRAM values:
|
|||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
|
||||
|
@ -122,15 +121,6 @@ case $1 in
|
|||
# Not GNU programs, they don't have --version.
|
||||
;;
|
||||
|
||||
tar*)
|
||||
if test -n "$run"; then
|
||||
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
|
@ -226,7 +216,7 @@ WARNING: \`$1' $msg. You should only need it if
|
|||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
eval LASTARG=\${$#}
|
||||
case $LASTARG in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
|
@ -256,7 +246,7 @@ WARNING: \`$1' is $msg. You should only need it if
|
|||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
eval LASTARG=\${$#}
|
||||
case $LASTARG in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
|
@ -318,41 +308,6 @@ WARNING: \`$1' is $msg. You should only need it if
|
|||
touch $file
|
||||
;;
|
||||
|
||||
tar*)
|
||||
shift
|
||||
|
||||
# We have already tried tar in the generic part.
|
||||
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||
# messages.
|
||||
if (gnutar --version > /dev/null 2>&1); then
|
||||
gnutar "$@" && exit 0
|
||||
fi
|
||||
if (gtar --version > /dev/null 2>&1); then
|
||||
gtar "$@" && exit 0
|
||||
fi
|
||||
firstarg="$1"
|
||||
if shift; then
|
||||
case $firstarg in
|
||||
*o*)
|
||||
firstarg=`echo "$firstarg" | sed s/o//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
case $firstarg in
|
||||
*h*)
|
||||
firstarg=`echo "$firstarg" | sed s/h//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||
You may want to install GNU tar or Free paxutils, or check the
|
||||
command line arguments."
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and is $msg.
|
||||
|
|
|
@ -1,30 +1,43 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
|
||||
sbin_PROGRAMS = tincd tincctl
|
||||
sbin_PROGRAMS = tincd tincctl sptps_test
|
||||
|
||||
EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
|
||||
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
|
||||
|
||||
tincd_SOURCES = \
|
||||
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
|
||||
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c \
|
||||
buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
|
||||
protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c tincd.c \
|
||||
dummy_device.c raw_socket_device.c multicast_device.c
|
||||
|
||||
if UML
|
||||
tincd_SOURCES += uml_device.c
|
||||
endif
|
||||
|
||||
if VDE
|
||||
tincd_SOURCES += vde_device.c
|
||||
endif
|
||||
|
||||
nodist_tincd_SOURCES = \
|
||||
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
|
||||
|
||||
tincctl_SOURCES = \
|
||||
utils.c getopt.c getopt1.c dropin.c \
|
||||
list.c tincctl.c top.c
|
||||
info.c list.c subnet_parse.c tincctl.c top.c
|
||||
|
||||
nodist_tincctl_SOURCES = \
|
||||
ecdsagen.c rsagen.c
|
||||
|
||||
sptps_test_SOURCES = \
|
||||
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
|
||||
sptps.c sptps_test.c utils.c
|
||||
|
||||
if TUNEMU
|
||||
tincd_SOURCES += bsd/tunemu.c
|
||||
endif
|
||||
|
||||
tincctl_LDADD = $(CURSES_LIBS)
|
||||
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
|
||||
DEFAULT_INCLUDES =
|
||||
|
||||
|
@ -32,8 +45,8 @@ INCLUDES = @INCLUDES@ -I$(top_builddir)
|
|||
|
||||
noinst_HEADERS = \
|
||||
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h tincctl.h top.h bsd/tunemu.h
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
|
||||
|
||||
nodist_noinst_HEADERS = \
|
||||
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
|
||||
|
|
146
src/Makefile.in
146
src/Makefile.in
|
@ -1,9 +1,9 @@
|
|||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
@ -17,6 +17,23 @@
|
|||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__make_dryrun = \
|
||||
{ \
|
||||
am__dry=no; \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
|
||||
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
|
||||
*) \
|
||||
for am__flg in $$MAKEFLAGS; do \
|
||||
case $$am__flg in \
|
||||
*=*|--*) ;; \
|
||||
*n*) am__dry=yes; break;; \
|
||||
esac; \
|
||||
done;; \
|
||||
esac; \
|
||||
test $$am__dry = yes; \
|
||||
}
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
|
@ -35,9 +52,11 @@ PRE_UNINSTALL = :
|
|||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT)
|
||||
@TUNEMU_TRUE@am__append_1 = bsd/tunemu.c
|
||||
@TUNEMU_TRUE@am__append_2 = -lpcap
|
||||
sbin_PROGRAMS = tincd$(EXEEXT) tincctl$(EXEEXT) sptps_test$(EXEEXT)
|
||||
@UML_TRUE@am__append_1 = uml_device.c
|
||||
@VDE_TRUE@am__append_2 = vde_device.c
|
||||
@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c
|
||||
@TUNEMU_TRUE@am__append_4 = -lpcap
|
||||
subdir = src
|
||||
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in
|
||||
|
@ -45,7 +64,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
|
@ -54,34 +74,47 @@ CONFIG_CLEAN_FILES =
|
|||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(sbindir)"
|
||||
PROGRAMS = $(sbin_PROGRAMS)
|
||||
am_sptps_test_OBJECTS = logger.$(OBJEXT) cipher.$(OBJEXT) \
|
||||
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
|
||||
digest.$(OBJEXT) prf.$(OBJEXT) sptps.$(OBJEXT) \
|
||||
sptps_test.$(OBJEXT) utils.$(OBJEXT)
|
||||
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
|
||||
sptps_test_LDADD = $(LDADD)
|
||||
am_tincctl_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) \
|
||||
getopt1.$(OBJEXT) dropin.$(OBJEXT) list.$(OBJEXT) \
|
||||
tincctl.$(OBJEXT) top.$(OBJEXT)
|
||||
getopt1.$(OBJEXT) dropin.$(OBJEXT) info.$(OBJEXT) \
|
||||
list.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
|
||||
top.$(OBJEXT)
|
||||
nodist_tincctl_OBJECTS = ecdsagen.$(OBJEXT) rsagen.$(OBJEXT)
|
||||
tincctl_OBJECTS = $(am_tincctl_OBJECTS) $(nodist_tincctl_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1)
|
||||
tincctl_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
|
||||
am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
|
||||
splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
|
||||
buffer.c conf.c connection.c control.c edge.c graph.c logger.c \
|
||||
meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \
|
||||
node.c process.c protocol.c protocol_auth.c protocol_edge.c \
|
||||
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
|
||||
subnet.c tincd.c bsd/tunemu.c
|
||||
@TUNEMU_TRUE@am__objects_1 = tunemu.$(OBJEXT)
|
||||
hash.c buffer.c conf.c connection.c control.c edge.c graph.c \
|
||||
logger.c meta.c net.c net_packet.c net_setup.c net_socket.c \
|
||||
netutl.c node.c process.c protocol.c protocol_auth.c \
|
||||
protocol_edge.c protocol_misc.c protocol_key.c \
|
||||
protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c \
|
||||
tincd.c dummy_device.c raw_socket_device.c multicast_device.c \
|
||||
uml_device.c vde_device.c bsd/tunemu.c
|
||||
@UML_TRUE@am__objects_1 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_2 = vde_device.$(OBJEXT)
|
||||
@TUNEMU_TRUE@am__objects_3 = tunemu.$(OBJEXT)
|
||||
am_tincd_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
|
||||
list.$(OBJEXT) splay_tree.$(OBJEXT) dropin.$(OBJEXT) \
|
||||
fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \
|
||||
buffer.$(OBJEXT) conf.$(OBJEXT) connection.$(OBJEXT) \
|
||||
control.$(OBJEXT) edge.$(OBJEXT) graph.$(OBJEXT) \
|
||||
logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \
|
||||
hash.$(OBJEXT) buffer.$(OBJEXT) conf.$(OBJEXT) \
|
||||
connection.$(OBJEXT) control.$(OBJEXT) edge.$(OBJEXT) \
|
||||
graph.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) net.$(OBJEXT) \
|
||||
net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \
|
||||
netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \
|
||||
protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
|
||||
protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \
|
||||
protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \
|
||||
route.$(OBJEXT) subnet.$(OBJEXT) tincd.$(OBJEXT) \
|
||||
$(am__objects_1)
|
||||
route.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
|
||||
subnet_parse.$(OBJEXT) tincd.$(OBJEXT) dummy_device.$(OBJEXT) \
|
||||
raw_socket_device.$(OBJEXT) multicast_device.$(OBJEXT) \
|
||||
$(am__objects_1) $(am__objects_2) $(am__objects_3)
|
||||
nodist_tincd_OBJECTS = device.$(OBJEXT) cipher.$(OBJEXT) \
|
||||
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
|
||||
digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT)
|
||||
|
@ -94,9 +127,16 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
|||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(tincctl_SOURCES) $(nodist_tincctl_SOURCES) \
|
||||
$(tincd_SOURCES) $(nodist_tincd_SOURCES)
|
||||
DIST_SOURCES = $(tincctl_SOURCES) $(am__tincd_SOURCES_DIST)
|
||||
SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
|
||||
$(nodist_tincctl_SOURCES) $(tincd_SOURCES) \
|
||||
$(nodist_tincd_SOURCES)
|
||||
DIST_SOURCES = $(sptps_test_SOURCES) $(tincctl_SOURCES) \
|
||||
$(am__tincd_SOURCES_DIST)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
HEADERS = $(nodist_noinst_HEADERS) $(noinst_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
|
@ -133,7 +173,7 @@ LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
|
|||
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
|
||||
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_2)
|
||||
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_4)
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
|
@ -149,6 +189,7 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
|
@ -203,30 +244,36 @@ target_alias = @target_alias@
|
|||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
EXTRA_DIST = linux bsd solaris cygwin mingw raw_socket uml_socket openssl gcrypt
|
||||
EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
|
||||
tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \
|
||||
dropin.c fake-getaddrinfo.c fake-getnameinfo.c buffer.c conf.c \
|
||||
connection.c control.c edge.c graph.c logger.c meta.c net.c \
|
||||
net_packet.c net_setup.c net_socket.c netutl.c node.c \
|
||||
dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c buffer.c \
|
||||
conf.c connection.c control.c edge.c graph.c logger.c meta.c \
|
||||
net.c net_packet.c net_setup.c net_socket.c netutl.c node.c \
|
||||
process.c protocol.c protocol_auth.c protocol_edge.c \
|
||||
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
|
||||
subnet.c tincd.c $(am__append_1)
|
||||
sptps.c subnet.c subnet_parse.c tincd.c dummy_device.c \
|
||||
raw_socket_device.c multicast_device.c $(am__append_1) \
|
||||
$(am__append_2) $(am__append_3)
|
||||
nodist_tincd_SOURCES = \
|
||||
device.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c rsa.c
|
||||
|
||||
tincctl_SOURCES = \
|
||||
utils.c getopt.c getopt1.c dropin.c \
|
||||
list.c tincctl.c top.c
|
||||
info.c list.c subnet_parse.c tincctl.c top.c
|
||||
|
||||
nodist_tincctl_SOURCES = \
|
||||
ecdsagen.c rsagen.c
|
||||
|
||||
tincctl_LDADD = $(CURSES_LIBS)
|
||||
sptps_test_SOURCES = \
|
||||
logger.c cipher.c crypto.c ecdh.c ecdsa.c digest.c prf.c \
|
||||
sptps.c sptps_test.c utils.c
|
||||
|
||||
tincctl_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
DEFAULT_INCLUDES =
|
||||
noinst_HEADERS = \
|
||||
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h tincctl.h top.h bsd/tunemu.h
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
|
||||
|
||||
nodist_noinst_HEADERS = \
|
||||
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
|
||||
|
@ -268,8 +315,11 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
|||
$(am__aclocal_m4_deps):
|
||||
install-sbinPROGRAMS: $(sbin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
|
||||
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed 's/$(EXEEXT)$$//' | \
|
||||
while read p p1; do if test -f $$p; \
|
||||
|
@ -303,10 +353,13 @@ uninstall-sbinPROGRAMS:
|
|||
|
||||
clean-sbinPROGRAMS:
|
||||
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
|
||||
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES)
|
||||
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
|
||||
@rm -f sptps_test$(EXEEXT)
|
||||
$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
|
||||
tincctl$(EXEEXT): $(tincctl_OBJECTS) $(tincctl_DEPENDENCIES) $(EXTRA_tincctl_DEPENDENCIES)
|
||||
@rm -f tincctl$(EXEEXT)
|
||||
$(LINK) $(tincctl_OBJECTS) $(tincctl_LDADD) $(LIBS)
|
||||
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES)
|
||||
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
|
||||
@rm -f tincd$(EXEEXT)
|
||||
$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
|
||||
|
||||
|
@ -325,6 +378,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/digest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dropin.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdh.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsagen.Po@am__quote@
|
||||
|
@ -334,9 +388,12 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/graph.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/meta.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multicast_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_packet.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_setup.Po@am__quote@
|
||||
|
@ -351,16 +408,22 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_key.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_misc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_subnet.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_socket_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsagen.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay_tree.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps_test.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet_parse.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincctl.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/top.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tunemu.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
|
@ -492,10 +555,15 @@ install-am: all-am
|
|||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,7 +33,12 @@
|
|||
#include "bsd/tunemu.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DEVICE "/dev/tun0"
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#if defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap0"
|
||||
#else
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tun0"
|
||||
#endif
|
||||
|
||||
typedef enum device_type {
|
||||
DEVICE_TYPE_TUN,
|
||||
|
@ -58,11 +63,15 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
|
|||
static device_type_t device_type = DEVICE_TYPE_TUN;
|
||||
#endif
|
||||
|
||||
bool setup_device(void) {
|
||||
static bool setup_device(void) {
|
||||
char *type;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
else
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
|
@ -81,7 +90,7 @@ bool setup_device(void) {
|
|||
else if(!strcasecmp(type, "tap"))
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
else {
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -102,10 +111,14 @@ bool setup_device(void) {
|
|||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
switch(device_type) {
|
||||
default:
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
|
@ -114,7 +127,7 @@ bool setup_device(void) {
|
|||
{
|
||||
const int zero = 0;
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +146,7 @@ bool setup_device(void) {
|
|||
{
|
||||
const int one = 1;
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -170,12 +183,12 @@ bool setup_device(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
static void close_device(void) {
|
||||
switch(device_type) {
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
|
@ -190,7 +203,7 @@ void close_device(void) {
|
|||
free(iface);
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
switch(device_type) {
|
||||
|
@ -204,7 +217,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
inlen = read(device_fd, packet->data + 14, MTU - 14);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -219,12 +232,13 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = inlen + 14;
|
||||
break;
|
||||
|
||||
|
@ -233,7 +247,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
|
||||
|
||||
if((inlen = readv(device_fd, vector, 2)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -250,19 +264,20 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown address family %x while reading packet from %s %s",
|
||||
ntohl(type), device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -276,20 +291,20 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -310,14 +325,14 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
type = htonl(AF_INET6);
|
||||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown address family %x while writing packet to %s %s",
|
||||
af, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(writev(device_fd, vector, 2) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -326,7 +341,7 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -335,7 +350,7 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -351,8 +366,16 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
218
src/cipher.c
Normal file
218
src/cipher.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
cipher.c -- Symmetric block cipher handling
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "cipher.h"
|
||||
#include "logger.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
typedef struct cipher_counter {
|
||||
unsigned char counter[EVP_MAX_IV_LENGTH];
|
||||
unsigned char block[EVP_MAX_IV_LENGTH];
|
||||
int n;
|
||||
} cipher_counter_t;
|
||||
|
||||
static bool cipher_open(cipher_t *cipher) {
|
||||
EVP_CIPHER_CTX_init(&cipher->ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
||||
cipher->cipher = EVP_get_cipherbyname(name);
|
||||
|
||||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
||||
cipher->cipher = EVP_get_cipherbynid(nid);
|
||||
|
||||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_open_blowfish_ofb(cipher_t *cipher) {
|
||||
cipher->cipher = EVP_bf_ofb();
|
||||
return cipher_open(cipher);
|
||||
}
|
||||
|
||||
void cipher_close(cipher_t *cipher) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
|
||||
free(cipher->counter);
|
||||
cipher->counter = NULL;
|
||||
}
|
||||
|
||||
size_t cipher_keylength(const cipher_t *cipher) {
|
||||
return cipher->cipher->key_len + cipher->cipher->block_size;
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
|
||||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_set_counter(cipher_t *cipher, const void *counter, size_t len) {
|
||||
if(len > cipher->cipher->block_size - 4) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter too long");
|
||||
abort();
|
||||
}
|
||||
|
||||
memcpy(cipher->counter->counter + cipher->cipher->block_size - len, counter, len);
|
||||
memset(cipher->counter->counter, 0, 4);
|
||||
cipher->counter->n = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_set_counter_key(cipher_t *cipher, void *key) {
|
||||
int result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, NULL);
|
||||
if(!result) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!cipher->counter)
|
||||
cipher->counter = xmalloc_and_zero(sizeof *cipher->counter);
|
||||
else
|
||||
cipher->counter->n = 0;
|
||||
|
||||
memcpy(cipher->counter->counter, (unsigned char *)key + cipher->cipher->key_len, cipher->cipher->block_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_counter_xor(cipher_t *cipher, const void *indata, size_t inlen, void *outdata) {
|
||||
if(!cipher->counter) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char *in = indata;
|
||||
unsigned char *out = outdata;
|
||||
|
||||
while(inlen--) {
|
||||
// Encrypt the new counter value if we need it
|
||||
if(!cipher->counter->n) {
|
||||
int len;
|
||||
if(!EVP_EncryptUpdate(&cipher->ctx, cipher->counter->block, &len, cipher->counter->counter, cipher->cipher->block_size)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the counter value
|
||||
for(int i = 0; i < cipher->cipher->block_size; i++)
|
||||
if(++cipher->counter->counter[i])
|
||||
break;
|
||||
}
|
||||
|
||||
*out++ = *in++ ^ cipher->counter->counter[cipher->counter->n++];
|
||||
|
||||
if(cipher->counter->n >= cipher->cipher->block_size)
|
||||
cipher->counter->n = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int cipher_get_nid(const cipher_t *cipher) {
|
||||
return cipher->cipher ? cipher->cipher->nid : 0;
|
||||
}
|
||||
|
||||
bool cipher_active(const cipher_t *cipher) {
|
||||
return cipher->cipher && cipher->cipher->nid != 0;
|
||||
}
|
114
src/conf.c
114
src/conf.c
|
@ -2,7 +2,7 @@
|
|||
conf.c -- configuration code
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
1998-2005 Ivo Timmermans
|
||||
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
||||
2000 Cris van Pelt
|
||||
|
||||
|
@ -141,7 +141,7 @@ bool get_config_bool(const config_t *cfg, bool *result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
@ -154,7 +154,7 @@ bool get_config_int(const config_t *cfg, int *result) {
|
|||
if(sscanf(cfg->value, "%d", result) == 1)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
@ -182,7 +182,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
@ -195,7 +195,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
|
|||
return false;
|
||||
|
||||
if(!str2net(&subnet, cfg->value)) {
|
||||
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
|
|||
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
|
||||
|| ((subnet.type == SUBNET_IPV6)
|
||||
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) {
|
||||
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
@ -236,8 +236,9 @@ static char *readline(FILE * fp, char *buf, size_t buflen) {
|
|||
if(!newline)
|
||||
return buf;
|
||||
|
||||
*newline = '\0'; /* kill newline */
|
||||
if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
|
||||
/* kill newline and carriage return if necessary */
|
||||
*newline = '\0';
|
||||
if(newline > p && newline[-1] == '\r')
|
||||
newline[-1] = '\0';
|
||||
|
||||
return buf;
|
||||
|
@ -265,10 +266,10 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
|||
if(!*value) {
|
||||
const char err[] = "No value for variable";
|
||||
if (fname)
|
||||
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||
err, variable, lineno, fname);
|
||||
else
|
||||
logger(LOG_ERR, "%s `%s' in command line option %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' in command line option %d",
|
||||
err, variable, lineno);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -298,7 +299,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
|
|||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -339,33 +340,31 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
|
|||
}
|
||||
|
||||
void read_config_options(splay_tree_t *config_tree, const char *prefix) {
|
||||
list_node_t *node, *next;
|
||||
size_t prefix_len = prefix ? strlen(prefix) : 0;
|
||||
|
||||
for(node = cmdline_conf->tail; node; node = next) {
|
||||
config_t *orig_cfg, *cfg = (config_t *)node->data;
|
||||
next = node->prev;
|
||||
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
|
||||
const config_t *cfg = node->data;
|
||||
config_t *new;
|
||||
|
||||
if(!prefix) {
|
||||
if(strchr(cfg->variable, '.'))
|
||||
continue;
|
||||
node->data = NULL;
|
||||
list_unlink_node(cmdline_conf, node);
|
||||
} else {
|
||||
if(strncmp(prefix, cfg->variable, prefix_len) ||
|
||||
cfg->variable[prefix_len] != '.')
|
||||
continue;
|
||||
/* Because host configuration is parsed again when
|
||||
reconnecting, nodes must not be freed when a prefix
|
||||
is given. */
|
||||
orig_cfg = cfg;
|
||||
cfg = new_config();
|
||||
cfg->variable = xstrdup(orig_cfg->variable + prefix_len + 1);
|
||||
cfg->value = xstrdup(orig_cfg->value);
|
||||
cfg->file = NULL;
|
||||
cfg->line = orig_cfg->line;
|
||||
}
|
||||
config_add(config_tree, cfg);
|
||||
|
||||
new = new_config();
|
||||
if(prefix)
|
||||
new->variable = xstrdup(cfg->variable + prefix_len + 1);
|
||||
else
|
||||
new->variable = xstrdup(cfg->variable);
|
||||
new->value = xstrdup(cfg->value);
|
||||
new->file = NULL;
|
||||
new->line = cfg->line;
|
||||
|
||||
config_add(config_tree, new);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,26 +374,25 @@ bool read_server_config(void) {
|
|||
|
||||
read_config_options(config_tree, NULL);
|
||||
|
||||
xasprintf(&fname, "%s/tinc.conf", confbase);
|
||||
xasprintf(&fname, "%s" SLASH "tinc.conf", confbase);
|
||||
x = read_config_file(config_tree, fname);
|
||||
|
||||
if(!x) { /* System error: complain */
|
||||
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||
}
|
||||
if(!x)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||
|
||||
free(fname);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool read_connection_config(connection_t *c) {
|
||||
bool read_host_config(splay_tree_t *config_tree, const char *name) {
|
||||
char *fname;
|
||||
bool x;
|
||||
|
||||
read_config_options(c->config_tree, c->name);
|
||||
read_config_options(config_tree, name);
|
||||
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
x = read_config_file(c->config_tree, fname);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
x = read_config_file(config_tree, fname);
|
||||
free(fname);
|
||||
|
||||
return x;
|
||||
|
@ -402,12 +400,12 @@ bool read_connection_config(connection_t *c) {
|
|||
|
||||
bool append_config_file(const char *name, const char *key, const char *value) {
|
||||
char *fname;
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, name);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
|
||||
FILE *fp = fopen(fname, "a");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
} else {
|
||||
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
|
||||
fclose(fp);
|
||||
|
@ -415,45 +413,5 @@ bool append_config_file(const char *name, const char *key, const char *value) {
|
|||
|
||||
free(fname);
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool disable_old_keys(FILE *f) {
|
||||
char buf[100];
|
||||
long pos;
|
||||
bool disabled = false;
|
||||
|
||||
rewind(f);
|
||||
pos = ftell(f);
|
||||
|
||||
if(pos < 0)
|
||||
return false;
|
||||
|
||||
while(fgets(buf, sizeof buf, f)) {
|
||||
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
|
||||
buf[11] = 'O';
|
||||
buf[12] = 'L';
|
||||
buf[13] = 'D';
|
||||
if(fseek(f, pos, SEEK_SET))
|
||||
break;
|
||||
if(fputs(buf, f) <= 0)
|
||||
break;
|
||||
disabled = true;
|
||||
}
|
||||
else if(!strncmp(buf, "-----END RSA", 12)) {
|
||||
buf[ 9] = 'O';
|
||||
buf[10] = 'L';
|
||||
buf[11] = 'D';
|
||||
if(fseek(f, pos, SEEK_SET))
|
||||
break;
|
||||
if(fputs(buf, f) <= 0)
|
||||
break;
|
||||
disabled = true;
|
||||
}
|
||||
pos = ftell(f);
|
||||
if(pos < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return disabled;
|
||||
return fp != NULL;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
conf.h -- header for conf.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -60,10 +60,7 @@ extern config_t *parse_config_line(char *, const char *, int);
|
|||
extern bool read_config_file(splay_tree_t *, const char *);
|
||||
extern void read_config_options(splay_tree_t *, const char *);
|
||||
extern bool read_server_config(void);
|
||||
extern bool read_connection_config(struct connection_t *);
|
||||
extern bool read_host_config(splay_tree_t *, const char *);
|
||||
extern bool append_config_file(const char *, const char *, const char *);
|
||||
extern FILE *ask_and_open(const char *, const char *, const char *);
|
||||
extern bool is_safe_path(const char *);
|
||||
extern bool disable_old_keys(FILE *);
|
||||
|
||||
#endif /* __TINC_CONF_H__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
connection.c -- connection list management
|
||||
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2008 Max Rijevski <maksuf@gmail.com>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "list.h"
|
||||
#include "cipher.h"
|
||||
#include "conf.h"
|
||||
#include "control_common.h"
|
||||
|
@ -31,23 +31,19 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
splay_tree_t *connection_tree; /* Meta connections */
|
||||
connection_t *broadcast;
|
||||
|
||||
static int connection_compare(const connection_t *a, const connection_t *b) {
|
||||
return a < b ? -1 : a == b ? 0 : 1;
|
||||
}
|
||||
list_t *connection_list;
|
||||
connection_t *everyone;
|
||||
|
||||
void init_connections(void) {
|
||||
connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection);
|
||||
broadcast = new_connection();
|
||||
broadcast->name = xstrdup("everyone");
|
||||
broadcast->hostname = xstrdup("BROADCAST");
|
||||
connection_list = list_alloc((list_action_t) free_connection);
|
||||
everyone = new_connection();
|
||||
everyone->name = xstrdup("everyone");
|
||||
everyone->hostname = xstrdup("BROADCAST");
|
||||
}
|
||||
|
||||
void exit_connections(void) {
|
||||
splay_delete_tree(connection_tree);
|
||||
free_connection(broadcast);
|
||||
list_delete_list(connection_list);
|
||||
free_connection(everyone);
|
||||
}
|
||||
|
||||
connection_t *new_connection(void) {
|
||||
|
@ -58,27 +54,17 @@ void free_connection(connection_t *c) {
|
|||
if(!c)
|
||||
return;
|
||||
|
||||
if(c->name)
|
||||
free(c->name);
|
||||
|
||||
if(c->hostname)
|
||||
free(c->hostname);
|
||||
|
||||
cipher_close(&c->incipher);
|
||||
digest_close(&c->indigest);
|
||||
cipher_close(&c->outcipher);
|
||||
digest_close(&c->outdigest);
|
||||
|
||||
ecdh_free(&c->ecdh);
|
||||
sptps_stop(&c->sptps);
|
||||
ecdsa_free(&c->ecdsa);
|
||||
rsa_free(&c->rsa);
|
||||
|
||||
if(c->hischallenge)
|
||||
free(c->hischallenge);
|
||||
|
||||
if(c->config_tree)
|
||||
exit_configuration(&c->config_tree);
|
||||
|
||||
buffer_clear(&c->inbuf);
|
||||
buffer_clear(&c->outbuf);
|
||||
|
||||
|
@ -91,24 +77,26 @@ void free_connection(connection_t *c) {
|
|||
if(c->socket > 0)
|
||||
closesocket(c->socket);
|
||||
|
||||
free(c->name);
|
||||
free(c->hostname);
|
||||
|
||||
if(c->config_tree)
|
||||
exit_configuration(&c->config_tree);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
void connection_add(connection_t *c) {
|
||||
splay_insert(connection_tree, c);
|
||||
list_insert_tail(connection_list, c);
|
||||
}
|
||||
|
||||
void connection_del(connection_t *c) {
|
||||
splay_delete(connection_tree, c);
|
||||
list_delete(connection_list, c);
|
||||
}
|
||||
|
||||
bool dump_connections(connection_t *cdump) {
|
||||
splay_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
send_request(cdump, "%d %d %s at %s options %x socket %d status %04x",
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
send_request(cdump, "%d %d %s %s %x %d %x",
|
||||
CONTROL, REQ_DUMP_CONNECTIONS,
|
||||
c->name, c->hostname, c->options, c->socket,
|
||||
bitfield_to_int(&c->status, sizeof c->status));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
connection.h -- header for connection.c
|
||||
Copyright (C) 2000-2010 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -25,29 +25,31 @@
|
|||
#include "cipher.h"
|
||||
#include "digest.h"
|
||||
#include "rsa.h"
|
||||
#include "splay_tree.h"
|
||||
#include "list.h"
|
||||
#include "sptps.h"
|
||||
|
||||
#define OPTION_INDIRECT 0x0001
|
||||
#define OPTION_TCPONLY 0x0002
|
||||
#define OPTION_PMTU_DISCOVERY 0x0004
|
||||
#define OPTION_CLAMP_MSS 0x0008
|
||||
#define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
|
||||
|
||||
typedef struct connection_status_t {
|
||||
unsigned int pinged:1; /* sent ping */
|
||||
unsigned int active:1; /* 1 if active.. */
|
||||
unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||
unsigned int termreq:1; /* the termination of this connection was requested */
|
||||
unsigned int unused_termreq:1; /* the termination of this connection was requested */
|
||||
unsigned int remove_unused:1; /* Set to 1 if you want this connection removed */
|
||||
unsigned int timeout_unused:1; /* 1 if gotten timeout */
|
||||
unsigned int encryptout:1; /* 1 if we can encrypt outgoing traffic */
|
||||
unsigned int decryptin:1; /* 1 if we have to decrypt incoming traffic */
|
||||
unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */
|
||||
unsigned int control:1;
|
||||
unsigned int pcap:1;
|
||||
unsigned int unused:21;
|
||||
unsigned int control:1; /* 1 if this is a control connection */
|
||||
unsigned int pcap:1; /* 1 if this is a control connection requesting packet capture */
|
||||
unsigned int log:1; /* 1 if this is a control connection requesting log dump */
|
||||
unsigned int unused:20;
|
||||
} connection_status_t;
|
||||
|
||||
#include "ecdh.h"
|
||||
#include "ecdsa.h"
|
||||
#include "edge.h"
|
||||
#include "net.h"
|
||||
|
@ -73,11 +75,11 @@ typedef struct connection_t {
|
|||
|
||||
rsa_t rsa; /* his public RSA key */
|
||||
ecdsa_t ecdsa; /* his public ECDSA key */
|
||||
ecdsa_t ecdh; /* state for ECDH key exchange */
|
||||
cipher_t incipher; /* Cipher he will use to send data to us */
|
||||
cipher_t outcipher; /* Cipher we will use to send data to him */
|
||||
digest_t indigest;
|
||||
digest_t outdigest;
|
||||
sptps_t sptps;
|
||||
|
||||
int inmaclength;
|
||||
int outmaclength;
|
||||
|
@ -98,8 +100,8 @@ typedef struct connection_t {
|
|||
splay_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||
} connection_t;
|
||||
|
||||
extern splay_tree_t *connection_tree;
|
||||
extern connection_t *broadcast;
|
||||
extern list_t *connection_list;
|
||||
extern connection_t *everyone;
|
||||
|
||||
extern void init_connections(void);
|
||||
extern void exit_connections(void);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
control.c -- Control socket handling.
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,7 +29,6 @@
|
|||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "route.h"
|
||||
#include "splay_tree.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
@ -44,16 +43,16 @@ static bool control_ok(connection_t *c, int type) {
|
|||
return control_return(c, type, 0);
|
||||
}
|
||||
|
||||
bool control_h(connection_t *c, char *request) {
|
||||
bool control_h(connection_t *c, const char *request) {
|
||||
int type;
|
||||
|
||||
if(!c->status.control || c->allow_request != CONTROL) {
|
||||
logger(LOG_ERR, "Unauthorized control request from %s (%s)", c->name, c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unauthorized control request from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sscanf(request, "%*d %d", &type) != 1) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -93,22 +92,18 @@ bool control_h(connection_t *c, char *request) {
|
|||
return control_ok(c, REQ_RETRY);
|
||||
|
||||
case REQ_RELOAD:
|
||||
logger(LOG_NOTICE, "Got '%s' command", "reload");
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got '%s' command", "reload");
|
||||
int result = reload_configuration();
|
||||
return control_return(c, REQ_RELOAD, result);
|
||||
|
||||
case REQ_DISCONNECT: {
|
||||
char name[MAX_STRING_SIZE];
|
||||
connection_t *other;
|
||||
splay_node_t *node, *next;
|
||||
bool found = false;
|
||||
|
||||
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1)
|
||||
return control_return(c, REQ_DISCONNECT, -1);
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
other = node->data;
|
||||
for list_each(connection_t, other, connection_list) {
|
||||
if(strcmp(other->name, name))
|
||||
continue;
|
||||
terminate_connection(other, other->status.active);
|
||||
|
@ -122,10 +117,17 @@ bool control_h(connection_t *c, char *request) {
|
|||
return dump_traffic(c);
|
||||
|
||||
case REQ_PCAP:
|
||||
sscanf(request, "%*d %*d %d", &c->outmaclength);
|
||||
c->status.pcap = true;
|
||||
pcap = true;
|
||||
return true;
|
||||
|
||||
case REQ_LOG:
|
||||
sscanf(request, "%*d %*d %d", &c->outcompression);
|
||||
c->status.log = true;
|
||||
logcontrol = true;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return send_request(c, "%d %d", CONTROL, REQ_INVALID);
|
||||
}
|
||||
|
@ -137,7 +139,7 @@ bool init_control(void) {
|
|||
|
||||
FILE *f = fopen(pidfilename, "w");
|
||||
if(!f) {
|
||||
logger(LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
control_protocol.h -- control socket protocol.
|
||||
Copyright (C) 2007 Scott Lamb <slamb@slamb.org>
|
||||
2009-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -39,6 +40,7 @@ enum request_type {
|
|||
REQ_DISCONNECT,
|
||||
REQ_DUMP_TRAFFIC,
|
||||
REQ_PCAP,
|
||||
REQ_LOG,
|
||||
};
|
||||
|
||||
#define TINC_CTL_VERSION_CURRENT 0
|
||||
|
|
43
src/crypto.c
Normal file
43
src/crypto.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
void crypto_init(void) {
|
||||
RAND_load_file("/dev/urandom", 1024);
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_register_all_complete();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
}
|
||||
|
||||
void crypto_exit(void) {
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
void randomize(void *out, size_t outlen) {
|
||||
RAND_pseudo_bytes(out, outlen);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -45,7 +45,7 @@ static uint64_t device_total_out = 0;
|
|||
static pid_t reader_pid;
|
||||
static int sp[2];
|
||||
|
||||
bool setup_device(void) {
|
||||
static bool setup_device(void) {
|
||||
HKEY key, key2;
|
||||
int i, err;
|
||||
|
||||
|
@ -64,7 +64,7 @@ bool setup_device(void) {
|
|||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ bool setup_device(void) {
|
|||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ bool setup_device(void) {
|
|||
Furthermore I don't really know how to do it the "Windows" way. */
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ bool setup_device(void) {
|
|||
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ bool setup_device(void) {
|
|||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ bool setup_device(void) {
|
|||
reader_pid = fork();
|
||||
|
||||
if(reader_pid == -1) {
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -180,13 +180,13 @@ bool setup_device(void) {
|
|||
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||
buf[0] = 0;
|
||||
write(sp[1], buf, 1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, "Tap reader forked and running.");
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader forked and running.");
|
||||
|
||||
/* Notify success */
|
||||
|
||||
|
@ -203,18 +203,18 @@ bool setup_device(void) {
|
|||
|
||||
read(device_fd, &gelukt, 1);
|
||||
if(gelukt != 1) {
|
||||
logger(LOG_DEBUG, "Tap reader failed!");
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
device_info = "Windows tap device";
|
||||
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
static void close_device(void) {
|
||||
close(sp[0]);
|
||||
close(sp[1]);
|
||||
CloseHandle(device_handle);
|
||||
|
@ -225,11 +225,11 @@ void close_device(void) {
|
|||
free(iface);
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -238,20 +238,20 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
long outlen;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -260,8 +260,16 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
24
src/device.h
24
src/device.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.h -- generic header for device.c
|
||||
device.h -- generic header for device.c
|
||||
Copyright (C) 2001-2005 Ivo Timmermans
|
||||
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -32,10 +32,20 @@ extern uint64_t device_in_bytes;
|
|||
extern uint64_t device_out_packets;
|
||||
extern uint64_t device_out_bytes;
|
||||
|
||||
extern bool setup_device(void);
|
||||
extern void close_device(void);
|
||||
extern bool read_packet(struct vpn_packet_t *);
|
||||
extern bool write_packet(struct vpn_packet_t *);
|
||||
extern void dump_device_stats(void);
|
||||
typedef struct devops_t {
|
||||
bool (*setup)(void);
|
||||
void (*close)(void);
|
||||
bool (*read)(struct vpn_packet_t *);
|
||||
bool (*write)(struct vpn_packet_t *);
|
||||
void (*dump_stats)(void);
|
||||
} devops_t;
|
||||
|
||||
extern const devops_t os_devops;
|
||||
extern const devops_t dummy_devops;
|
||||
extern const devops_t raw_socket_devops;
|
||||
extern const devops_t multicast_devops;
|
||||
extern const devops_t uml_devops;
|
||||
extern const devops_t vde_devops;
|
||||
extern devops_t devops;
|
||||
|
||||
#endif /* __TINC_DEVICE_H__ */
|
||||
|
|
127
src/digest.c
Normal file
127
src/digest.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
digest.c -- Digest handling
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include "digest.h"
|
||||
#include "logger.h"
|
||||
|
||||
static void set_maclength(digest_t *digest, int maclength) {
|
||||
int digestlen = EVP_MD_size(digest->digest);
|
||||
|
||||
if(maclength > digestlen || maclength < 0)
|
||||
digest->maclength = digestlen;
|
||||
else
|
||||
digest->maclength = maclength;
|
||||
}
|
||||
|
||||
bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
|
||||
digest->digest = EVP_get_digestbyname(name);
|
||||
digest->key = NULL;
|
||||
|
||||
if(!digest->digest) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
set_maclength(digest, maclength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
|
||||
digest->digest = EVP_get_digestbynid(nid);
|
||||
digest->key = NULL;
|
||||
|
||||
if(!digest->digest) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
set_maclength(digest, maclength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_open_sha1(digest_t *digest, int maclength) {
|
||||
digest->digest = EVP_sha1();
|
||||
digest->key = NULL;
|
||||
|
||||
set_maclength(digest, maclength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
|
||||
digest->key = xrealloc(digest->key, len);
|
||||
memcpy(digest->key, key, len);
|
||||
digest->keylength = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void digest_close(digest_t *digest) {
|
||||
free(digest->key);
|
||||
digest->key = NULL;
|
||||
}
|
||||
|
||||
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
|
||||
size_t len = EVP_MD_size(digest->digest);
|
||||
unsigned char tmpdata[len];
|
||||
|
||||
if(digest->key) {
|
||||
HMAC(digest->digest, digest->key, digest->keylength, indata, inlen, tmpdata, NULL);
|
||||
} else {
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
if(!EVP_DigestInit(&ctx, digest->digest)
|
||||
|| !EVP_DigestUpdate(&ctx, indata, inlen)
|
||||
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(outdata, tmpdata, digest->maclength);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
|
||||
size_t len = digest->maclength;
|
||||
unsigned char outdata[len];
|
||||
|
||||
return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, digest->maclength);
|
||||
}
|
||||
|
||||
int digest_get_nid(const digest_t *digest) {
|
||||
return digest->digest ? digest->digest->type : 0;
|
||||
}
|
||||
|
||||
size_t digest_keylength(const digest_t *digest) {
|
||||
return digest->digest->md_size;
|
||||
}
|
||||
|
||||
size_t digest_length(const digest_t *digest) {
|
||||
return digest->maclength;
|
||||
}
|
||||
|
||||
bool digest_active(const digest_t *digest) {
|
||||
return digest->digest && digest->digest->type != 0;
|
||||
}
|
62
src/dummy_device.c
Normal file
62
src/dummy_device.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
device.c -- Dummy device
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
|
||||
static char *device_info = "dummy device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
device = "dummy";
|
||||
iface = "dummy";
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
device_total_out += packet->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t dummy_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
96
src/ecdh.c
Normal file
96
src/ecdh.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange handling
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include "ecdh.h"
|
||||
#include "logger.h"
|
||||
|
||||
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
|
||||
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!*ecdh) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EC_KEY_generate_key(*ecdh)) {
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
const EC_POINT *point = EC_KEY_get0_public_key(*ecdh);
|
||||
if(!point) {
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh));
|
||||
if(!point) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
EC_POINT_free(point);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ECDH_compute_key(shared, ECDH_SIZE, point, *ecdh, NULL);
|
||||
EC_POINT_free(point);
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
|
||||
if(!result) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ecdh_free(ecdh_t *ecdh) {
|
||||
if(*ecdh) {
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
}
|
||||
}
|
130
src/ecdsa.c
Normal file
130
src/ecdsa.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
ecdsa.c -- ECDSA key handling
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "ecdsa.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Get and set ECDSA keys
|
||||
//
|
||||
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
|
||||
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!*ecdsa) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = strlen(p);
|
||||
unsigned char pubkey[len / 4 * 3 + 3];
|
||||
const unsigned char *ppubkey = pubkey;
|
||||
len = b64decode(p, (char *)pubkey, len);
|
||||
|
||||
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
||||
unsigned char *pubkey = NULL;
|
||||
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
|
||||
|
||||
char *base64 = malloc(len * 4 / 3 + 5);
|
||||
b64encode((char *)pubkey, base64, len);
|
||||
|
||||
free(pubkey);
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
// Read PEM ECDSA keys
|
||||
|
||||
bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
*ecdsa = PEM_read_EC_PUBKEY(fp, ecdsa, NULL, NULL);
|
||||
|
||||
if(*ecdsa)
|
||||
return true;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
*ecdsa = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL);
|
||||
|
||||
if(*ecdsa)
|
||||
return true;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
||||
return ECDSA_size(*ecdsa);
|
||||
}
|
||||
|
||||
// TODO: standardise output format?
|
||||
|
||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
unsigned int siglen = ECDSA_size(*ecdsa);
|
||||
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
memset(sig, 0, siglen);
|
||||
|
||||
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
unsigned int siglen = ECDSA_size(*ecdsa);
|
||||
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
||||
return *ecdsa;
|
||||
}
|
||||
|
||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
||||
if(*ecdsa) {
|
||||
EC_KEY_free(*ecdsa);
|
||||
*ecdsa = NULL;
|
||||
}
|
||||
}
|
19
src/edge.c
19
src/edge.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
edge.c -- edge tree management
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,7 +29,7 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
splay_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
|
||||
splay_tree_t *edge_weight_tree;
|
||||
|
||||
static int edge_compare(const edge_t *a, const edge_t *b) {
|
||||
return strcmp(a->to->name, b->to->name);
|
||||
|
@ -107,17 +107,10 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
|
|||
}
|
||||
|
||||
bool dump_edges(connection_t *c) {
|
||||
splay_node_t *node, *node2;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *address;
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
||||
e = node2->data;
|
||||
address = sockaddr2hostname(&e->address);
|
||||
send_request(c, "%d %d %s to %s at %s options %x weight %d",
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
char *address = sockaddr2hostname(&e->address);
|
||||
send_request(c, "%d %d %s %s %s %x %d",
|
||||
CONTROL, REQ_DUMP_EDGES,
|
||||
e->from->name, e->to->name, address,
|
||||
e->options, e->weight);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
edge.h -- header for edge.c
|
||||
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -32,8 +32,7 @@ struct addrinfo {
|
|||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
int getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
#define _FAKE_GETNAMEINFO_H
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
cipher.c -- Symmetric block cipher handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -97,12 +97,12 @@ static bool cipher_open(cipher_t *cipher, int algo, int mode) {
|
|||
gcry_error_t err;
|
||||
|
||||
if(!ciphertonid(algo, mode, &cipher->nid)) {
|
||||
logger(LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
|
||||
logger(LOG_DEBUG, "Unable to intialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unable to intialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
|||
int algo, mode;
|
||||
|
||||
if(!nametocipher(name, &algo, &mode)) {
|
||||
logger(LOG_DEBUG, "Unknown cipher name '%s'!", name);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
|||
int algo, mode;
|
||||
|
||||
if(!nidtocipher(nid, &algo, &mode)) {
|
||||
logger(LOG_DEBUG, "Unknown cipher ID %d!", nid);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher ID %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
size_t reqlen = ((inlen + cipher->blklen) / cipher->blklen) * cipher->blklen;
|
||||
|
||||
if(*outlen < reqlen) {
|
||||
logger(LOG_ERR, "Error while encrypting: not enough room for padding");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: not enough room for padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -217,13 +217,13 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
||||
logger(LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cipher->padding) {
|
||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata + inlen, cipher->blklen, pad, cipher->blklen))) {
|
||||
logger(LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
if((err = gcry_cipher_decrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
||||
logger(LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
uint8_t padbyte = ((uint8_t *)outdata)[inlen - 1];
|
||||
|
||||
if(padbyte == 0 || padbyte > cipher->blklen || padbyte > inlen) {
|
||||
logger(LOG_ERR, "Error while decrypting: invalid padding");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,7 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
|
||||
for(int i = inlen - 1; i >= origlen; i--)
|
||||
if(((uint8_t *)outdata)[i] != padbyte) {
|
||||
logger(LOG_ERR, "Error while decrypting: invalid padding");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
cipher.h -- header file cipher.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
crypto.h -- header for crypto.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
digest.c -- Digest handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -75,7 +75,7 @@ static bool digesttonid(int algo, int *nid) {
|
|||
|
||||
static bool digest_open(digest_t *digest, int algo, int maclength) {
|
||||
if(!digesttonid(algo, &digest->nid)) {
|
||||
logger(LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
|
|||
int algo;
|
||||
|
||||
if(!nametodigest(name, &algo)) {
|
||||
logger(LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
|
|||
int algo;
|
||||
|
||||
if(!nidtodigest(nid, &algo)) {
|
||||
logger(LOG_DEBUG, "Unknown digest ID %d!", nid);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest ID %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
digest.h -- header file digest.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
rsa.c -- RSA key handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -187,7 +187,7 @@ bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
|
|||
?: gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
|
|||
?: gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|
|||
size_t derlen;
|
||||
|
||||
if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof derbuf, &derlen)) {
|
||||
logger(LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|
|||
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|
||||
|| derlen) {
|
||||
logger(LOG_ERR, "Error while decoding RSA public key");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA public key");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|
|||
size_t derlen;
|
||||
|
||||
if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof derbuf, &derlen)) {
|
||||
logger(LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|
|||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // u
|
||||
|| derlen) {
|
||||
logger(LOG_ERR, "Error while decoding RSA private key");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA private key");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ size_t rsa_size(rsa_t *rsa) {
|
|||
*/
|
||||
|
||||
// TODO: get rid of this macro, properly clean up gcry_ structures after use
|
||||
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
|
||||
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(DEBUG_ALWAYS, LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
|
||||
|
||||
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
gcry_mpi_t inmpi;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
rsagen.c -- RSA key generation and export
|
||||
Copyright (C) 2008 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2008-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -164,12 +164,12 @@ bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
|
|||
if(!ber_write_mpi(&derp1, &derlen1, &rsa->n)
|
||||
|| !ber_write_mpi(&derp1, &derlen1, &rsa->e)
|
||||
|| !ber_write_sequence(&derp2, &derlen2, derbuf1, derlen1)) {
|
||||
logger(LOG_ERR, "Error while encoding RSA public key");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA public key");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pem_encode(fp, "RSA PUBLIC KEY", derbuf2, derlen2)) {
|
||||
logger(LOG_ERR, "Unable to write RSA public key: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA public key: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -193,12 +193,12 @@ bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
|
|||
|| ber_write_mpi(&derp1, &derlen1, &exp1)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &exp2)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &coeff))
|
||||
logger(LOG_ERR, "Error while encoding RSA private key");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA private key");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pem_encode(fp, "RSA PRIVATE KEY", derbuf2, derlen2)) {
|
||||
logger(LOG_ERR, "Unable to write RSA private key: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA private key: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
221
src/graph.c
221
src/graph.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
graph.c -- graph algorithms
|
||||
Copyright (C) 2001-2011 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -44,12 +44,12 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "config.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "edge.h"
|
||||
#include "graph.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
|
@ -65,34 +65,22 @@
|
|||
Please note that sorting on weight is already done by add_edge().
|
||||
*/
|
||||
|
||||
void mst_kruskal(void) {
|
||||
splay_node_t *node, *next;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
connection_t *c;
|
||||
|
||||
static void mst_kruskal(void) {
|
||||
/* Clear MST status on connections */
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
for list_each(connection_t, c, connection_list)
|
||||
c->status.mst = false;
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
for splay_each(node_t, n, node_tree)
|
||||
n->status.visited = false;
|
||||
}
|
||||
|
||||
/* Add safe edges */
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
e = node->data;
|
||||
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(!e->reverse || (e->from->status.visited && e->to->status.visited))
|
||||
continue;
|
||||
|
||||
|
@ -105,31 +93,21 @@ void mst_kruskal(void) {
|
|||
if(e->reverse->connection)
|
||||
e->reverse->connection->status.mst = true;
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
|
||||
e->to->name, e->weight);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implementation of Dijkstra's algorithm.
|
||||
Running time: O(N^2)
|
||||
/* Implementation of a simple breadth-first search algorithm.
|
||||
Running time: O(E)
|
||||
*/
|
||||
|
||||
static void sssp_dijkstra(void) {
|
||||
splay_node_t *node, *to;
|
||||
edge_t *e;
|
||||
node_t *n, *m;
|
||||
list_t *todo_list;
|
||||
list_node_t *lnode, *nnode;
|
||||
bool indirect;
|
||||
|
||||
todo_list = list_alloc(NULL);
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:");
|
||||
static void sssp_bfs(void) {
|
||||
list_t *todo_list = list_alloc(NULL);
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
n->status.visited = false;
|
||||
n->status.indirect = true;
|
||||
n->distance = -1;
|
||||
|
@ -137,119 +115,23 @@ static void sssp_dijkstra(void) {
|
|||
|
||||
/* Begin with myself */
|
||||
|
||||
myself->status.visited = true;
|
||||
myself->status.indirect = false;
|
||||
myself->nexthop = myself;
|
||||
myself->prevedge = NULL;
|
||||
myself->via = myself;
|
||||
myself->distance = 0;
|
||||
list_insert_head(todo_list, myself);
|
||||
|
||||
/* Loop while todo_list is filled */
|
||||
|
||||
while(todo_list->head) {
|
||||
n = NULL;
|
||||
nnode = NULL;
|
||||
for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Examining edges from %s", n->name);
|
||||
|
||||
/* Select node from todo_list with smallest distance */
|
||||
|
||||
for(lnode = todo_list->head; lnode; lnode = lnode->next) {
|
||||
m = lnode->data;
|
||||
if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) {
|
||||
n = m;
|
||||
nnode = lnode;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark this node as visited and remove it from the todo_list */
|
||||
|
||||
n->status.visited = true;
|
||||
list_unlink_node(todo_list, nnode);
|
||||
|
||||
/* Update distance of neighbours and add them to the todo_list */
|
||||
|
||||
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
|
||||
e = to->data;
|
||||
|
||||
if(e->to->status.visited || !e->reverse)
|
||||
continue;
|
||||
|
||||
/* Situation:
|
||||
|
||||
/
|
||||
/
|
||||
----->(n)---e-->(e->to)
|
||||
\
|
||||
\
|
||||
|
||||
Where e is an edge, (n) and (e->to) are nodes.
|
||||
n->address is set to the e->address of the edge left of n to n.
|
||||
We are currently examining the edge e right of n from n:
|
||||
|
||||
- If edge e provides for better reachability of e->to, update e->to.
|
||||
*/
|
||||
|
||||
if(e->to->distance < 0)
|
||||
list_insert_tail(todo_list, e->to);
|
||||
|
||||
indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address));
|
||||
|
||||
if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight)
|
||||
continue;
|
||||
|
||||
e->to->distance = n->distance + e->weight;
|
||||
e->to->status.indirect = indirect;
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
|
||||
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
|
||||
update_node_udp(e->to, &e->address);
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name,
|
||||
e->to->name, e->weight, e->to->distance);
|
||||
}
|
||||
}
|
||||
|
||||
list_free(todo_list);
|
||||
}
|
||||
|
||||
/* Implementation of a simple breadth-first search algorithm.
|
||||
Running time: O(E)
|
||||
*/
|
||||
|
||||
void sssp_bfs(void) {
|
||||
splay_node_t *node, *to;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
list_t *todo_list;
|
||||
list_node_t *from, *todonext;
|
||||
bool indirect;
|
||||
|
||||
todo_list = list_alloc(NULL);
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
n->status.visited = false;
|
||||
n->status.indirect = true;
|
||||
}
|
||||
|
||||
/* Begin with myself */
|
||||
|
||||
myself->status.visited = true;
|
||||
myself->status.indirect = false;
|
||||
myself->nexthop = myself;
|
||||
myself->via = myself;
|
||||
list_insert_head(todo_list, myself);
|
||||
|
||||
/* Loop while todo_list is filled */
|
||||
|
||||
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
|
||||
n = from->data;
|
||||
|
||||
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
|
||||
e = to->data;
|
||||
if(n->distance < 0)
|
||||
abort();
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
|
||||
if(!e->reverse)
|
||||
continue;
|
||||
|
||||
|
@ -270,61 +152,63 @@ void sssp_bfs(void) {
|
|||
of nodes behind it.
|
||||
*/
|
||||
|
||||
indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||
bool indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||
|
||||
if(e->to->status.visited
|
||||
&& (!e->to->status.indirect || indirect))
|
||||
&& (!e->to->status.indirect || indirect)
|
||||
&& (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
|
||||
continue;
|
||||
|
||||
e->to->status.visited = true;
|
||||
e->to->status.indirect = indirect;
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
e->to->prevedge = e;
|
||||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
e->to->distance = n->distance + 1;
|
||||
|
||||
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
|
||||
if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN))
|
||||
update_node_udp(e->to, &e->address);
|
||||
|
||||
list_insert_tail(todo_list, e->to);
|
||||
}
|
||||
|
||||
todonext = from->next;
|
||||
list_delete_node(todo_list, from);
|
||||
next = node->next; /* Because the list_insert_tail() above could have added something extra for us! */
|
||||
list_delete_node(todo_list, node);
|
||||
}
|
||||
|
||||
list_free(todo_list);
|
||||
}
|
||||
|
||||
static void check_reachability(void) {
|
||||
splay_node_t *node, *next;
|
||||
node_t *n;
|
||||
char *name;
|
||||
char *address, *port;
|
||||
char *envp[7];
|
||||
int i;
|
||||
|
||||
/* Check reachability status. */
|
||||
|
||||
for(node = node_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
n = node->data;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n->status.visited != n->status.reachable) {
|
||||
n->status.reachable = !n->status.reachable;
|
||||
n->last_state_change = time(NULL);
|
||||
|
||||
if(n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
n->name, n->hostname);
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
n->name, n->hostname);
|
||||
}
|
||||
|
||||
if(experimental && OPTION_VERSION(n->options) >= 2)
|
||||
n->status.sptps = true;
|
||||
|
||||
/* TODO: only clear status.validkey if node is unreachable? */
|
||||
|
||||
n->status.validkey = false;
|
||||
if(n->status.sptps) {
|
||||
sptps_stop(&n->sptps);
|
||||
n->status.waitingforkey = false;
|
||||
}
|
||||
n->last_req_key = 0;
|
||||
|
||||
n->status.udp_confirmed = false;
|
||||
n->maxmtu = MTU;
|
||||
n->minmtu = 0;
|
||||
n->mtuprobes = 0;
|
||||
|
@ -332,6 +216,11 @@ static void check_reachability(void) {
|
|||
if(timeout_initialized(&n->mtuevent))
|
||||
event_del(&n->mtuevent);
|
||||
|
||||
char *name;
|
||||
char *address;
|
||||
char *port;
|
||||
char *envp[7];
|
||||
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
|
@ -343,31 +232,37 @@ static void check_reachability(void) {
|
|||
|
||||
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
||||
|
||||
xasprintf(&name,
|
||||
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
|
||||
n->name);
|
||||
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
|
||||
execute_script(name, envp);
|
||||
|
||||
free(name);
|
||||
free(address);
|
||||
free(port);
|
||||
|
||||
for(i = 0; i < 6; i++)
|
||||
for(int i = 0; i < 6; i++)
|
||||
free(envp[i]);
|
||||
|
||||
subnet_update(n, NULL, n->status.reachable);
|
||||
|
||||
if(!n->status.reachable)
|
||||
if(!n->status.reachable) {
|
||||
update_node_udp(n, NULL);
|
||||
else if(n->connection)
|
||||
memset(&n->status, 0, sizeof n->status);
|
||||
n->options = 0;
|
||||
} else if(n->connection) {
|
||||
if(n->status.sptps) {
|
||||
if(n->connection->outgoing)
|
||||
send_req_key(n);
|
||||
} else {
|
||||
send_ans_key(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graph(void) {
|
||||
subnet_cache_flush();
|
||||
sssp_dijkstra();
|
||||
sssp_bfs();
|
||||
check_reachability();
|
||||
mst_kruskal();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
graph.h -- header for graph.c
|
||||
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
105
src/hash.c
Normal file
105
src/hash.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
hash.c -- hash table management
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "hash.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Generic hash function */
|
||||
|
||||
static uint32_t hash_function(const void *p, size_t len) {
|
||||
const uint8_t *q = p;
|
||||
uint32_t hash = 0;
|
||||
while(true) {
|
||||
for(int i = len > 4 ? 4 : len; --i;)
|
||||
hash += q[i] << (8 * i);
|
||||
hash *= 0x9e370001UL; // Golden ratio prime.
|
||||
if(len <= 4)
|
||||
break;
|
||||
len -= 4;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Map 32 bits int onto 0..n-1, without throwing away too many bits if n is 2^8 or 2^16 */
|
||||
|
||||
static uint32_t modulo(uint32_t hash, size_t n) {
|
||||
if(n == 0x100)
|
||||
return (hash >> 24) ^ ((hash >> 16) & 0xff) ^ ((hash >> 8) & 0xff) ^ (hash & 0xff);
|
||||
else if(n == 0x10000)
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
else
|
||||
return hash % n;
|
||||
}
|
||||
|
||||
/* (De)allocation */
|
||||
|
||||
hash_t *hash_alloc(size_t n, size_t size) {
|
||||
hash_t *hash = xmalloc_and_zero(sizeof *hash);
|
||||
hash->n = n;
|
||||
hash->size = size;
|
||||
hash->keys = xmalloc(hash->n * hash->size);
|
||||
hash->values = xmalloc_and_zero(hash->n * sizeof *hash->values);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void hash_free(hash_t *hash) {
|
||||
free(hash->keys);
|
||||
free(hash->values);
|
||||
free(hash);
|
||||
}
|
||||
|
||||
/* Searching and inserting */
|
||||
|
||||
void hash_insert(hash_t *hash, const void *key, const void *value) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
memcpy(hash->keys + i * hash->size, key, hash->size);
|
||||
hash->values[i] = value;
|
||||
}
|
||||
|
||||
void *hash_search(const hash_t *hash, const void *key) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
|
||||
return (void *)hash->values[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *hash_search_or_insert(hash_t *hash, const void *key, const void *value) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size))
|
||||
return (void *)hash->values[i];
|
||||
memcpy(hash->keys + i * hash->size, key, hash->size);
|
||||
hash->values[i] = value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
void hash_clear(hash_t *hash) {
|
||||
memset(hash->values, 0, hash->n * sizeof *hash->values);
|
||||
}
|
||||
|
||||
void hash_resize(hash_t *hash, size_t n) {
|
||||
hash->keys = xrealloc(hash->keys, n * hash->size);
|
||||
hash->values = xrealloc(hash->values, n * sizeof *hash->values);
|
||||
if(n > hash->n)
|
||||
memset(hash->values + hash->n, 0, (n - hash->n) * sizeof *hash->values);
|
||||
}
|
41
src/hash.h
Normal file
41
src/hash.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
hash.h -- header file for hash.c
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_HASH_H__
|
||||
#define __TINC_HASH_H__
|
||||
|
||||
typedef struct hash_t {
|
||||
size_t n;
|
||||
size_t size;
|
||||
char *keys;
|
||||
const void **values;
|
||||
} hash_t;
|
||||
|
||||
extern hash_t *hash_alloc(size_t n, size_t size) __attribute__ ((__malloc__));
|
||||
extern void hash_free(hash_t *);
|
||||
|
||||
extern void hash_insert(hash_t *, const void *key, const void *value);
|
||||
|
||||
extern void *hash_search(const hash_t *, const void *key);
|
||||
extern void *hash_search_or_insert(hash_t *, const void *key, const void *value);
|
||||
|
||||
extern void hash_clear(hash_t *);
|
||||
extern void hash_resize(hash_t *, size_t n);
|
||||
|
||||
#endif /* __TINC_HASH_H__ */
|
266
src/info.c
Normal file
266
src/info.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
info.c -- Show information about a node, subnet or address
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "control_common.h"
|
||||
#include "list.h"
|
||||
#include "subnet.h"
|
||||
#include "tincctl.h"
|
||||
#include "info.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
char *strip_weight(char *netstr) {
|
||||
int len = strlen(netstr);
|
||||
if(len >= 3 && !strcmp(netstr + len - 3, "#10"))
|
||||
netstr[len - 3] = 0;
|
||||
return netstr;
|
||||
}
|
||||
|
||||
static int info_node(int fd, const char *item) {
|
||||
// Check the list of nodes
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_NODES, item);
|
||||
|
||||
bool found = false;
|
||||
char line[4096];
|
||||
|
||||
char node[4096];
|
||||
char from[4096];
|
||||
char to[4096];
|
||||
char subnet[4096];
|
||||
char host[4096];
|
||||
char port[4096];
|
||||
char via[4096];
|
||||
char nexthop[4096];
|
||||
int code, req, cipher, digest, maclength, compression, distance;
|
||||
short int pmtu, minmtu, maxmtu;
|
||||
unsigned int options;
|
||||
node_status_t status;
|
||||
long int last_state_change;
|
||||
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
|
||||
|
||||
if(n == 2)
|
||||
break;
|
||||
|
||||
if(n != 18) {
|
||||
fprintf(stderr, "Unable to parse node dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(node, item)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
fprintf(stderr, "Unknown node %s.\n", item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Node: %s\n", item);
|
||||
printf("Address: %s port %s\n", host, port);
|
||||
|
||||
char timestr[32] = "never";
|
||||
if(last_state_change)
|
||||
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&last_state_change));
|
||||
|
||||
if(status.reachable)
|
||||
printf("Online since: %s\n", timestr);
|
||||
else
|
||||
printf("Last seen: %s\n", timestr);
|
||||
|
||||
printf("Status: ");
|
||||
if(status.validkey)
|
||||
printf(" validkey");
|
||||
if(status.visited)
|
||||
printf(" visited");
|
||||
if(status.reachable)
|
||||
printf(" reachable");
|
||||
if(status.indirect)
|
||||
printf(" indirect");
|
||||
if(status.sptps)
|
||||
printf(" sptps");
|
||||
if(status.udp_confirmed)
|
||||
printf(" udp_confirmed");
|
||||
printf("\n");
|
||||
|
||||
printf("Options: ");
|
||||
if(options & OPTION_INDIRECT)
|
||||
printf(" indirect");
|
||||
if(options & OPTION_TCPONLY)
|
||||
printf(" tcponly");
|
||||
if(options & OPTION_PMTU_DISCOVERY)
|
||||
printf(" pmtu_discovery");
|
||||
if(options & OPTION_CLAMP_MSS)
|
||||
printf(" clamp_mss");
|
||||
printf("\n");
|
||||
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
|
||||
printf("Reachability: ");
|
||||
if(!strcmp(host, "MYSELF"))
|
||||
printf("can reach itself\n");
|
||||
else if(!status.reachable)
|
||||
printf("unreachable\n");
|
||||
else if(strcmp(via, item))
|
||||
printf("indirectly via %s\n", via);
|
||||
else if(!status.validkey)
|
||||
printf("unknown\n");
|
||||
else if(minmtu > 0)
|
||||
printf("directly with UDP\nPMTU: %d\n", pmtu);
|
||||
else if(!strcmp(nexthop, item))
|
||||
printf("directly with TCP\n");
|
||||
else
|
||||
printf("none, forwarded via %s\n", nexthop);
|
||||
|
||||
// List edges
|
||||
printf("Edges: ");
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
int n = sscanf(line, "%d %d %s %s", &code, &req, from, to);
|
||||
if(n == 2)
|
||||
break;
|
||||
if(n != 4) {
|
||||
fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
|
||||
return 1;
|
||||
}
|
||||
if(!strcmp(from, item))
|
||||
printf(" %s", to);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// List subnets
|
||||
printf("Subnets: ");
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
int n = sscanf(line, "%d %d %s %s", &code, &req, subnet, from);
|
||||
if(n == 2)
|
||||
break;
|
||||
if(n != 4) {
|
||||
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
if(!strcmp(from, item))
|
||||
printf(" %s", strip_weight(subnet));
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int info_subnet(int fd, const char *item) {
|
||||
subnet_t subnet, find;
|
||||
|
||||
if(!str2net(&find, item)) {
|
||||
fprintf(stderr, "Could not parse subnet or address '%s'.\n", item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool address = !strchr(item, '/');
|
||||
bool weight = strchr(item, '#');
|
||||
bool found = false;
|
||||
|
||||
char line[4096];
|
||||
char netstr[4096];
|
||||
char owner[4096];
|
||||
|
||||
int code, req;
|
||||
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
int n = sscanf(line, "%d %d %s %s", &code, &req, netstr, owner);
|
||||
if(n == 2)
|
||||
break;
|
||||
|
||||
if(n != 4 || !str2net(&subnet, netstr)) {
|
||||
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(find.type != subnet.type)
|
||||
continue;
|
||||
|
||||
if(weight) {
|
||||
if(find.weight != subnet.weight)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(find.type == SUBNET_IPV4) {
|
||||
if(address) {
|
||||
if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength))
|
||||
continue;
|
||||
} else {
|
||||
if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength)
|
||||
continue;
|
||||
if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
|
||||
continue;
|
||||
}
|
||||
} else if(find.type == SUBNET_IPV6) {
|
||||
if(address) {
|
||||
if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength))
|
||||
continue;
|
||||
} else {
|
||||
if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength)
|
||||
continue;
|
||||
if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
|
||||
continue;
|
||||
}
|
||||
} if(find.type == SUBNET_MAC) {
|
||||
if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof subnet.net.mac))
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
printf("Subnet: %s\n", strip_weight(netstr));
|
||||
printf("Owner: %s\n", owner);
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
if(address)
|
||||
fprintf(stderr, "Unknown address %s.\n", item);
|
||||
else
|
||||
fprintf(stderr, "Unknown subnet %s.\n", item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int info(int fd, const char *item) {
|
||||
if(check_id(item))
|
||||
return info_node(fd, item);
|
||||
if(strchr(item, '.') || strchr(item, ':'))
|
||||
return info_subnet(fd, item);
|
||||
|
||||
fprintf(stderr, "Argument is not a node name, subnet or address.\n");
|
||||
return 1;
|
||||
}
|
27
src/info.h
Normal file
27
src/info.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
info.h -- header for info.c.
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_INFO_H__
|
||||
#define __TINC_INFO_H__
|
||||
|
||||
extern int info(int fd, const char *item);
|
||||
extern char *strip_weight(char *);
|
||||
|
||||
#endif
|
||||
|
10
src/ipv4.h
10
src/ipv4.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
ipv4.h -- missing IPv4 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -41,6 +41,14 @@
|
|||
#define ICMP_NET_UNKNOWN 6
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_TIME_EXCEEDED
|
||||
#define ICMP_TIME_EXCEEDED 11
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_EXC_TTL
|
||||
#define ICMP_EXC_TTL 0
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_UNREACH
|
||||
#define ICMP_NET_UNREACH 0
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
ipv6.h -- missing IPv6 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -95,8 +95,10 @@ struct icmp6_hdr {
|
|||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
#define ICMP6_TIME_EXCEEDED 3
|
||||
#define ICMP6_DST_UNREACH_ADMIN 1
|
||||
#define ICMP6_DST_UNREACH_ADDR 3
|
||||
#define ICMP6_TIME_EXCEED_TRANSIT 0
|
||||
#define ND_NEIGHBOR_SOLICIT 135
|
||||
#define ND_NEIGHBOR_ADVERT 136
|
||||
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Linux ethertap and tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -41,6 +41,7 @@ int device_fd = -1;
|
|||
static device_type_t device_type;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *type = NULL;
|
||||
static char ifrname[IFNAMSIZ];
|
||||
static char *device_info;
|
||||
|
||||
|
@ -49,27 +50,35 @@ uint64_t device_in_bytes = 0;
|
|||
uint64_t device_out_packets = 0;
|
||||
uint64_t device_out_bytes = 0;
|
||||
|
||||
bool setup_device(void) {
|
||||
static bool setup_device(void) {
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
if (netname != NULL)
|
||||
if(netname)
|
||||
iface = xstrdup(netname);
|
||||
#else
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
#endif
|
||||
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
struct ifreq ifr = {{{0}}};
|
||||
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
get_config_string(lookup_config(config_tree, "DeviceType"), &type);
|
||||
|
||||
if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((type && !strcasecmp(type, "tun")) || (!type && routing_mode == RMODE_ROUTER)) {
|
||||
ifr.ifr_flags = IFF_TUN;
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
device_info = "Linux tun/tap device (tun mode)";
|
||||
|
@ -92,28 +101,24 @@ bool setup_device(void) {
|
|||
|
||||
if(!ioctl(device_fd, TUNSETIFF, &ifr)) {
|
||||
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
|
||||
if(iface) free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
|
||||
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
|
||||
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
|
||||
if(iface) free(iface);
|
||||
free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
|
||||
free(type);
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
switch(device_type) {
|
||||
|
@ -121,18 +126,19 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
inlen = read(device_fd, packet->data + 10, MTU - 10);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
break;
|
||||
case DEVICE_TYPE_TAP:
|
||||
inlen = read(device_fd, packet->data, MTU);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -146,28 +152,28 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
device_in_packets++;
|
||||
device_in_bytes += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
packet->data[10] = packet->data[11] = 0;
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -182,8 +188,16 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
42
src/list.c
42
src/list.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
list.c -- functions to deal with double linked lists
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -26,9 +26,7 @@
|
|||
/* (De)constructors */
|
||||
|
||||
list_t *list_alloc(list_action_t delete) {
|
||||
list_t *list;
|
||||
|
||||
list = xmalloc_and_zero(sizeof(list_t));
|
||||
list_t *list = xmalloc_and_zero(sizeof(list_t));
|
||||
list->delete = delete;
|
||||
|
||||
return list;
|
||||
|
@ -52,9 +50,7 @@ void list_free_node(list_t *list, list_node_t *node) {
|
|||
/* Insertion and deletion */
|
||||
|
||||
list_node_t *list_insert_head(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
list_node_t *node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->prev = NULL;
|
||||
|
@ -72,9 +68,7 @@ list_node_t *list_insert_head(list_t *list, void *data) {
|
|||
}
|
||||
|
||||
list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
list_node_t *node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
|
@ -92,9 +86,7 @@ list_node_t *list_insert_tail(list_t *list, void *data) {
|
|||
}
|
||||
|
||||
list_node_t *list_insert_after(list_t *list, list_node_t *after, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
list_node_t *node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = after->next;
|
||||
|
@ -158,6 +150,12 @@ void list_delete_tail(list_t *list) {
|
|||
list_delete_node(list, list->tail);
|
||||
}
|
||||
|
||||
void list_delete(list_t *list, const void *data) {
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
if(node->data == data)
|
||||
list_delete_node(list, node);
|
||||
}
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
void *list_get_head(list_t *list) {
|
||||
|
@ -177,12 +175,8 @@ void *list_get_tail(list_t *list) {
|
|||
/* Fast list deletion */
|
||||
|
||||
void list_delete_list(list_t *list) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
list_free(list);
|
||||
}
|
||||
|
@ -190,20 +184,12 @@ void list_delete_list(list_t *list) {
|
|||
/* Traversing */
|
||||
|
||||
void list_foreach_node(list_t *list, list_action_node_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
void list_foreach(list_t *list, list_action_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
if(node->data)
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
list.h -- header file for list.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -57,6 +57,8 @@ extern list_node_t *list_insert_tail(list_t *, void *);
|
|||
extern list_node_t *list_insert_after(list_t *, list_node_t *, void *);
|
||||
extern list_node_t *list_insert_before(list_t *, list_node_t *, void *);
|
||||
|
||||
extern void list_delete(list_t *, const void *);
|
||||
|
||||
extern void list_unlink_node(list_t *, list_node_t *);
|
||||
extern void list_delete_node(list_t *, list_node_t *);
|
||||
|
||||
|
@ -77,4 +79,6 @@ extern void list_delete_list(list_t *);
|
|||
extern void list_foreach(list_t *, list_action_t);
|
||||
extern void list_foreach_node(list_t *, list_action_node_t);
|
||||
|
||||
#define list_each(type, item, list) (type *item = (type *)1; item; item = NULL) for(list_node_t *node = (list)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
|
||||
|
||||
#endif /* __TINC_LIST_H__ */
|
||||
|
|
145
src/logger.c
145
src/logger.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
logger.c -- logging code
|
||||
Copyright (C) 2004-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2004-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2004-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -21,7 +21,11 @@
|
|||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "meta.h"
|
||||
#include "logger.h"
|
||||
#include "connection.h"
|
||||
#include "control_common.h"
|
||||
#include "sptps.h"
|
||||
|
||||
debug_t debug_level = DEBUG_NOTHING;
|
||||
static logmode_t logmode = LOGMODE_STDERR;
|
||||
|
@ -32,6 +36,89 @@ static FILE *logfile = NULL;
|
|||
static HANDLE loghandle = NULL;
|
||||
#endif
|
||||
static const char *logident = NULL;
|
||||
bool logcontrol = false;
|
||||
|
||||
|
||||
static void real_logger(int level, int priority, const char *message) {
|
||||
char timestr[32] = "";
|
||||
time_t now;
|
||||
static bool suppress = false;
|
||||
|
||||
// Bail out early if there is nothing to do.
|
||||
if(suppress)
|
||||
return;
|
||||
|
||||
if(!logcontrol && (level > debug_level || logmode == LOGMODE_NULL))
|
||||
return;
|
||||
|
||||
if(level <= debug_level) {
|
||||
switch(logmode) {
|
||||
case LOGMODE_STDERR:
|
||||
fprintf(stderr, "%s\n", message);
|
||||
fflush(stderr);
|
||||
break;
|
||||
case LOGMODE_FILE:
|
||||
now = time(NULL);
|
||||
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
|
||||
fflush(logfile);
|
||||
break;
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
{
|
||||
const char *messages[] = {message};
|
||||
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
|
||||
}
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
syslog(priority, "%s", message);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(logcontrol) {
|
||||
suppress = true;
|
||||
logcontrol = false;
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->status.log)
|
||||
continue;
|
||||
logcontrol = true;
|
||||
if(level > (c->outcompression >= 0 ? c->outcompression : debug_level))
|
||||
continue;
|
||||
int len = strlen(message);
|
||||
if(send_request(c, "%d %d %d", CONTROL, REQ_LOG, len))
|
||||
send_meta(c, message, len);
|
||||
}
|
||||
suppress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
char message[1024] = "";
|
||||
|
||||
va_start(ap, format);
|
||||
int len = vsnprintf(message, sizeof message, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
|
||||
message[len - 1] = 0;
|
||||
|
||||
real_logger(level, priority, message);
|
||||
}
|
||||
|
||||
static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) {
|
||||
char message[1024] = "";
|
||||
int len = vsnprintf(message, sizeof message, format, ap);
|
||||
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
|
||||
message[len - 1] = 0;
|
||||
|
||||
real_logger(DEBUG_ALWAYS, LOG_ERR, message);
|
||||
}
|
||||
|
||||
void openlogger(const char *ident, logmode_t mode) {
|
||||
logident = ident;
|
||||
|
@ -66,6 +153,11 @@ void openlogger(const char *ident, logmode_t mode) {
|
|||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
if(logmode != LOGMODE_NULL)
|
||||
sptps_log = sptps_logger;
|
||||
else
|
||||
sptps_log = sptps_log_quiet;
|
||||
}
|
||||
|
||||
void reopenlogger() {
|
||||
|
@ -75,62 +167,13 @@ void reopenlogger() {
|
|||
fflush(logfile);
|
||||
FILE *newfile = fopen(logfilename, "a");
|
||||
if(!newfile) {
|
||||
logger(LOG_ERR, "Unable to reopen log file %s: %s\n", logfilename, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
fclose(logfile);
|
||||
logfile = newfile;
|
||||
}
|
||||
|
||||
void logger(int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
char timestr[32] = "";
|
||||
time_t now;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
switch(logmode) {
|
||||
case LOGMODE_STDERR:
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
break;
|
||||
case LOGMODE_FILE:
|
||||
now = time(NULL);
|
||||
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid);
|
||||
vfprintf(logfile, format, ap);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
break;
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
{
|
||||
char message[4096];
|
||||
const char *messages[] = {message};
|
||||
vsnprintf(message, sizeof message, format, ap);
|
||||
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
|
||||
}
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#ifdef HAVE_VSYSLOG
|
||||
vsyslog(priority, format, ap);
|
||||
#else
|
||||
{
|
||||
char message[4096];
|
||||
vsnprintf(message, sizeof message, format, ap);
|
||||
syslog(priority, "%s", message);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void closelogger(void) {
|
||||
switch(logmode) {
|
||||
|
|
25
src/logger.h
25
src/logger.h
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
logger.h -- header file for logger.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_LOGGER_H__
|
||||
#define __TINC_LOGGER_H__
|
||||
|
||||
|
@ -46,11 +66,10 @@ enum {
|
|||
#endif
|
||||
|
||||
extern debug_t debug_level;
|
||||
extern bool logcontrol;
|
||||
extern void openlogger(const char *, logmode_t);
|
||||
extern void reopenlogger(void);
|
||||
extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
|
||||
extern void logger(int, int, const char *, ...) __attribute__ ((__format__(printf, 3, 4)));
|
||||
extern void closelogger(void);
|
||||
|
||||
#define ifdebug(l) if(debug_level >= DEBUG_##l)
|
||||
|
||||
#endif /* __TINC_LOGGER_H__ */
|
||||
|
|
92
src/meta.c
92
src/meta.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.c -- handle the meta communication
|
||||
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "cipher.h"
|
||||
#include "connection.h"
|
||||
#include "logger.h"
|
||||
|
@ -31,21 +30,38 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
bool send_meta(connection_t *c, const char *buffer, int length) {
|
||||
bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t length) {
|
||||
connection_t *c = handle;
|
||||
|
||||
if(!c) {
|
||||
logger(LOG_ERR, "send_meta() called with NULL pointer!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta_sptps() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
|
||||
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
event_add(&c->outevent, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_meta(connection_t *c, const char *buffer, int length) {
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
|
||||
logger(DEBUG_META, LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
|
||||
c->name, c->hostname);
|
||||
|
||||
if(c->protocol_minor >= 2)
|
||||
return sptps_send_record(&c->sptps, 0, buffer, length);
|
||||
|
||||
/* Add our data to buffer */
|
||||
if(c->status.encryptout) {
|
||||
size_t outlen = length;
|
||||
|
||||
if(!cipher_encrypt(&c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
|
||||
logger(LOG_ERR, "Error while encrypting metadata to %s (%s)",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
@ -60,15 +76,47 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
|
|||
}
|
||||
|
||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||
splay_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c != from && c->status.active)
|
||||
send_meta(c, buffer, length);
|
||||
}
|
||||
|
||||
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
|
||||
connection_t *c = handle;
|
||||
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "receive_meta_sptps() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
|
||||
if(type == SPTPS_HANDSHAKE) {
|
||||
if(c->allow_request == ACK)
|
||||
return send_ack(c);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!data)
|
||||
return true;
|
||||
|
||||
/* Are we receiving a TCPpacket? */
|
||||
|
||||
if(c->tcplen) {
|
||||
if(length != c->tcplen)
|
||||
return false;
|
||||
receive_tcppacket(c, data, length);
|
||||
c->tcplen = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Change newline to null byte, just like non-SPTPS requests */
|
||||
|
||||
if(data[length - 1] == '\n')
|
||||
((char *)data)[length - 1] = 0;
|
||||
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
return receive_request(c, data);
|
||||
}
|
||||
|
||||
bool receive_meta(connection_t *c) {
|
||||
|
@ -88,7 +136,7 @@ bool receive_meta(connection_t *c) {
|
|||
buffer_compact(&c->inbuf, MAXBUFSIZE);
|
||||
|
||||
if(sizeof inbuf <= c->inbuf.len) {
|
||||
logger(LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -96,17 +144,20 @@ bool receive_meta(connection_t *c) {
|
|||
|
||||
if(inlen <= 0) {
|
||||
if(!inlen || !errno) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno))
|
||||
return true;
|
||||
else
|
||||
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if(c->protocol_minor >= 2)
|
||||
return sptps_receive_data(&c->sptps, bufp, inlen);
|
||||
|
||||
if(!c->status.decryptin) {
|
||||
endp = memchr(bufp, '\n', inlen);
|
||||
if(endp)
|
||||
|
@ -120,10 +171,9 @@ bool receive_meta(connection_t *c) {
|
|||
bufp = endp;
|
||||
} else {
|
||||
size_t outlen = inlen;
|
||||
ifdebug(META) logger(LOG_DEBUG, "Received encrypted %d bytes", inlen);
|
||||
|
||||
if(!cipher_decrypt(&c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) {
|
||||
logger(LOG_ERR, "Error while decrypting metadata from %s (%s)",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
@ -137,6 +187,14 @@ bool receive_meta(connection_t *c) {
|
|||
if(c->tcplen) {
|
||||
char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
|
||||
if(tcpbuffer) {
|
||||
if(proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
|
||||
if(tcpbuffer[0] == 0 && tcpbuffer[1] == 0x5a) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
receive_tcppacket(c, tcpbuffer, c->tcplen);
|
||||
c->tcplen = 0;
|
||||
continue;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.h -- header for meta.c
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -24,6 +24,8 @@
|
|||
#include "connection.h"
|
||||
|
||||
extern bool send_meta(struct connection_t *, const char *, int);
|
||||
extern bool send_meta_sptps(void *, uint8_t, const char *, size_t);
|
||||
extern bool receive_meta_sptps(void *, uint8_t, const char *, uint16_t);
|
||||
extern void broadcast_meta(struct connection_t *, const char *, int);
|
||||
extern bool receive_meta(struct connection_t *);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a MinGW environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -50,7 +50,7 @@ static DWORD WINAPI tapreader(void *bla) {
|
|||
OVERLAPPED overlapped;
|
||||
vpn_packet_t packet;
|
||||
|
||||
logger(LOG_DEBUG, "Tap reader running");
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader running");
|
||||
|
||||
/* Read from tap device and send to parent */
|
||||
|
||||
|
@ -69,7 +69,7 @@ static DWORD WINAPI tapreader(void *bla) {
|
|||
if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
|
||||
continue;
|
||||
} else {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ static DWORD WINAPI tapreader(void *bla) {
|
|||
}
|
||||
}
|
||||
|
||||
bool setup_device(void) {
|
||||
static bool setup_device(void) {
|
||||
HKEY key, key2;
|
||||
int i;
|
||||
|
||||
|
@ -105,7 +105,7 @@ bool setup_device(void) {
|
|||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ bool setup_device(void) {
|
|||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -174,14 +174,14 @@ bool setup_device(void) {
|
|||
}
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ bool setup_device(void) {
|
|||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||
|
||||
if(!thread) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -205,31 +205,31 @@ bool setup_device(void) {
|
|||
|
||||
device_info = "Windows tap device";
|
||||
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
static void close_device(void) {
|
||||
CloseHandle(device_handle);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
long outlen;
|
||||
OVERLAPPED overlapped = {0};
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -238,8 +238,16 @@ bool write_packet(vpn_packet_t *packet) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
235
src/multicast_device.c
Normal file
235
src/multicast_device.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
device.c -- multicast socket
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "device.h"
|
||||
#include "net.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
#include "utils.h"
|
||||
#include "route.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static struct addrinfo *ai = NULL;
|
||||
static mac_t ignore_src = {{0}};
|
||||
|
||||
static bool setup_device(void) {
|
||||
char *host = NULL;
|
||||
char *port;
|
||||
char *space;
|
||||
int ttl = 1;
|
||||
|
||||
device_info = "multicast socket";
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Device variable required for %s", device_info);
|
||||
goto error;
|
||||
}
|
||||
|
||||
host = xstrdup(device);
|
||||
space = strchr(host, ' ');
|
||||
if(!space) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Port number required for %s", device_info);
|
||||
goto error;
|
||||
}
|
||||
|
||||
*space++ = 0;
|
||||
port = space;
|
||||
space = strchr(port, ' ');
|
||||
|
||||
if(space) {
|
||||
*space++ = 0;
|
||||
ttl = atoi(space);
|
||||
}
|
||||
|
||||
ai = str2addrinfo(host, port, SOCK_DGRAM);
|
||||
if(!ai)
|
||||
goto error;
|
||||
|
||||
device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(device_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
static const int one = 1;
|
||||
setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one);
|
||||
|
||||
if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch(ai->ai_family) {
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
case AF_INET: {
|
||||
struct ip_mreq mreq;
|
||||
struct sockaddr_in in;
|
||||
memcpy(&in, ai->ai_addr, sizeof in);
|
||||
mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
}
|
||||
#ifdef IP_MULTICAST_LOOP
|
||||
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one);
|
||||
#endif
|
||||
#ifdef IP_MULTICAST_TTL
|
||||
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof ttl);
|
||||
#endif
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef IPV6_JOIN_GROUP
|
||||
case AF_INET6: {
|
||||
struct ipv6_mreq mreq;
|
||||
struct sockaddr_in6 in6;
|
||||
memcpy(&in6, ai->ai_addr, sizeof in6);
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr);
|
||||
mreq.ipv6mr_interface = in6.sin6_scope_id;
|
||||
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
}
|
||||
#ifdef IPV6_MULTICAST_LOOP
|
||||
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one);
|
||||
#endif
|
||||
#ifdef IPV6_MULTICAST_HOPS
|
||||
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof ttl);
|
||||
#endif
|
||||
} break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family);
|
||||
goto error;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
if(device_fd >= 0)
|
||||
closesocket(device_fd);
|
||||
if(ai)
|
||||
freeaddrinfo(ai);
|
||||
free(host);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
|
||||
if(ai)
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = recv(device_fd, packet->data, MTU, 0)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) {
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
|
||||
packet->len = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(sendto(device_fd, packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
memcpy(&ignore_src, packet->data + 6, sizeof ignore_src);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
static bool not_supported(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Raw socket device not supported on this platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = not_supported,
|
||||
.close = NULL,
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.dump_stats = NULL,
|
||||
};
|
||||
#endif
|
223
src/net.c
223
src/net.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.c -- most of the network code
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2011 Loïc Grenié <loic.grenie@gmail.com>
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
|||
#include "system.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "splay_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
|
@ -40,40 +39,28 @@
|
|||
int contradicting_add_edge = 0;
|
||||
int contradicting_del_edge = 0;
|
||||
static int sleeptime = 10;
|
||||
time_t last_config_check = 0;
|
||||
|
||||
/* Purge edges and subnets of unreachable nodes. Use carefully. */
|
||||
|
||||
void purge(void) {
|
||||
splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
subnet_t *s;
|
||||
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes");
|
||||
|
||||
/* Remove all edges and subnets owned by unreachable nodes. */
|
||||
|
||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
||||
nnext = nnode->next;
|
||||
n = nnode->data;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
|
||||
n->hostname);
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname);
|
||||
|
||||
for(snode = n->subnet_tree->head; snode; snode = snext) {
|
||||
snext = snode->next;
|
||||
s = snode->data;
|
||||
send_del_subnet(broadcast, s);
|
||||
for splay_each(subnet_t, s, n->subnet_tree) {
|
||||
send_del_subnet(everyone, s);
|
||||
if(!strictsubnets)
|
||||
subnet_del(n, s);
|
||||
}
|
||||
|
||||
for(enode = n->edge_tree->head; enode; enode = enext) {
|
||||
enext = enode->next;
|
||||
e = enode->data;
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
if(!tunnelserver)
|
||||
send_del_edge(broadcast, e);
|
||||
send_del_edge(everyone, e);
|
||||
edge_del(e);
|
||||
}
|
||||
}
|
||||
|
@ -81,20 +68,13 @@ void purge(void) {
|
|||
|
||||
/* Check if anyone else claims to have an edge to an unreachable node. If not, delete node. */
|
||||
|
||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
||||
nnext = nnode->next;
|
||||
n = nnode->data;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(!n->status.reachable) {
|
||||
for(enode = edge_weight_tree->head; enode; enode = enext) {
|
||||
enext = enode->next;
|
||||
e = enode->data;
|
||||
|
||||
for splay_each(edge_t, e, edge_weight_tree)
|
||||
if(e->to == n)
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
if(!enode && (!strictsubnets || !n->subnet_tree->head))
|
||||
if(!strictsubnets || !n->subnet_tree->head)
|
||||
/* in strictsubnets mode do not delete nodes with subnets */
|
||||
node_del(n);
|
||||
}
|
||||
|
@ -103,25 +83,25 @@ void purge(void) {
|
|||
|
||||
/*
|
||||
Terminate a connection:
|
||||
- Close the socket
|
||||
- Remove associated edge and tell other connections about it if report = true
|
||||
- Mark it as inactive
|
||||
- Remove the edge representing this connection
|
||||
- Kill it with fire
|
||||
- Check if we need to retry making an outgoing connection
|
||||
- Deactivate the host
|
||||
*/
|
||||
void terminate_connection(connection_t *c, bool report) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
|
||||
c->name, c->hostname);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname);
|
||||
|
||||
c->status.active = false;
|
||||
|
||||
if(c->node)
|
||||
if(c->node && c->node->connection == c)
|
||||
c->node->connection = NULL;
|
||||
|
||||
if(c->edge) {
|
||||
if(report && !tunnelserver)
|
||||
send_del_edge(broadcast, c->edge);
|
||||
send_del_edge(everyone, c->edge);
|
||||
|
||||
edge_del(c->edge);
|
||||
c->edge = NULL;
|
||||
|
||||
/* Run MST and SSSP algorithms */
|
||||
|
||||
|
@ -134,18 +114,19 @@ void terminate_connection(connection_t *c, bool report) {
|
|||
e = lookup_edge(c->node, myself);
|
||||
if(e) {
|
||||
if(!tunnelserver)
|
||||
send_del_edge(broadcast, e);
|
||||
send_del_edge(everyone, e);
|
||||
edge_del(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outgoing_t *outgoing = c->outgoing;
|
||||
connection_del(c);
|
||||
|
||||
/* Check if this was our outgoing connection */
|
||||
|
||||
if(c->outgoing)
|
||||
retry_outgoing(c->outgoing);
|
||||
|
||||
connection_del(c);
|
||||
if(outgoing)
|
||||
do_outgoing_connection(outgoing);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -157,42 +138,34 @@ void terminate_connection(connection_t *c, bool report) {
|
|||
and close the connection.
|
||||
*/
|
||||
static void timeout_handler(int fd, short events, void *event) {
|
||||
splay_node_t *node, *next;
|
||||
connection_t *c;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
c = node->data;
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->status.control)
|
||||
continue;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now) {
|
||||
if(c->status.active) {
|
||||
if(c->status.pinged) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
|
||||
c->name, c->hostname, now - c->last_ping_time);
|
||||
terminate_connection(c, true);
|
||||
continue;
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now - c->last_ping_time);
|
||||
} else if(c->last_ping_time + pinginterval <= now) {
|
||||
send_ping(c);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
if(c->status.connecting) {
|
||||
ifdebug(CONNECTIONS)
|
||||
logger(LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
|
||||
c->status.connecting = false;
|
||||
closesocket(c->socket);
|
||||
do_outgoing_connection(c);
|
||||
} else {
|
||||
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
|
||||
terminate_connection(c, false);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(c->status.connecting)
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
|
||||
else
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
|
||||
}
|
||||
terminate_connection(c, c->status.active);
|
||||
}
|
||||
}
|
||||
|
||||
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
|
||||
logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
|
||||
usleep(sleeptime * 1000000LL);
|
||||
sleeptime *= 2;
|
||||
if(sleeptime < 0)
|
||||
|
@ -222,11 +195,8 @@ void handle_meta_connection_data(int fd, short events, void *data) {
|
|||
if(!result)
|
||||
finish_connecting(c);
|
||||
else {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
|
||||
"Error while connecting to %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(result));
|
||||
closesocket(c->socket);
|
||||
do_outgoing_connection(c);
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result));
|
||||
terminate_connection(c, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -238,27 +208,23 @@ void handle_meta_connection_data(int fd, short events, void *data) {
|
|||
}
|
||||
|
||||
static void sigterm_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
static void sighup_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
reopenlogger();
|
||||
reload_configuration();
|
||||
}
|
||||
|
||||
static void sigalrm_handler(int signal, short events, void *data) {
|
||||
logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
retry();
|
||||
}
|
||||
|
||||
int reload_configuration(void) {
|
||||
connection_t *c;
|
||||
splay_node_t *node, *next;
|
||||
char *fname;
|
||||
struct stat s;
|
||||
static time_t last_config_check = 0;
|
||||
|
||||
/* Reread our own configuration file */
|
||||
|
||||
|
@ -266,85 +232,112 @@ int reload_configuration(void) {
|
|||
init_configuration(&config_tree);
|
||||
|
||||
if(!read_server_config()) {
|
||||
logger(LOG_ERR, "Unable to reread configuration file, exitting.");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting.");
|
||||
event_loopexit(NULL);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Close connections to hosts that have a changed or deleted host config file */
|
||||
read_config_options(config_tree, NULL);
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
c = node->data;
|
||||
next = node->next;
|
||||
|
||||
if(c->outgoing) {
|
||||
free(c->outgoing->name);
|
||||
if(c->outgoing->ai)
|
||||
freeaddrinfo(c->outgoing->ai);
|
||||
free(c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
}
|
||||
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
if(stat(fname, &s) || s.st_mtime > last_config_check)
|
||||
terminate_connection(c, c->status.active);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
|
||||
read_config_file(config_tree, fname);
|
||||
free(fname);
|
||||
}
|
||||
|
||||
last_config_check = time(NULL);
|
||||
/* Parse some options that are allowed to be changed while tinc is running */
|
||||
|
||||
setup_myself_reloadable();
|
||||
|
||||
/* If StrictSubnet is set, expire deleted Subnets and read new ones in */
|
||||
|
||||
if(strictsubnets) {
|
||||
subnet_t *subnet;
|
||||
|
||||
|
||||
for(node = subnet_tree->head; node; node = node->next) {
|
||||
subnet = node->data;
|
||||
for splay_each(subnet_t, subnet, subnet_tree)
|
||||
subnet->expires = 1;
|
||||
}
|
||||
|
||||
load_all_subnets();
|
||||
|
||||
for(node = subnet_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
subnet = node->data;
|
||||
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||
if(subnet->expires == 1) {
|
||||
send_del_subnet(broadcast, subnet);
|
||||
send_del_subnet(everyone, subnet);
|
||||
if(subnet->owner->status.reachable)
|
||||
subnet_update(subnet->owner, subnet, false);
|
||||
subnet_del(subnet->owner, subnet);
|
||||
} else if(subnet->expires == -1) {
|
||||
subnet->expires = 0;
|
||||
} else {
|
||||
send_add_subnet(broadcast, subnet);
|
||||
send_add_subnet(everyone, subnet);
|
||||
if(subnet->owner->status.reachable)
|
||||
subnet_update(subnet->owner, subnet, true);
|
||||
}
|
||||
}
|
||||
} else { /* Only read our own subnets back in */
|
||||
for splay_each(subnet_t, subnet, myself->subnet_tree)
|
||||
if(!subnet->expires)
|
||||
subnet->expires = 1;
|
||||
|
||||
config_t *cfg = lookup_config(config_tree, "Subnet");
|
||||
|
||||
while(cfg) {
|
||||
subnet_t *subnet, *s2;
|
||||
|
||||
if(!get_config_subnet(cfg, &subnet))
|
||||
continue;
|
||||
|
||||
if((s2 = lookup_subnet(myself, subnet))) {
|
||||
if(s2->expires == 1)
|
||||
s2->expires = 0;
|
||||
|
||||
free_subnet(subnet);
|
||||
} else {
|
||||
subnet_add(myself, subnet);
|
||||
send_add_subnet(everyone, subnet);
|
||||
subnet_update(myself, subnet, true);
|
||||
}
|
||||
|
||||
cfg = lookup_config_next(config_tree, cfg);
|
||||
}
|
||||
|
||||
for splay_each(subnet_t, subnet, myself->subnet_tree) {
|
||||
if(subnet->expires == 1) {
|
||||
send_del_subnet(everyone, subnet);
|
||||
subnet_update(myself, subnet, false);
|
||||
subnet_del(myself, subnet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to make outgoing connections */
|
||||
|
||||
try_outgoing_connections();
|
||||
|
||||
/* Close connections to hosts that have a changed or deleted host config file */
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->status.control)
|
||||
continue;
|
||||
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
|
||||
struct stat s;
|
||||
if(stat(fname, &s) || s.st_mtime > last_config_check) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Host config file of %s has been changed", c->name);
|
||||
terminate_connection(c, c->status.active);
|
||||
}
|
||||
free(fname);
|
||||
}
|
||||
|
||||
last_config_check = time(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void retry(void) {
|
||||
connection_t *c;
|
||||
splay_node_t *node;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing && !c->node) {
|
||||
if(timeout_initialized(&c->outgoing->ev))
|
||||
event_del(&c->outgoing->ev);
|
||||
if(c->status.connecting)
|
||||
close(c->socket);
|
||||
c->outgoing->timeout = 0;
|
||||
do_outgoing_connection(c);
|
||||
terminate_connection(c, c->status.active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +368,7 @@ int main_loop(void) {
|
|||
#endif
|
||||
|
||||
if(event_loop(0) < 0) {
|
||||
logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
48
src/net.h
48
src/net.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,8 +31,11 @@
|
|||
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
|
||||
#endif
|
||||
|
||||
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
|
||||
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
|
||||
/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + padding + HMAC + compressor overhead */
|
||||
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
|
||||
|
||||
/* MAXBUFSIZE is the maximum size of a request: enough for a MAXSIZEd packet or a 8192 bits RSA key */
|
||||
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)
|
||||
|
||||
#define MAXSOCKETS 8 /* Probably overkill... */
|
||||
|
||||
|
@ -83,6 +86,18 @@ typedef struct vpn_packet_t {
|
|||
uint8_t data[MAXSIZE];
|
||||
} vpn_packet_t;
|
||||
|
||||
/* Packet types when using SPTPS */
|
||||
|
||||
#define PKT_COMPRESSED 1
|
||||
#define PKT_MAC 2
|
||||
#define PKT_PROBE 4
|
||||
|
||||
typedef enum packet_type_t {
|
||||
PACKET_NORMAL,
|
||||
PACKET_COMPRESSED,
|
||||
PACKET_PROBE
|
||||
} packet_type_t;
|
||||
|
||||
typedef struct listen_socket_t {
|
||||
struct event ev_tcp;
|
||||
struct event ev_udp;
|
||||
|
@ -97,6 +112,7 @@ typedef struct listen_socket_t {
|
|||
typedef struct outgoing_t {
|
||||
char *name;
|
||||
int timeout;
|
||||
splay_tree_t *config_tree;
|
||||
struct config_t *cfg;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *aip;
|
||||
|
@ -109,6 +125,7 @@ extern int maxoutbufsize;
|
|||
extern int seconds_till_retry;
|
||||
extern int addressfamily;
|
||||
extern unsigned replaywin;
|
||||
extern bool localdiscovery;
|
||||
|
||||
extern listen_socket_t listen_socket[MAXSOCKETS];
|
||||
extern int listen_sockets;
|
||||
|
@ -119,6 +136,24 @@ extern bool do_prune;
|
|||
extern char *myport;
|
||||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
extern time_t last_config_check;
|
||||
|
||||
extern char *proxyhost;
|
||||
extern char *proxyport;
|
||||
extern char *proxyuser;
|
||||
extern char *proxypass;
|
||||
typedef enum proxytype_t {
|
||||
PROXY_NONE = 0,
|
||||
PROXY_SOCKS4,
|
||||
PROXY_SOCKS4A,
|
||||
PROXY_SOCKS5,
|
||||
PROXY_HTTP,
|
||||
PROXY_EXEC,
|
||||
} proxytype_t;
|
||||
extern proxytype_t proxytype;
|
||||
|
||||
extern char *scriptinterpreter;
|
||||
extern char *scriptextension;
|
||||
|
||||
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
|
||||
#include "connection.h"
|
||||
|
@ -127,20 +162,23 @@ extern int contradicting_del_edge;
|
|||
extern void retry_outgoing(outgoing_t *);
|
||||
extern void handle_incoming_vpn_data(int, short, void *);
|
||||
extern void finish_connecting(struct connection_t *);
|
||||
extern bool do_outgoing_connection(struct connection_t *);
|
||||
extern bool do_outgoing_connection(struct outgoing_t *);
|
||||
extern void handle_new_meta_connection(int, short, void *);
|
||||
extern int setup_listen_socket(const sockaddr_t *);
|
||||
extern int setup_vpn_in_socket(const sockaddr_t *);
|
||||
extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
|
||||
extern bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len);
|
||||
extern void send_packet(struct node_t *, vpn_packet_t *);
|
||||
extern void receive_tcppacket(struct connection_t *, const char *, int);
|
||||
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern char *get_name(void);
|
||||
extern bool setup_myself_reloadable(void);
|
||||
extern bool setup_network(void);
|
||||
extern void setup_outgoing_connection(struct outgoing_t *);
|
||||
extern void try_outgoing_connections(void);
|
||||
extern void close_network_connections(void);
|
||||
extern int main_loop(void);
|
||||
extern void terminate_connection(struct connection_t *, bool);
|
||||
extern void flush_queue(struct node_t *);
|
||||
extern bool node_read_ecdsa_public_key(struct node_t *);
|
||||
extern bool read_ecdsa_public_key(struct connection_t *);
|
||||
extern bool read_rsa_public_key(struct connection_t *);
|
||||
|
|
408
src/net_packet.c
408
src/net_packet.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_packet.c -- Handles in- and outgoing VPN packets
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010 Timothy Redaelli <timothy@redaelli.eu>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
@ -36,7 +36,6 @@
|
|||
#include LZO1X_H
|
||||
#endif
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "cipher.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
|
@ -62,24 +61,30 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
|
|||
static void send_udppacket(node_t *, vpn_packet_t *);
|
||||
|
||||
unsigned replaywin = 16;
|
||||
bool localdiscovery = false;
|
||||
|
||||
#define MAX_SEQNO 1073741824
|
||||
|
||||
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
|
||||
// mtuprobes == 31: sleep pinginterval seconds
|
||||
// mtuprobes == 32: send 1 burst, sleep pingtimeout second
|
||||
// mtuprobes == 33: no response from other side, restart PMTU discovery process
|
||||
/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
|
||||
mtuprobes == 31: sleep pinginterval seconds
|
||||
mtuprobes == 32: send 1 burst, sleep pingtimeout second
|
||||
mtuprobes == 33: no response from other side, restart PMTU discovery process
|
||||
|
||||
Probes are sent in batches of three, with random sizes between the lower and
|
||||
upper boundaries for the MTU thus far discovered.
|
||||
|
||||
In case local discovery is enabled, a fourth packet is added to each batch,
|
||||
which will be broadcast to the local network.
|
||||
*/
|
||||
|
||||
static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||
node_t *n = data;
|
||||
vpn_packet_t packet;
|
||||
int len, i;
|
||||
int timeout = 1;
|
||||
|
||||
n->mtuprobes++;
|
||||
|
||||
if(!n->status.reachable || !n->status.validkey) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -91,14 +96,15 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
goto end;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
|
||||
n->status.udp_confirmed = false;
|
||||
n->mtuprobes = 1;
|
||||
n->minmtu = 0;
|
||||
n->maxmtu = MTU;
|
||||
}
|
||||
|
||||
if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 31;
|
||||
}
|
||||
|
||||
|
@ -108,7 +114,7 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
else
|
||||
n->maxmtu = n->minmtu;
|
||||
n->mtu = n->minmtu;
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
|
||||
n->mtuprobes = 31;
|
||||
}
|
||||
|
||||
|
@ -119,7 +125,9 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
timeout = pingtimeout;
|
||||
}
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
for(int i = 0; i < 3 + localdiscovery; i++) {
|
||||
int len;
|
||||
|
||||
if(n->maxmtu <= n->minmtu)
|
||||
len = n->maxmtu;
|
||||
else
|
||||
|
@ -128,12 +136,16 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
if(len < 64)
|
||||
len = 64;
|
||||
|
||||
vpn_packet_t packet;
|
||||
memset(packet.data, 0, 14);
|
||||
randomize(packet.data + 14, len - 14);
|
||||
packet.len = len;
|
||||
if(i >= 3 && n->mtuprobes <= 10)
|
||||
packet.priority = -1;
|
||||
else
|
||||
packet.priority = 0;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
|
||||
|
||||
send_udppacket(n, &packet);
|
||||
}
|
||||
|
@ -149,12 +161,14 @@ void send_mtu_probe(node_t *n) {
|
|||
}
|
||||
|
||||
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
|
||||
|
||||
if(!packet->data[0]) {
|
||||
packet->data[0] = 1;
|
||||
send_udppacket(n, packet);
|
||||
} else {
|
||||
n->status.udp_confirmed = true;
|
||||
|
||||
if(n->mtuprobes > 30) {
|
||||
if(n->minmtu)
|
||||
n->mtuprobes = 30;
|
||||
|
@ -231,7 +245,7 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
|
|||
/* VPN packet I/O */
|
||||
|
||||
static void receive_packet(node_t *n, vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
|
||||
packet->len, n->name, n->hostname);
|
||||
|
||||
n->in_packets++;
|
||||
|
@ -241,6 +255,9 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
|
||||
if(n->status.sptps)
|
||||
return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
|
||||
|
||||
if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
|
||||
return false;
|
||||
|
||||
|
@ -254,8 +271,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
vpn_packet_t *outpkt = pkt[0];
|
||||
size_t outlen;
|
||||
|
||||
if(n->status.sptps) {
|
||||
sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!cipher_active(&n->incipher)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -263,7 +285,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
/* Check packet length */
|
||||
|
||||
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -273,7 +295,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
if(digest_active(&n->indigest)) {
|
||||
inpkt->len -= n->indigest.maclength;
|
||||
if(!digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +306,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -301,16 +323,16 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
if(inpkt->seqno != n->received_seqno + 1) {
|
||||
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
|
||||
if(n->farfuture++ < replaywin >> 2) {
|
||||
logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
|
||||
return;
|
||||
}
|
||||
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
|
||||
memset(n->late, 0, replaywin);
|
||||
} else if (inpkt->seqno <= n->received_seqno) {
|
||||
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
|
||||
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
n->name, n->hostname, inpkt->seqno, n->received_seqno);
|
||||
return;
|
||||
}
|
||||
|
@ -338,7 +360,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -369,6 +391,53 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
|||
receive_packet(c->node, &outpkt);
|
||||
}
|
||||
|
||||
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
||||
if(!n->status.validkey) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
|
||||
if(!n->status.waitingforkey)
|
||||
send_req_key(n);
|
||||
else if(n->last_req_key + 10 < time(NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
|
||||
sptps_stop(&n->sptps);
|
||||
n->status.waitingforkey = false;
|
||||
send_req_key(n);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t type = 0;
|
||||
int offset = 0;
|
||||
|
||||
if(!(origpkt->data[12] | origpkt->data[13])) {
|
||||
sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
|
||||
return;
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
offset = 14;
|
||||
else
|
||||
type = PKT_MAC;
|
||||
|
||||
if(origpkt->len < offset)
|
||||
return;
|
||||
|
||||
vpn_packet_t outpkt;
|
||||
|
||||
if(n->outcompression) {
|
||||
int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
|
||||
if(len < 0) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
|
||||
} else if(len < origpkt->len - offset) {
|
||||
outpkt.len = len + offset;
|
||||
origpkt = &outpkt;
|
||||
type |= PKT_COMPRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
|
||||
return;
|
||||
}
|
||||
|
||||
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
||||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
|
@ -379,21 +448,23 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
size_t outlen;
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
static int priority = 0;
|
||||
int origpriority = origpkt->priority;
|
||||
#endif
|
||||
int sock;
|
||||
int origpriority = origpkt->priority;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->status.sptps)
|
||||
return send_sptps_packet(n, origpkt);
|
||||
|
||||
/* Make sure we have a valid key */
|
||||
|
||||
if(!n->status.validkey) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO,
|
||||
"No valid key known yet for %s (%s), forwarding via TCP",
|
||||
n->name, n->hostname);
|
||||
|
||||
|
@ -408,7 +479,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
}
|
||||
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO,
|
||||
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
|
||||
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
|
||||
|
||||
|
@ -426,7 +497,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -446,7 +517,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -461,41 +532,221 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
inpkt->len += digest_length(&n->outdigest);
|
||||
}
|
||||
|
||||
/* Send the packet */
|
||||
|
||||
sockaddr_t *sa;
|
||||
int sock;
|
||||
|
||||
/* Overloaded use of priority field: -1 means local broadcast */
|
||||
|
||||
if(origpriority == -1 && n->prevedge) {
|
||||
sockaddr_t broadcast;
|
||||
broadcast.in.sin_family = AF_INET;
|
||||
broadcast.in.sin_addr.s_addr = -1;
|
||||
broadcast.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
sa = &broadcast;
|
||||
sock = 0;
|
||||
} else {
|
||||
if(origpriority == -1)
|
||||
origpriority = 0;
|
||||
|
||||
if(n->status.udp_confirmed) {
|
||||
/* Address of this node is confirmed, so use it. */
|
||||
sa = &n->address;
|
||||
sock = n->sock;
|
||||
} else {
|
||||
/* Otherwise, go through the list of known addresses of
|
||||
this node. The first address we try is always the
|
||||
one in n->address; that could be set to the node's
|
||||
reflexive UDP address discovered during key
|
||||
exchange. The other known addresses are those found
|
||||
in edges to this node. */
|
||||
|
||||
static unsigned int i;
|
||||
int j = 0;
|
||||
edge_t *candidate = NULL;
|
||||
|
||||
if(i) {
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(e->to != n)
|
||||
continue;
|
||||
j++;
|
||||
if(!candidate || j == i)
|
||||
candidate = e;
|
||||
}
|
||||
}
|
||||
|
||||
if(!candidate) {
|
||||
sa = &n->address;
|
||||
sock = n->sock;
|
||||
} else {
|
||||
sa = &candidate->address;
|
||||
sock = rand() % listen_sockets;
|
||||
}
|
||||
|
||||
if(i++)
|
||||
if(i > j)
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine which socket we have to use */
|
||||
|
||||
if(sa->sa.sa_family != listen_socket[sock].sa.sa.sa_family)
|
||||
for(sock = 0; sock < listen_sockets; sock++)
|
||||
if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family)
|
||||
if(sa->sa.sa_family == listen_socket[sock].sa.sa.sa_family)
|
||||
break;
|
||||
|
||||
if(sock >= listen_sockets)
|
||||
sock = 0; /* If none is available, just use the first and hope for the best. */
|
||||
sock = 0;
|
||||
|
||||
/* Send the packet */
|
||||
if(!n->status.udp_confirmed)
|
||||
n->sock = sock;
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
if(priorityinheritance && origpriority != priority
|
||||
&& listen_socket[sock].sa.sa.sa_family == AF_INET) {
|
||||
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
|
||||
priority = origpriority;
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
|
||||
if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority)) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
|
||||
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
socklen_t sl = SALEN(n->address.sa);
|
||||
|
||||
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, sl) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen)
|
||||
n->maxmtu = origlen - 1;
|
||||
if(n->mtu >= origlen)
|
||||
n->mtu = origlen - 1;
|
||||
} else
|
||||
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
end:
|
||||
origpkt->len = origlen;
|
||||
}
|
||||
|
||||
bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
|
||||
node_t *to = handle;
|
||||
|
||||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, or this packet is larger than the MTU. */
|
||||
|
||||
if(type >= SPTPS_HANDSHAKE || ((myself->options | to->options) & OPTION_TCPONLY) || (type != PKT_PROBE && len > to->minmtu)) {
|
||||
char buf[len * 4 / 3 + 5];
|
||||
b64encode(data, buf, len);
|
||||
/* If no valid key is known yet, send the packets using ANS_KEY requests,
|
||||
to ensure we get to learn the reflexive UDP address. */
|
||||
if(!to->status.validkey)
|
||||
return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, myself->name, to->name, buf, myself->incompression);
|
||||
else
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_SPTPS, buf);
|
||||
}
|
||||
|
||||
/* Otherwise, send the packet via UDP */
|
||||
|
||||
struct sockaddr *sa;
|
||||
socklen_t sl;
|
||||
int sock;
|
||||
|
||||
sa = &(to->address.sa);
|
||||
sl = SALEN(to->address.sa);
|
||||
sock = to->sock;
|
||||
|
||||
if(sendto(listen_socket[sock].udp, data, len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(to->maxmtu >= len)
|
||||
to->maxmtu = len - 1;
|
||||
if(to->mtu >= len)
|
||||
to->mtu = len - 1;
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", to->name, to->hostname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len) {
|
||||
node_t *from = handle;
|
||||
|
||||
if(type == SPTPS_HANDSHAKE) {
|
||||
if(!from->status.validkey) {
|
||||
from->status.validkey = true;
|
||||
from->status.waitingforkey = false;
|
||||
logger(DEBUG_META, LOG_INFO, "SPTPS key exchange with %s (%s) succesful", from->name, from->hostname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(len > MTU) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Packet from %s (%s) larger than maximum supported size (%d > %d)", from->name, from->hostname, len, MTU);
|
||||
return false;
|
||||
}
|
||||
|
||||
vpn_packet_t inpkt;
|
||||
|
||||
if(type == PKT_PROBE) {
|
||||
inpkt.len = len;
|
||||
memcpy(inpkt.data, data, len);
|
||||
mtu_probe_h(from, &inpkt, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(type & ~(PKT_COMPRESSED | PKT_MAC)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unexpected SPTPS record type %d len %d from %s (%s)", type, len, from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if we have the headers we need */
|
||||
if(routing_mode != RMODE_ROUTER && !(type & PKT_MAC)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Received packet from %s (%s) without MAC header (maybe Mode is not set correctly)", from->name, from->hostname);
|
||||
return false;
|
||||
} else if(routing_mode == RMODE_ROUTER && (type & PKT_MAC)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Received packet from %s (%s) with MAC header (maybe Mode is not set correctly)", from->name, from->hostname);
|
||||
}
|
||||
|
||||
int offset = (type & PKT_MAC) ? 0 : 14;
|
||||
if(type & PKT_COMPRESSED) {
|
||||
len = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
|
||||
if(len < 0) {
|
||||
return false;
|
||||
} else {
|
||||
inpkt.len = len + offset;
|
||||
}
|
||||
if(inpkt.len > MAXSIZE)
|
||||
abort();
|
||||
} else {
|
||||
memcpy(inpkt.data + offset, data, len);
|
||||
inpkt.len = len + offset;
|
||||
}
|
||||
|
||||
/* Generate the Ethernet packet type if necessary */
|
||||
if(offset) {
|
||||
switch(inpkt.data[14] >> 4) {
|
||||
case 4:
|
||||
inpkt.data[12] = 0x08;
|
||||
inpkt.data[13] = 0x00;
|
||||
break;
|
||||
case 6:
|
||||
inpkt.data[12] = 0x86;
|
||||
inpkt.data[13] = 0xDD;
|
||||
break;
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s (%s)",
|
||||
inpkt.data[14] >> 4, from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
receive_packet(from, &inpkt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
send a packet to the given vpn ip.
|
||||
*/
|
||||
|
@ -507,15 +758,15 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
|
|||
memcpy(packet->data, mymac.x, ETH_ALEN);
|
||||
n->out_packets++;
|
||||
n->out_bytes += packet->len;
|
||||
write_packet(packet);
|
||||
devops.write(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Sending packet of %d bytes to %s (%s)",
|
||||
packet->len, n->name, n->hostname);
|
||||
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Node %s (%s) is not reachable",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -523,10 +774,15 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
|
|||
n->out_packets++;
|
||||
n->out_bytes += packet->len;
|
||||
|
||||
if(n->status.sptps) {
|
||||
send_sptps_packet(n, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
|
||||
|
||||
if(via != n)
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet to %s via %s (%s)",
|
||||
n->name, via->name, n->via->hostname);
|
||||
|
||||
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
|
||||
|
@ -539,46 +795,53 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
|
|||
/* Broadcast a packet using the minimum spanning tree */
|
||||
|
||||
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
||||
splay_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
|
||||
packet->len, from->name, from->hostname);
|
||||
|
||||
if(from != myself) {
|
||||
// Always give ourself a copy of the packet.
|
||||
if(from != myself)
|
||||
send_packet(myself, packet);
|
||||
|
||||
// In TunnelServer mode, do not forward broadcast packets.
|
||||
// The MST might not be valid and create loops.
|
||||
if(tunnelserver)
|
||||
if(tunnelserver || broadcast_mode == BMODE_NONE)
|
||||
return;
|
||||
}
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
|
||||
packet->len, from->name, from->hostname);
|
||||
|
||||
switch(broadcast_mode) {
|
||||
// In MST mode, broadcast packets travel via the Minimum Spanning Tree.
|
||||
// This guarantees all nodes receive the broadcast packet, and
|
||||
// usually distributes the sending of broadcast packets over all nodes.
|
||||
case BMODE_MST:
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
||||
send_packet(c->node, packet);
|
||||
break;
|
||||
|
||||
// In direct mode, we send copies to each node we know of.
|
||||
// However, this only reaches nodes that can be reached in a single hop.
|
||||
// We don't have enough information to forward broadcast packets in this case.
|
||||
case BMODE_DIRECT:
|
||||
if(from != myself)
|
||||
break;
|
||||
|
||||
for splay_each(node_t, n, node_tree)
|
||||
if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
|
||||
send_packet(n, packet);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
||||
splay_node_t *node;
|
||||
edge_t *e;
|
||||
node_t *n = NULL;
|
||||
bool hard = false;
|
||||
static time_t last_hard_try = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if(last_hard_try == now)
|
||||
return NULL;
|
||||
else
|
||||
last_hard_try = now;
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(e->to == myself)
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(!e->to->status.reachable || e->to == myself)
|
||||
continue;
|
||||
|
||||
if(sockaddrcmp_noport(from, &e->address)) {
|
||||
|
@ -597,13 +860,14 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
|||
if(hard)
|
||||
last_hard_try = now;
|
||||
|
||||
last_hard_try = now;
|
||||
return n;
|
||||
}
|
||||
|
||||
void handle_incoming_vpn_data(int sock, short events, void *data) {
|
||||
vpn_packet_t pkt;
|
||||
char *hostname;
|
||||
sockaddr_t from;
|
||||
sockaddr_t from = {{0}};
|
||||
socklen_t fromlen = sizeof from;
|
||||
node_t *n;
|
||||
int len;
|
||||
|
@ -612,7 +876,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
|
||||
if(len <= 0 || len > MAXSIZE) {
|
||||
if(!sockwouldblock(sockerrno))
|
||||
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -626,9 +890,9 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
n = try_harder(&from, &pkt);
|
||||
if(n)
|
||||
update_node_udp(n, &from);
|
||||
else ifdebug(PROTOCOL) {
|
||||
else if(debug_level >= DEBUG_PROTOCOL) {
|
||||
hostname = sockaddr2hostname(&from);
|
||||
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
|
||||
free(hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -636,6 +900,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
n->sock = (intptr_t)data;
|
||||
|
||||
receive_udppacket(n, &pkt);
|
||||
}
|
||||
|
||||
|
@ -644,7 +910,7 @@ void handle_device_data(int sock, short events, void *data) {
|
|||
|
||||
packet.priority = 0;
|
||||
|
||||
if(read_packet(&packet)) {
|
||||
if(devops.read(&packet)) {
|
||||
myself->in_packets++;
|
||||
myself->in_bytes += packet.len;
|
||||
route(myself, &packet);
|
||||
|
|
606
src/net_setup.c
606
src/net_setup.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_setup.c -- Setup.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "cipher.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
|
@ -44,6 +43,16 @@
|
|||
|
||||
char *myport;
|
||||
static struct event device_ev;
|
||||
devops_t devops;
|
||||
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
|
||||
char *scriptinterpreter;
|
||||
char *scriptextension;
|
||||
|
||||
bool node_read_ecdsa_public_key(node_t *n) {
|
||||
if(ecdsa_active(&n->ecdsa))
|
||||
|
@ -51,14 +60,14 @@ bool node_read_ecdsa_public_key(node_t *n) {
|
|||
|
||||
splay_tree_t *config_tree;
|
||||
FILE *fp;
|
||||
char *fname;
|
||||
char *pubname = NULL, *hcfname = NULL;
|
||||
char *p;
|
||||
bool result = false;
|
||||
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, n->name);
|
||||
xasprintf(&hcfname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
|
||||
|
||||
init_configuration(&config_tree);
|
||||
if(!read_config_file(config_tree, fname))
|
||||
if(!read_config_file(config_tree, hcfname))
|
||||
goto exit;
|
||||
|
||||
/* First, check for simple ECDSAPublicKey statement */
|
||||
|
@ -71,15 +80,13 @@ bool node_read_ecdsa_public_key(node_t *n) {
|
|||
|
||||
/* Else, check for ECDSAPublicKeyFile statement and read it */
|
||||
|
||||
free(fname);
|
||||
if(!get_config_string(lookup_config(config_tree, "ECDSAPublicKeyFile"), &pubname))
|
||||
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "ECDSAPublicKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, n->name);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
fp = fopen(pubname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Error reading ECDSA public key file `%s': %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s", pubname, strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -88,7 +95,8 @@ bool node_read_ecdsa_public_key(node_t *n) {
|
|||
|
||||
exit:
|
||||
exit_configuration(&config_tree);
|
||||
free(fname);
|
||||
free(hcfname);
|
||||
free(pubname);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -109,12 +117,12 @@ bool read_ecdsa_public_key(connection_t *c) {
|
|||
/* Else, check for ECDSAPublicKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(c->config_tree, "ECDSAPublicKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Error reading ECDSA public key file `%s': %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
|
@ -124,7 +132,7 @@ bool read_ecdsa_public_key(connection_t *c) {
|
|||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
logger(LOG_ERR, "Reading ECDSA public key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing ECDSA public key file `%s' failed.", fname);
|
||||
free(fname);
|
||||
return result;
|
||||
}
|
||||
|
@ -146,13 +154,12 @@ bool read_rsa_public_key(connection_t *c) {
|
|||
/* Else, check for PublicKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
@ -161,7 +168,7 @@ bool read_rsa_public_key(connection_t *c) {
|
|||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
|
||||
free(fname);
|
||||
return result;
|
||||
}
|
||||
|
@ -174,13 +181,12 @@ static bool read_ecdsa_private_key(void) {
|
|||
/* Check for PrivateKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "ECDSAPrivateKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s/ecdsa_key.priv", confbase);
|
||||
xasprintf(&fname, "%s" SLASH "ecdsa_key.priv", confbase);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Error reading ECDSA private key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
@ -189,20 +195,20 @@ static bool read_ecdsa_private_key(void) {
|
|||
struct stat s;
|
||||
|
||||
if(fstat(fileno(fp), &s)) {
|
||||
logger(LOG_ERR, "Could not stat ECDSA private key file `%s': %s'", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat ECDSA private key file `%s': %s'", fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(s.st_mode & ~0100700)
|
||||
logger(LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
|
||||
#endif
|
||||
|
||||
result = ecdsa_read_pem_private_key(&myself->connection->ecdsa, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
logger(LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
free(fname);
|
||||
return result;
|
||||
}
|
||||
|
@ -217,25 +223,25 @@ static bool read_rsa_private_key(void) {
|
|||
|
||||
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
|
||||
if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
|
||||
logger(LOG_ERR, "PrivateKey used but no PublicKey found!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
|
||||
free(d);
|
||||
return false;
|
||||
}
|
||||
result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
|
||||
free(n);
|
||||
free(d);
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Else, check for PrivateKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s/rsa_key.priv", confbase);
|
||||
xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Error reading RSA private key file `%s': %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
|
@ -245,20 +251,20 @@ static bool read_rsa_private_key(void) {
|
|||
struct stat s;
|
||||
|
||||
if(fstat(fileno(fp), &s)) {
|
||||
logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(s.st_mode & ~0100700)
|
||||
logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
|
||||
#endif
|
||||
|
||||
result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(!result)
|
||||
logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
free(fname);
|
||||
return result;
|
||||
}
|
||||
|
@ -271,7 +277,7 @@ static void keyexpire_handler(int fd, short events, void *data) {
|
|||
|
||||
void regenerate_key(void) {
|
||||
if(timeout_initialized(&keyexpire_event)) {
|
||||
ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
|
||||
event_del(&keyexpire_event);
|
||||
send_key_changed();
|
||||
} else {
|
||||
|
@ -288,17 +294,11 @@ void load_all_subnets(void) {
|
|||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char *dname;
|
||||
char *fname;
|
||||
splay_tree_t *config_tree;
|
||||
config_t *cfg;
|
||||
subnet_t *s, *s2;
|
||||
node_t *n;
|
||||
bool result;
|
||||
|
||||
xasprintf(&dname, "%s/hosts", confbase);
|
||||
xasprintf(&dname, "%s" SLASH "hosts", confbase);
|
||||
dir = opendir(dname);
|
||||
if(!dir) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
|
||||
free(dname);
|
||||
return;
|
||||
}
|
||||
|
@ -307,18 +307,20 @@ void load_all_subnets(void) {
|
|||
if(!check_id(ent->d_name))
|
||||
continue;
|
||||
|
||||
n = lookup_node(ent->d_name);
|
||||
node_t *n = lookup_node(ent->d_name);
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
//if(ent->d_type != DT_REG)
|
||||
// continue;
|
||||
#endif
|
||||
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
|
||||
char *fname;
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
||||
|
||||
splay_tree_t *config_tree;
|
||||
init_configuration(&config_tree);
|
||||
result = read_config_file(config_tree, fname);
|
||||
read_config_options(config_tree, ent->d_name);
|
||||
read_config_file(config_tree, fname);
|
||||
free(fname);
|
||||
if(!result)
|
||||
continue;
|
||||
|
||||
if(!n) {
|
||||
n = new_node();
|
||||
|
@ -326,7 +328,9 @@ void load_all_subnets(void) {
|
|||
node_add(n);
|
||||
}
|
||||
|
||||
for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s, *s2;
|
||||
|
||||
if(!get_config_subnet(cfg, &s))
|
||||
continue;
|
||||
|
||||
|
@ -343,84 +347,127 @@ void load_all_subnets(void) {
|
|||
closedir(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
Configure node_t myself and set up the local sockets (listen only)
|
||||
*/
|
||||
static bool setup_myself(void) {
|
||||
config_t *cfg;
|
||||
subnet_t *subnet;
|
||||
char *name, *hostname, *mode, *afname, *cipher, *digest;
|
||||
char *fname = NULL;
|
||||
char *address = NULL;
|
||||
char *envp[5];
|
||||
struct addrinfo *ai, *aip, hint = {0};
|
||||
bool choice;
|
||||
int i, err;
|
||||
int replaywin_int;
|
||||
char *get_name(void) {
|
||||
char *name = NULL;
|
||||
|
||||
myself = new_node();
|
||||
myself->connection = new_connection();
|
||||
get_config_string(lookup_config(config_tree, "Name"), &name);
|
||||
|
||||
myself->hostname = xstrdup("MYSELF");
|
||||
myself->connection->hostname = xstrdup("MYSELF");
|
||||
if(!name)
|
||||
return NULL;
|
||||
|
||||
myself->connection->options = 0;
|
||||
myself->connection->protocol_major = PROT_MAJOR;
|
||||
myself->connection->protocol_minor = PROT_MINOR;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */
|
||||
logger(LOG_ERR, "Name for tinc daemon required!");
|
||||
if(*name == '$') {
|
||||
char *envname = getenv(name + 1);
|
||||
if(!envname) {
|
||||
if(strcmp(name + 1, "HOST")) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
|
||||
return false;
|
||||
}
|
||||
envname = alloca(32);
|
||||
if(gethostname(envname, 32)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
envname[31] = 0;
|
||||
}
|
||||
free(name);
|
||||
name = xstrdup(envname);
|
||||
for(char *c = name; *c; c++)
|
||||
if(!isalnum(*c))
|
||||
*c = '_';
|
||||
}
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(LOG_ERR, "Invalid name for myself!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
myself->name = name;
|
||||
myself->connection->name = xstrdup(name);
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, name);
|
||||
read_config_options(config_tree, name);
|
||||
read_config_file(config_tree, fname);
|
||||
free(fname);
|
||||
return name;
|
||||
}
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
|
||||
bool setup_myself_reloadable(void) {
|
||||
char *proxy = NULL;
|
||||
char *rmode = NULL;
|
||||
char *fmode = NULL;
|
||||
char *bmode = NULL;
|
||||
char *afname = NULL;
|
||||
char *space;
|
||||
bool choice;
|
||||
|
||||
if(experimental && !read_ecdsa_private_key())
|
||||
free(scriptinterpreter);
|
||||
scriptinterpreter = NULL;
|
||||
get_config_string(lookup_config(config_tree, "ScriptsInterpreter"), &scriptinterpreter);
|
||||
|
||||
|
||||
free(scriptextension);
|
||||
if(!get_config_string(lookup_config(config_tree, "ScriptsExtension"), &scriptextension))
|
||||
#ifdef HAVE_MINGW
|
||||
scriptextension = xstrdup(".bat");
|
||||
#else
|
||||
scriptextension = xstrdup("");
|
||||
#endif
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Proxy"), &proxy);
|
||||
if(proxy) {
|
||||
if((space = strchr(proxy, ' ')))
|
||||
*space++ = 0;
|
||||
|
||||
if(!strcasecmp(proxy, "none")) {
|
||||
proxytype = PROXY_NONE;
|
||||
} else if(!strcasecmp(proxy, "socks4")) {
|
||||
proxytype = PROXY_SOCKS4;
|
||||
} else if(!strcasecmp(proxy, "socks4a")) {
|
||||
proxytype = PROXY_SOCKS4A;
|
||||
} else if(!strcasecmp(proxy, "socks5")) {
|
||||
proxytype = PROXY_SOCKS5;
|
||||
} else if(!strcasecmp(proxy, "http")) {
|
||||
proxytype = PROXY_HTTP;
|
||||
} else if(!strcasecmp(proxy, "exec")) {
|
||||
proxytype = PROXY_EXEC;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type %s!", proxy);
|
||||
return false;
|
||||
|
||||
if(!read_rsa_private_key())
|
||||
return false;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
|
||||
myport = xstrdup("655");
|
||||
|
||||
if(!atoi(myport)) {
|
||||
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
|
||||
sockaddr_t sa;
|
||||
if(!ai || !ai->ai_addr)
|
||||
return false;
|
||||
free(myport);
|
||||
memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
|
||||
sockaddr2str(&sa, NULL, &myport);
|
||||
}
|
||||
|
||||
/* Read in all the subnets specified in the host configuration file */
|
||||
switch(proxytype) {
|
||||
case PROXY_NONE:
|
||||
default:
|
||||
break;
|
||||
|
||||
cfg = lookup_config(config_tree, "Subnet");
|
||||
|
||||
while(cfg) {
|
||||
if(!get_config_subnet(cfg, &subnet))
|
||||
case PROXY_EXEC:
|
||||
if(!space || !*space) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Argument expected for proxy type exec!");
|
||||
return false;
|
||||
}
|
||||
proxyhost = xstrdup(space);
|
||||
break;
|
||||
|
||||
subnet_add(myself, subnet);
|
||||
|
||||
cfg = lookup_config_next(config_tree, cfg);
|
||||
case PROXY_SOCKS4:
|
||||
case PROXY_SOCKS4A:
|
||||
case PROXY_SOCKS5:
|
||||
case PROXY_HTTP:
|
||||
proxyhost = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxyport = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxyuser = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxypass = space;
|
||||
if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Host and port argument expected for proxy!");
|
||||
return false;
|
||||
}
|
||||
proxyhost = xstrdup(proxyhost);
|
||||
proxyport = xstrdup(proxyport);
|
||||
if(proxyuser && *proxyuser)
|
||||
proxyuser = xstrdup(proxyuser);
|
||||
if(proxypass && *proxypass)
|
||||
proxypass = xstrdup(proxypass);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check some options */
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
|
||||
myself->options |= OPTION_INDIRECT;
|
||||
|
@ -432,36 +479,34 @@ static bool setup_myself(void) {
|
|||
myself->options |= OPTION_INDIRECT;
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
|
||||
get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
|
||||
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
|
||||
strictsubnets |= tunnelserver;
|
||||
get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
|
||||
if(!strcasecmp(mode, "router"))
|
||||
if(get_config_string(lookup_config(config_tree, "Mode"), &rmode)) {
|
||||
if(!strcasecmp(rmode, "router"))
|
||||
routing_mode = RMODE_ROUTER;
|
||||
else if(!strcasecmp(mode, "switch"))
|
||||
else if(!strcasecmp(rmode, "switch"))
|
||||
routing_mode = RMODE_SWITCH;
|
||||
else if(!strcasecmp(mode, "hub"))
|
||||
else if(!strcasecmp(rmode, "hub"))
|
||||
routing_mode = RMODE_HUB;
|
||||
else {
|
||||
logger(LOG_ERR, "Invalid routing mode!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid routing mode!");
|
||||
return false;
|
||||
}
|
||||
free(mode);
|
||||
free(rmode);
|
||||
}
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
|
||||
if(!strcasecmp(mode, "off"))
|
||||
if(get_config_string(lookup_config(config_tree, "Forwarding"), &fmode)) {
|
||||
if(!strcasecmp(fmode, "off"))
|
||||
forwarding_mode = FMODE_OFF;
|
||||
else if(!strcasecmp(mode, "internal"))
|
||||
else if(!strcasecmp(fmode, "internal"))
|
||||
forwarding_mode = FMODE_INTERNAL;
|
||||
else if(!strcasecmp(mode, "kernel"))
|
||||
else if(!strcasecmp(fmode, "kernel"))
|
||||
forwarding_mode = FMODE_KERNEL;
|
||||
else {
|
||||
logger(LOG_ERR, "Invalid forwarding mode!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid forwarding mode!");
|
||||
return false;
|
||||
}
|
||||
free(mode);
|
||||
free(fmode);
|
||||
}
|
||||
|
||||
choice = true;
|
||||
|
@ -475,10 +520,24 @@ static bool setup_myself(void) {
|
|||
myself->options |= OPTION_CLAMP_MSS;
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
|
||||
get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
|
||||
if(get_config_string(lookup_config(config_tree, "Broadcast"), &bmode)) {
|
||||
if(!strcasecmp(bmode, "no"))
|
||||
broadcast_mode = BMODE_NONE;
|
||||
else if(!strcasecmp(bmode, "yes") || !strcasecmp(bmode, "mst"))
|
||||
broadcast_mode = BMODE_MST;
|
||||
else if(!strcasecmp(bmode, "direct"))
|
||||
broadcast_mode = BMODE_DIRECT;
|
||||
else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid broadcast mode!");
|
||||
return false;
|
||||
}
|
||||
free(bmode);
|
||||
}
|
||||
|
||||
#if !defined(SOL_IP) || !defined(IP_TOS)
|
||||
if(priorityinheritance)
|
||||
logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
|
||||
#endif
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
|
||||
|
@ -486,34 +545,12 @@ static bool setup_myself(void) {
|
|||
|
||||
if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
|
||||
if(maxtimeout <= 0) {
|
||||
logger(LOG_ERR, "Bogus maximum timeout!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus maximum timeout!");
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
maxtimeout = 900;
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
|
||||
if(udp_rcvbuf <= 0) {
|
||||
logger(LOG_ERR, "UDPRcvBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
|
||||
if(udp_sndbuf <= 0) {
|
||||
logger(LOG_ERR, "UDPSndBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
|
||||
if(replaywin_int < 0) {
|
||||
logger(LOG_ERR, "ReplayWindow cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
replaywin = (unsigned)replaywin_int;
|
||||
}
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
|
||||
if(!strcasecmp(afname, "IPv4"))
|
||||
addressfamily = AF_INET;
|
||||
|
@ -522,7 +559,7 @@ static bool setup_myself(void) {
|
|||
else if(!strcasecmp(afname, "any"))
|
||||
addressfamily = AF_UNSPEC;
|
||||
else {
|
||||
logger(LOG_ERR, "Invalid address family!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid address family!");
|
||||
return false;
|
||||
}
|
||||
free(afname);
|
||||
|
@ -530,44 +567,149 @@ static bool setup_myself(void) {
|
|||
|
||||
get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
|
||||
keylifetime = 3600;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Configure node_t myself and set up the local sockets (listen only)
|
||||
*/
|
||||
static bool setup_myself(void) {
|
||||
char *name, *hostname, *cipher, *digest, *type;
|
||||
char *fname = NULL;
|
||||
char *address = NULL;
|
||||
|
||||
if(!(name = get_name())) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
|
||||
return false;
|
||||
}
|
||||
|
||||
myself = new_node();
|
||||
myself->connection = new_connection();
|
||||
myself->name = name;
|
||||
myself->connection->name = xstrdup(name);
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
read_config_options(config_tree, name);
|
||||
read_config_file(config_tree, fname);
|
||||
free(fname);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
|
||||
myport = xstrdup("655");
|
||||
|
||||
xasprintf(&myself->hostname, "MYSELF port %s", myport);
|
||||
myself->connection->hostname = xstrdup(myself->hostname);
|
||||
|
||||
myself->connection->options = 0;
|
||||
myself->connection->protocol_major = PROT_MAJOR;
|
||||
myself->connection->protocol_minor = PROT_MINOR;
|
||||
|
||||
myself->options |= PROT_MINOR << 24;
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
|
||||
|
||||
if(experimental && !read_ecdsa_private_key())
|
||||
return false;
|
||||
|
||||
if(!read_rsa_private_key())
|
||||
return false;
|
||||
|
||||
if(!atoi(myport)) {
|
||||
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
|
||||
sockaddr_t sa;
|
||||
if(!ai || !ai->ai_addr)
|
||||
return false;
|
||||
free(myport);
|
||||
memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
|
||||
sockaddr2str(&sa, NULL, &myport);
|
||||
}
|
||||
|
||||
/* Read in all the subnets specified in the host configuration file */
|
||||
|
||||
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *subnet;
|
||||
|
||||
if(!get_config_subnet(cfg, &subnet))
|
||||
return false;
|
||||
|
||||
subnet_add(myself, subnet);
|
||||
}
|
||||
|
||||
/* Check some options */
|
||||
|
||||
if(!setup_myself_reloadable())
|
||||
return false;
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
|
||||
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
|
||||
strictsubnets |= tunnelserver;
|
||||
|
||||
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
|
||||
if(udp_rcvbuf <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UDPRcvBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
|
||||
if(udp_sndbuf <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UDPSndBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int replaywin_int;
|
||||
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
|
||||
if(replaywin_int < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "ReplayWindow cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
replaywin = (unsigned)replaywin_int;
|
||||
sptps_replaywin = replaywin;
|
||||
}
|
||||
|
||||
/* Generate packet encryption key */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
|
||||
cipher = xstrdup("blowfish");
|
||||
|
||||
if(!cipher_open_by_name(&myself->incipher, cipher)) {
|
||||
logger(LOG_ERR, "Unrecognized cipher type!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
|
||||
keylifetime = 3600;
|
||||
free(cipher);
|
||||
|
||||
regenerate_key();
|
||||
|
||||
/* Check if we want to use message authentication codes... */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
|
||||
digest = xstrdup("sha1");
|
||||
|
||||
int maclength = 4;
|
||||
get_config_int(lookup_config(config_tree, "MACLength"), &maclength);
|
||||
|
||||
if(maclength < 0) {
|
||||
logger(LOG_ERR, "Bogus MAC length!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus MAC length!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
|
||||
digest = xstrdup("sha1");
|
||||
|
||||
if(!digest_open_by_name(&myself->indigest, digest, maclength)) {
|
||||
logger(LOG_ERR, "Unrecognized digest type!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
free(digest);
|
||||
|
||||
/* Compression */
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) {
|
||||
if(myself->incompression < 0 || myself->incompression > 11) {
|
||||
logger(LOG_ERR, "Bogus compression level!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus compression level!");
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
|
@ -580,6 +722,8 @@ static bool setup_myself(void) {
|
|||
myself->nexthop = myself;
|
||||
myself->via = myself;
|
||||
myself->status.reachable = true;
|
||||
myself->last_state_change = time(NULL);
|
||||
myself->status.sptps = experimental;
|
||||
node_add(myself);
|
||||
|
||||
graph();
|
||||
|
@ -589,20 +733,40 @@ static bool setup_myself(void) {
|
|||
|
||||
/* Open device */
|
||||
|
||||
if(!setup_device())
|
||||
devops = os_devops;
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "dummy"))
|
||||
devops = dummy_devops;
|
||||
else if(!strcasecmp(type, "raw_socket"))
|
||||
devops = raw_socket_devops;
|
||||
else if(!strcasecmp(type, "multicast"))
|
||||
devops = multicast_devops;
|
||||
#ifdef ENABLE_UML
|
||||
else if(!strcasecmp(type, "uml"))
|
||||
devops = uml_devops;
|
||||
#endif
|
||||
#ifdef ENABLE_VDE
|
||||
else if(!strcasecmp(type, "vde"))
|
||||
devops = vde_devops;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(!devops.setup())
|
||||
return false;
|
||||
|
||||
if(device_fd >= 0) {
|
||||
event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
|
||||
|
||||
if (event_add(&device_ev, NULL) < 0) {
|
||||
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
close_device();
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
devops.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run tinc-up script to further initialize the tap interface */
|
||||
char *envp[5];
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
|
@ -611,7 +775,7 @@ static bool setup_myself(void) {
|
|||
|
||||
execute_script("tinc-up", envp);
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
|
||||
/* Run subnet-up scripts for our own subnets */
|
||||
|
@ -620,24 +784,100 @@ static bool setup_myself(void) {
|
|||
|
||||
/* Open sockets */
|
||||
|
||||
get_config_string(lookup_config(config_tree, "BindToAddress"), &address);
|
||||
if(!do_detach && getenv("LISTEN_FDS")) {
|
||||
sockaddr_t sa;
|
||||
socklen_t salen;
|
||||
|
||||
listen_sockets = atoi(getenv("LISTEN_FDS"));
|
||||
#ifdef HAVE_UNSETENV
|
||||
unsetenv("LISTEN_FDS");
|
||||
#endif
|
||||
|
||||
if(listen_sockets > MAXSOCKETS) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
salen = sizeof sa;
|
||||
if(getsockname(i + 3, &sa.sa, &salen) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
listen_socket[i].tcp = i + 3;
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(i + 3, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
listen_socket[i].udp = setup_vpn_in_socket(&sa);
|
||||
if(listen_socket[i].udp < 0)
|
||||
return false;
|
||||
|
||||
event_set(&listen_socket[i].ev_tcp, listen_socket[i].tcp, EV_READ|EV_PERSIST, handle_new_meta_connection, NULL);
|
||||
if(event_add(&listen_socket[i].ev_tcp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
event_set(&listen_socket[i].ev_udp, listen_socket[i].udp, EV_READ|EV_PERSIST, handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
hostname = sockaddr2hostname(&sa);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
|
||||
free(hostname);
|
||||
}
|
||||
|
||||
memcpy(&listen_socket[i].sa, &sa, salen);
|
||||
}
|
||||
} else {
|
||||
listen_sockets = 0;
|
||||
config_t *cfg = lookup_config(config_tree, "BindToAddress");
|
||||
|
||||
do {
|
||||
get_config_string(cfg, &address);
|
||||
if(cfg)
|
||||
cfg = lookup_config_next(config_tree, cfg);
|
||||
|
||||
char *port = myport;
|
||||
|
||||
if(address) {
|
||||
char *space = strchr(address, ' ');
|
||||
if(space) {
|
||||
*space++ = 0;
|
||||
port = space;
|
||||
}
|
||||
|
||||
if(!strcmp(address, "*"))
|
||||
*address = 0;
|
||||
}
|
||||
|
||||
struct addrinfo *ai, hint = {0};
|
||||
hint.ai_family = addressfamily;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
hint.ai_flags = AI_PASSIVE;
|
||||
|
||||
err = getaddrinfo(address, myport, &hint, &ai);
|
||||
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
||||
free(address);
|
||||
|
||||
if(err || !ai) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
|
||||
gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
listen_sockets = 0;
|
||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||
if(listen_sockets >= MAXSOCKETS) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(aip = ai; aip; aip = aip->ai_next) {
|
||||
listen_socket[listen_sockets].tcp =
|
||||
setup_listen_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
|
@ -657,43 +897,42 @@ static bool setup_myself(void) {
|
|||
EV_READ|EV_PERSIST,
|
||||
handle_new_meta_connection, NULL);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
|
||||
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
event_set(&listen_socket[listen_sockets].ev_udp,
|
||||
listen_socket[listen_sockets].udp,
|
||||
EV_READ|EV_PERSIST,
|
||||
handle_incoming_vpn_data, NULL);
|
||||
handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
|
||||
logger(LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
ifdebug(CONNECTIONS) {
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
|
||||
logger(LOG_NOTICE, "Listening on %s", hostname);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
|
||||
free(hostname);
|
||||
}
|
||||
|
||||
memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
|
||||
listen_sockets++;
|
||||
|
||||
if(listen_sockets >= MAXSOCKETS) {
|
||||
logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
} while(cfg);
|
||||
}
|
||||
|
||||
if(listen_sockets)
|
||||
logger(LOG_NOTICE, "Ready");
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
|
||||
else {
|
||||
logger(LOG_ERR, "Unable to create any listening socket!");
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to create any listening socket!");
|
||||
return false;
|
||||
}
|
||||
|
||||
last_config_check = time(NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -732,14 +971,12 @@ bool setup_network(void) {
|
|||
close all open network connections
|
||||
*/
|
||||
void close_network_connections(void) {
|
||||
splay_node_t *node, *next;
|
||||
connection_t *c;
|
||||
char *envp[5];
|
||||
int i;
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
||||
next = node->next;
|
||||
c = node->data;
|
||||
connection_t *c = node->data;
|
||||
/* Keep control connections open until the end, so they know when we really terminated */
|
||||
if(c->status.control)
|
||||
c->socket = -1;
|
||||
c->outgoing = NULL;
|
||||
terminate_connection(c, false);
|
||||
}
|
||||
|
@ -752,13 +989,14 @@ void close_network_connections(void) {
|
|||
free_connection(myself->connection);
|
||||
}
|
||||
|
||||
for(i = 0; i < listen_sockets; i++) {
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
event_del(&listen_socket[i].ev_tcp);
|
||||
event_del(&listen_socket[i].ev_udp);
|
||||
close(listen_socket[i].tcp);
|
||||
close(listen_socket[i].udp);
|
||||
}
|
||||
|
||||
char *envp[5];
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
|
@ -775,10 +1013,10 @@ void close_network_connections(void) {
|
|||
|
||||
if(myport) free(myport);
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
|
||||
close_device();
|
||||
devops.close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
454
src/net_socket.c
454
src/net_socket.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_socket.c -- Handle various kinds of sockets.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2009 Florian Forster <octo@verplant.org>
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
|
@ -33,8 +33,6 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Needed on Mac OS/X */
|
||||
#ifndef SOL_TCP
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
|
@ -59,13 +57,13 @@ static void configure_tcp(connection_t *c) {
|
|||
int flags = fcntl(c->socket, F_GETFL);
|
||||
|
||||
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
unsigned long arg = 1;
|
||||
|
||||
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
|
||||
logger(LOG_ERR, "ioctlsocket for %s: %d", c->hostname, sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -98,74 +96,17 @@ static bool bind_to_interface(int sd) {
|
|||
|
||||
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
|
||||
if(status) {
|
||||
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
|
||||
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bind_to_address(connection_t *c) {
|
||||
char *node;
|
||||
struct addrinfo *ai_list;
|
||||
struct addrinfo *ai_ptr;
|
||||
struct addrinfo ai_hints;
|
||||
int status;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->socket >= 0);
|
||||
|
||||
node = NULL;
|
||||
if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
|
||||
&node))
|
||||
return true;
|
||||
|
||||
assert(node != NULL);
|
||||
|
||||
memset(&ai_hints, 0, sizeof(ai_hints));
|
||||
ai_hints.ai_family = c->address.sa.sa_family;
|
||||
/* We're called from `do_outgoing_connection' only. */
|
||||
ai_hints.ai_socktype = SOCK_STREAM;
|
||||
ai_hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
ai_list = NULL;
|
||||
|
||||
status = getaddrinfo(node, /* service = */ NULL,
|
||||
&ai_hints, &ai_list);
|
||||
if(status) {
|
||||
logger(LOG_WARNING, "Error looking up %s port %s: %s",
|
||||
node, "any", gai_strerror(status));
|
||||
free(node);
|
||||
return false;
|
||||
}
|
||||
assert(ai_list != NULL);
|
||||
|
||||
status = -1;
|
||||
for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
|
||||
status = bind(c->socket,
|
||||
ai_list->ai_addr, ai_list->ai_addrlen);
|
||||
if(!status)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(status) {
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno));
|
||||
} else ifdebug(CONNECTIONS) {
|
||||
logger(LOG_DEBUG, "Successfully bound outgoing "
|
||||
"TCP socket to %s", node);
|
||||
}
|
||||
|
||||
free(node);
|
||||
freeaddrinfo(ai_list);
|
||||
|
||||
return status ? false : true;
|
||||
}
|
||||
|
||||
int setup_listen_socket(const sockaddr_t *sa) {
|
||||
int nfd;
|
||||
char *addrstr;
|
||||
|
@ -175,10 +116,14 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(nfd < 0) {
|
||||
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
|
||||
logger(DEBUG_STATUS, LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(nfd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
option = 1;
|
||||
|
@ -199,26 +144,26 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
|
||||
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
strerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(nfd, 3)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -233,17 +178,21 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(nfd < 0) {
|
||||
logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(nfd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
#ifdef O_NONBLOCK
|
||||
{
|
||||
int flags = fcntl(nfd, F_GETFL);
|
||||
|
||||
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "fcntl",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -253,7 +202,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
unsigned long arg = 1;
|
||||
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -261,12 +210,13 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
|
||||
option = 1;
|
||||
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
|
||||
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof option);
|
||||
|
||||
if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf)))
|
||||
logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
|
||||
|
||||
if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf)))
|
||||
logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if(sa->sa.sa_family == AF_INET6)
|
||||
|
@ -313,7 +263,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
@ -334,14 +284,15 @@ void retry_outgoing(outgoing_t *outgoing) {
|
|||
timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
|
||||
event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0});
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE,
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE,
|
||||
"Trying to re-establish outgoing connection in %d seconds",
|
||||
outgoing->timeout);
|
||||
}
|
||||
|
||||
void finish_connecting(connection_t *c) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
||||
|
||||
if(proxytype != PROXY_EXEC)
|
||||
configure_tcp(c);
|
||||
|
||||
c->last_ping_time = time(NULL);
|
||||
|
@ -350,113 +301,68 @@ void finish_connecting(connection_t *c) {
|
|||
send_id(c);
|
||||
}
|
||||
|
||||
bool do_outgoing_connection(connection_t *c) {
|
||||
char *address, *port, *space;
|
||||
int result;
|
||||
static void do_outgoing_pipe(connection_t *c, char *command) {
|
||||
#ifndef HAVE_MINGW
|
||||
int fd[2];
|
||||
|
||||
if(!c->outgoing) {
|
||||
logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name);
|
||||
abort();
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
begin:
|
||||
if(!c->outgoing->ai) {
|
||||
if(!c->outgoing->cfg) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
|
||||
c->name);
|
||||
retry_outgoing(c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
connection_del(c);
|
||||
return false;
|
||||
if(fork()) {
|
||||
c->socket = fd[0];
|
||||
close(fd[1]);
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Using proxy %s", command);
|
||||
return;
|
||||
}
|
||||
|
||||
get_config_string(c->outgoing->cfg, &address);
|
||||
close(0);
|
||||
close(1);
|
||||
close(fd[0]);
|
||||
dup2(fd[1], 0);
|
||||
dup2(fd[1], 1);
|
||||
close(fd[1]);
|
||||
|
||||
space = strchr(address, ' ');
|
||||
if(space) {
|
||||
port = xstrdup(space + 1);
|
||||
*space = 0;
|
||||
} else {
|
||||
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
|
||||
port = xstrdup("655");
|
||||
}
|
||||
// Other filedescriptors should be closed automatically by CLOEXEC
|
||||
|
||||
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
|
||||
free(address);
|
||||
free(port);
|
||||
char *host = NULL;
|
||||
char *port = NULL;
|
||||
|
||||
c->outgoing->aip = c->outgoing->ai;
|
||||
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
|
||||
}
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
setenv("REMOTEADDRESS", host, true);
|
||||
setenv("REMOTEPORT", port, true);
|
||||
setenv("NODE", c->name, true);
|
||||
setenv("NAME", myself->name, true);
|
||||
if(netname)
|
||||
setenv("NETNAME", netname, true);
|
||||
|
||||
if(!c->outgoing->aip) {
|
||||
if(c->outgoing->ai)
|
||||
freeaddrinfo(c->outgoing->ai);
|
||||
c->outgoing->ai = NULL;
|
||||
goto begin;
|
||||
}
|
||||
|
||||
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
|
||||
c->outgoing->aip = c->outgoing->aip->ai_next;
|
||||
|
||||
if(c->hostname)
|
||||
free(c->hostname);
|
||||
|
||||
c->hostname = sockaddr2hostname(&c->address);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
|
||||
c->hostname);
|
||||
|
||||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(c->socket == -1) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
goto begin;
|
||||
}
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
int result = system(command);
|
||||
if(result < 0)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not execute %s: %s", command, strerror(errno));
|
||||
else if(result)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s exited with non-zero status %d", command, result);
|
||||
exit(result);
|
||||
#else
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type exec not supported on this platform!");
|
||||
return;
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
bind_to_address(c);
|
||||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
configure_tcp(c);
|
||||
|
||||
/* Connect */
|
||||
|
||||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
|
||||
if(result == -1) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
c->status.connecting = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
closesocket(c->socket);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno));
|
||||
|
||||
goto begin;
|
||||
}
|
||||
|
||||
finish_connecting(c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handle_meta_write(int sock, short events, void *data) {
|
||||
ifdebug(META) logger(LOG_DEBUG, "handle_meta_write() called");
|
||||
|
||||
connection_t *c = data;
|
||||
|
||||
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
|
||||
if(outlen <= 0) {
|
||||
logger(LOG_ERR, "Onoes, outlen = %d (%s)", (int)outlen, strerror(errno));
|
||||
if(!errno || errno == EPIPE) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)", c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Sending %d bytes to %s (%s) would block", c->outbuf.len - c->outbuf.offset, c->name, c->hostname);
|
||||
return;
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, strerror(errno));
|
||||
}
|
||||
|
||||
terminate_connection(c, c->status.active);
|
||||
return;
|
||||
}
|
||||
|
@ -466,51 +372,151 @@ static void handle_meta_write(int sock, short events, void *data) {
|
|||
event_del(&c->outevent);
|
||||
}
|
||||
|
||||
void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||
connection_t *c;
|
||||
node_t *n;
|
||||
|
||||
if(event_initialized(&outgoing->ev))
|
||||
event_del(&outgoing->ev);
|
||||
bool do_outgoing_connection(outgoing_t *outgoing) {
|
||||
char *address, *port, *space;
|
||||
struct addrinfo *proxyai = NULL;
|
||||
int result;
|
||||
|
||||
n = lookup_node(outgoing->name);
|
||||
|
||||
if(n)
|
||||
if(n->connection) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);
|
||||
|
||||
n->connection->outgoing = outgoing;
|
||||
return;
|
||||
begin:
|
||||
if(!outgoing->ai) {
|
||||
if(!outgoing->cfg) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
|
||||
retry_outgoing(outgoing);
|
||||
return false;
|
||||
}
|
||||
|
||||
c = new_connection();
|
||||
get_config_string(outgoing->cfg, &address);
|
||||
|
||||
space = strchr(address, ' ');
|
||||
if(space) {
|
||||
port = xstrdup(space + 1);
|
||||
*space = 0;
|
||||
} else {
|
||||
if(!get_config_string(lookup_config(outgoing->config_tree, "Port"), &port))
|
||||
port = xstrdup("655");
|
||||
}
|
||||
|
||||
outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
|
||||
free(address);
|
||||
free(port);
|
||||
|
||||
outgoing->aip = outgoing->ai;
|
||||
outgoing->cfg = lookup_config_next(outgoing->config_tree, outgoing->cfg);
|
||||
}
|
||||
|
||||
if(!outgoing->aip) {
|
||||
if(outgoing->ai)
|
||||
freeaddrinfo(outgoing->ai);
|
||||
outgoing->ai = NULL;
|
||||
goto begin;
|
||||
}
|
||||
|
||||
connection_t *c = new_connection();
|
||||
c->outgoing = outgoing;
|
||||
|
||||
memcpy(&c->address, outgoing->aip->ai_addr, outgoing->aip->ai_addrlen);
|
||||
outgoing->aip = outgoing->aip->ai_next;
|
||||
|
||||
c->hostname = sockaddr2hostname(&c->address);
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Trying to connect to %s (%s)", outgoing->name, c->hostname);
|
||||
|
||||
if(!proxytype) {
|
||||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
configure_tcp(c);
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
do_outgoing_pipe(c, proxyhost);
|
||||
} else {
|
||||
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
|
||||
if(!proxyai) {
|
||||
free_connection(c);
|
||||
goto begin;
|
||||
}
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
|
||||
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
if(c->socket == -1) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
free_connection(c);
|
||||
goto begin;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
if(proxytype != PROXY_EXEC) {
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
|
||||
if(!proxytype) {
|
||||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
|
||||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
||||
if(result == -1 && !sockinprogress(sockerrno)) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not connect to %s (%s): %s", outgoing->name, c->hostname, sockstrerror(sockerrno));
|
||||
free_connection(c);
|
||||
|
||||
goto begin;
|
||||
}
|
||||
|
||||
/* Now that there is a working socket, fill in the rest and register this connection. */
|
||||
|
||||
c->status.connecting = true;
|
||||
c->name = xstrdup(outgoing->name);
|
||||
c->outcipher = myself->connection->outcipher;
|
||||
c->outdigest = myself->connection->outdigest;
|
||||
c->outmaclength = myself->connection->outmaclength;
|
||||
c->outcompression = myself->connection->outcompression;
|
||||
|
||||
init_configuration(&c->config_tree);
|
||||
read_connection_config(c);
|
||||
|
||||
outgoing->cfg = lookup_config(c->config_tree, "Address");
|
||||
|
||||
if(!outgoing->cfg) {
|
||||
logger(LOG_ERR, "No address specified for %s", c->name);
|
||||
free_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->outgoing = outgoing;
|
||||
c->last_ping_time = time(NULL);
|
||||
|
||||
connection_add(c);
|
||||
|
||||
if (do_outgoing_connection(c)) {
|
||||
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
|
||||
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
|
||||
event_add(&c->inevent, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||
if(event_initialized(&outgoing->ev))
|
||||
event_del(&outgoing->ev);
|
||||
|
||||
node_t *n = lookup_node(outgoing->name);
|
||||
|
||||
if(n && n->connection) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
|
||||
|
||||
n->connection->outgoing = outgoing;
|
||||
return;
|
||||
}
|
||||
|
||||
init_configuration(&outgoing->config_tree);
|
||||
read_host_config(outgoing->config_tree, outgoing->name);
|
||||
outgoing->cfg = lookup_config(outgoing->config_tree, "Address");
|
||||
|
||||
if(!outgoing->cfg) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No address specified for %s", outgoing->name);
|
||||
return;
|
||||
}
|
||||
|
||||
do_outgoing_connection(outgoing);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -526,7 +532,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
fd = accept(sock, &sa.sa, &len);
|
||||
|
||||
if(fd < 0) {
|
||||
logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -544,7 +550,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
c->socket = fd;
|
||||
c->last_ping_time = time(NULL);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
|
||||
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
|
||||
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
|
||||
|
@ -559,9 +565,15 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
}
|
||||
|
||||
static void free_outgoing(outgoing_t *outgoing) {
|
||||
if(event_initialized(&outgoing->ev))
|
||||
event_del(&outgoing->ev);
|
||||
|
||||
if(outgoing->ai)
|
||||
freeaddrinfo(outgoing->ai);
|
||||
|
||||
if(outgoing->config_tree)
|
||||
exit_configuration(&outgoing->config_tree);
|
||||
|
||||
if(outgoing->name)
|
||||
free(outgoing->name);
|
||||
|
||||
|
@ -569,26 +581,60 @@ static void free_outgoing(outgoing_t *outgoing) {
|
|||
}
|
||||
|
||||
void try_outgoing_connections(void) {
|
||||
static config_t *cfg = NULL;
|
||||
char *name;
|
||||
outgoing_t *outgoing;
|
||||
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
|
||||
|
||||
if(!outgoing_list) {
|
||||
outgoing_list = list_alloc((list_action_t)free_outgoing);
|
||||
} else {
|
||||
for list_each(outgoing_t, outgoing, outgoing_list)
|
||||
outgoing->timeout = -1;
|
||||
}
|
||||
|
||||
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
|
||||
|
||||
for(config_t *cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
char *name;
|
||||
get_config_string(cfg, &name);
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(LOG_ERR,
|
||||
logger(DEBUG_ALWAYS, LOG_ERR,
|
||||
"Invalid name for outgoing connection in %s line %d",
|
||||
cfg->file, cfg->line);
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
outgoing = xmalloc_and_zero(sizeof *outgoing);
|
||||
bool found = false;
|
||||
|
||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||
if(!strcmp(outgoing->name, name)) {
|
||||
found = true;
|
||||
outgoing->timeout = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
outgoing_t *outgoing = xmalloc_and_zero(sizeof *outgoing);
|
||||
outgoing->name = name;
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing);
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate any connections whose outgoing_t is to be deleted. */
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing && c->outgoing->timeout == -1) {
|
||||
c->outgoing = NULL;
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
|
||||
terminate_connection(c, c->status.active);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete outgoing_ts for which there is no ConnectTo. */
|
||||
|
||||
for list_each(outgoing_t, outgoing, outgoing_list)
|
||||
if(outgoing->timeout == -1)
|
||||
list_delete_node(outgoing_list, node);
|
||||
}
|
||||
|
|
85
src/netutl.c
85
src/netutl.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
netutl.c -- some supporting network utility code
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,7 +42,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
|
|||
err = getaddrinfo(address, service, &hint, &ai);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Error looking up %s port %s: %s", address,
|
||||
service, gai_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
@ -62,8 +62,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port) {
|
|||
err = getaddrinfo(address, port, &hint, &ai);
|
||||
|
||||
if(err || !ai) {
|
||||
ifdebug(SCARY_THINGS)
|
||||
logger(LOG_DEBUG, "Unknown type address %s port %s", address, port);
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Unknown type address %s port %s", address, port);
|
||||
result.sa.sa_family = AF_UNKNOWN;
|
||||
result.unknown.address = xstrdup(address);
|
||||
result.unknown.port = xstrdup(port);
|
||||
|
@ -83,7 +82,9 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
|
|||
int err;
|
||||
|
||||
if(sa->sa.sa_family == AF_UNKNOWN) {
|
||||
if(addrstr)
|
||||
*addrstr = xstrdup(sa->unknown.address);
|
||||
if(portstr)
|
||||
*portstr = xstrdup(sa->unknown.port);
|
||||
return;
|
||||
}
|
||||
|
@ -91,7 +92,7 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
|
|||
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while translating addresses: %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while translating addresses: %s",
|
||||
gai_strerror(err));
|
||||
abort();
|
||||
}
|
||||
|
@ -121,7 +122,7 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
|
|||
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
|
||||
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while looking up hostname: %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while looking up hostname: %s",
|
||||
gai_strerror(err));
|
||||
}
|
||||
|
||||
|
@ -152,7 +153,7 @@ int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
|
|||
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
|
||||
a->sa.sa_family);
|
||||
abort();
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
|
|||
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
|
||||
a->sa.sa_family);
|
||||
abort();
|
||||
}
|
||||
|
@ -224,71 +225,3 @@ void sockaddrunmap(sockaddr_t *sa) {
|
|||
sa->in.sin_family = AF_INET;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subnet mask handling */
|
||||
|
||||
int maskcmp(const void *va, const void *vb, int masklen) {
|
||||
int i, m, result;
|
||||
const char *a = va;
|
||||
const char *b = vb;
|
||||
|
||||
for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
|
||||
result = a[i] - b[i];
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(m)
|
||||
return (a[i] & (0x100 - (1 << (8 - m)))) -
|
||||
(b[i] & (0x100 - (1 << (8 - m))));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mask(void *va, int masklen, int len) {
|
||||
int i;
|
||||
char *a = va;
|
||||
|
||||
i = masklen / 8;
|
||||
masklen %= 8;
|
||||
|
||||
if(masklen)
|
||||
a[i++] &= (0x100 - (1 << (8 - masklen)));
|
||||
|
||||
for(; i < len; i++)
|
||||
a[i] = 0;
|
||||
}
|
||||
|
||||
void maskcpy(void *va, const void *vb, int masklen, int len) {
|
||||
int i, m;
|
||||
char *a = va;
|
||||
const char *b = vb;
|
||||
|
||||
for(m = masklen, i = 0; m >= 8; m -= 8, i++)
|
||||
a[i] = b[i];
|
||||
|
||||
if(m) {
|
||||
a[i] = b[i] & (0x100 - (1 << (8 - m)));
|
||||
i++;
|
||||
}
|
||||
|
||||
for(; i < len; i++)
|
||||
a[i] = 0;
|
||||
}
|
||||
|
||||
bool maskcheck(const void *va, int masklen, int len) {
|
||||
int i;
|
||||
const char *a = va;
|
||||
|
||||
i = masklen / 8;
|
||||
masklen %= 8;
|
||||
|
||||
if(masklen && a[i++] & (0xff >> masklen))
|
||||
return false;
|
||||
|
||||
for(; i < len; i++)
|
||||
if(a[i] != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
netutl.h -- header file for netutl.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -34,9 +34,5 @@ extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
|
|||
extern void sockaddrunmap(sockaddr_t *);
|
||||
extern void sockaddrfree(sockaddr_t *);
|
||||
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *);
|
||||
extern int maskcmp(const void *, const void *, int);
|
||||
extern void maskcpy(void *, const void *, int, int);
|
||||
extern void mask(void *, int, int);
|
||||
extern bool maskcheck(const void *, int, int);
|
||||
|
||||
#endif /* __TINC_NETUTL_H__ */
|
||||
|
|
84
src/node.c
84
src/node.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
node.c -- node tree management
|
||||
Copyright (C) 2001-2011 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -21,16 +21,17 @@
|
|||
#include "system.h"
|
||||
|
||||
#include "control_common.h"
|
||||
#include "splay_tree.h"
|
||||
#include "hash.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "splay_tree.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
splay_tree_t *node_tree; /* Known nodes, sorted by name */
|
||||
splay_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */
|
||||
splay_tree_t *node_tree;
|
||||
static hash_t *node_udp_cache;
|
||||
|
||||
node_t *myself;
|
||||
|
||||
|
@ -38,24 +39,13 @@ static int node_compare(const node_t *a, const node_t *b) {
|
|||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static int node_udp_compare(const node_t *a, const node_t *b) {
|
||||
int result;
|
||||
|
||||
result = sockaddrcmp(&a->address, &b->address);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
|
||||
}
|
||||
|
||||
void init_nodes(void) {
|
||||
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
|
||||
node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
|
||||
node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
|
||||
}
|
||||
|
||||
void exit_nodes(void) {
|
||||
splay_delete_tree(node_udp_tree);
|
||||
hash_free(node_udp_cache);
|
||||
splay_delete_tree(node_tree);
|
||||
}
|
||||
|
||||
|
@ -85,8 +75,8 @@ void free_node(node_t *n) {
|
|||
cipher_close(&n->outcipher);
|
||||
digest_close(&n->outdigest);
|
||||
|
||||
ecdh_free(&n->ecdh);
|
||||
ecdsa_free(&n->ecdsa);
|
||||
sptps_stop(&n->sptps);
|
||||
|
||||
if(timeout_initialized(&n->mtuevent))
|
||||
event_del(&n->mtuevent);
|
||||
|
@ -108,23 +98,12 @@ void node_add(node_t *n) {
|
|||
}
|
||||
|
||||
void node_del(node_t *n) {
|
||||
splay_node_t *node, *next;
|
||||
edge_t *e;
|
||||
subnet_t *s;
|
||||
|
||||
for(node = n->subnet_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
s = node->data;
|
||||
for splay_each(subnet_t, s, n->subnet_tree)
|
||||
subnet_del(n, s);
|
||||
}
|
||||
|
||||
for(node = n->edge_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
e = node->data;
|
||||
for splay_each(edge_t, e, n->edge_tree)
|
||||
edge_del(e);
|
||||
}
|
||||
|
||||
splay_delete(node_udp_tree, n);
|
||||
splay_delete(node_tree, n);
|
||||
}
|
||||
|
||||
|
@ -137,62 +116,41 @@ node_t *lookup_node(char *name) {
|
|||
}
|
||||
|
||||
node_t *lookup_node_udp(const sockaddr_t *sa) {
|
||||
node_t n = {NULL};
|
||||
|
||||
n.address = *sa;
|
||||
n.name = NULL;
|
||||
|
||||
return splay_search(node_udp_tree, &n);
|
||||
return hash_search(node_udp_cache, sa);
|
||||
}
|
||||
|
||||
void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
||||
if(n == myself) {
|
||||
logger(LOG_WARNING, "Trying to update UDP address of myself!");
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Trying to update UDP address of myself!");
|
||||
return;
|
||||
}
|
||||
|
||||
splay_delete(node_udp_tree, n);
|
||||
|
||||
if(n->hostname)
|
||||
free(n->hostname);
|
||||
hash_insert(node_udp_cache, &n->address, NULL);
|
||||
|
||||
if(sa) {
|
||||
n->address = *sa;
|
||||
hash_insert(node_udp_cache, sa, n);
|
||||
free(n->hostname);
|
||||
n->hostname = sockaddr2hostname(&n->address);
|
||||
splay_insert(node_udp_tree, n);
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
|
||||
} else {
|
||||
memset(&n->address, 0, sizeof n->address);
|
||||
n->hostname = NULL;
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
|
||||
}
|
||||
}
|
||||
|
||||
bool dump_nodes(connection_t *c) {
|
||||
splay_node_t *node;
|
||||
node_t *n;
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
send_request(c, "%d %d %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)", CONTROL, REQ_DUMP_NODES,
|
||||
n->name, n->hostname, cipher_get_nid(&n->outcipher),
|
||||
for splay_each(node_t, n, node_tree)
|
||||
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
|
||||
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(&n->outcipher),
|
||||
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
|
||||
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
|
||||
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu);
|
||||
}
|
||||
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
|
||||
|
||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
|
||||
}
|
||||
|
||||
bool dump_traffic(connection_t *c) {
|
||||
splay_node_t *node;
|
||||
node_t *n;
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
for splay_each(node_t, n, node_tree)
|
||||
send_request(c, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_TRAFFIC,
|
||||
n->name, n->in_packets, n->in_bytes, n->out_packets, n->out_bytes);
|
||||
}
|
||||
|
||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
|
||||
}
|
||||
|
|
16
src/node.h
16
src/node.h
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
node.h -- header for node.c
|
||||
Copyright (C) 2001-2010 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -25,32 +25,34 @@
|
|||
#include "cipher.h"
|
||||
#include "connection.h"
|
||||
#include "digest.h"
|
||||
#include "ecdh.h"
|
||||
#include "subnet.h"
|
||||
|
||||
typedef struct node_status_t {
|
||||
unsigned int unused_active:1; /* 1 if active (not used for nodes) */
|
||||
unsigned int validkey:1; /* 1 if we currently have a valid key for him */
|
||||
unsigned int unused_waitingforkey:1; /* 1 if we already sent out a request */
|
||||
unsigned int waitingforkey:1; /* 1 if we already sent out a request */
|
||||
unsigned int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
|
||||
unsigned int reachable:1; /* 1 if this node is reachable in the graph */
|
||||
unsigned int indirect:1; /* 1 if this node is not directly reachable by us */
|
||||
unsigned int ecdh:1; /* 1 if this node supports ECDH key exchange */
|
||||
unsigned int unused:25;
|
||||
unsigned int sptps:1; /* 1 if this node supports SPTPS */
|
||||
unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */
|
||||
unsigned int unused:24;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
char *name; /* name of this node */
|
||||
uint32_t options; /* options turned on for this node */
|
||||
|
||||
int sock; /* Socket to use for outgoing UDP packets */
|
||||
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
|
||||
node_status_t status;
|
||||
time_t last_state_change;
|
||||
time_t last_req_key;
|
||||
|
||||
ecdsa_t ecdsa; /* His public ECDSA key */
|
||||
ecdh_t ecdh; /* State for ECDH key exchange */
|
||||
sptps_t sptps;
|
||||
|
||||
cipher_t incipher; /* Cipher for UDP packets */
|
||||
digest_t indigest; /* Digest for UDP packets */
|
||||
|
@ -63,6 +65,7 @@ typedef struct node_t {
|
|||
|
||||
int distance;
|
||||
struct node_t *nexthop; /* nearest node from us to him */
|
||||
struct edge_t *prevedge; /* nearest node from him to us */
|
||||
struct node_t *via; /* next hop for UDP packets */
|
||||
|
||||
splay_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
|
||||
|
@ -90,7 +93,6 @@ typedef struct node_t {
|
|||
|
||||
extern struct node_t *myself;
|
||||
extern splay_tree_t *node_tree;
|
||||
extern splay_tree_t *node_udp_tree;
|
||||
|
||||
extern void init_nodes(void);
|
||||
extern void exit_nodes(void);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
cipher.c -- Symmetric block cipher handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -26,6 +26,12 @@
|
|||
#include "logger.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
typedef struct cipher_counter {
|
||||
unsigned char counter[EVP_MAX_IV_LENGTH];
|
||||
unsigned char block[EVP_MAX_IV_LENGTH];
|
||||
int n;
|
||||
} cipher_counter_t;
|
||||
|
||||
static bool cipher_open(cipher_t *cipher) {
|
||||
EVP_CIPHER_CTX_init(&cipher->ctx);
|
||||
|
||||
|
@ -38,7 +44,7 @@ bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
|||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(LOG_ERR, "Unknown cipher name '%s'!", name);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,7 +54,7 @@ bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
|||
if(cipher->cipher)
|
||||
return cipher_open(cipher);
|
||||
|
||||
logger(LOG_ERR, "Unknown cipher nid %d!", nid);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown cipher nid %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,10 +65,12 @@ bool cipher_open_blowfish_ofb(cipher_t *cipher) {
|
|||
|
||||
void cipher_close(cipher_t *cipher) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
|
||||
free(cipher->counter);
|
||||
cipher->counter = NULL;
|
||||
}
|
||||
|
||||
size_t cipher_keylength(const cipher_t *cipher) {
|
||||
return cipher->cipher->key_len + cipher->cipher->iv_len;
|
||||
return cipher->cipher->key_len + cipher->cipher->block_size;
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
|
@ -76,7 +84,7 @@ bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
|||
if(result)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,28 +99,92 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
|
|||
if(result)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cipher_set_counter(cipher_t *cipher, const void *counter, size_t len) {
|
||||
if(len > cipher->cipher->block_size - 4) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter too long");
|
||||
abort();
|
||||
}
|
||||
|
||||
memcpy(cipher->counter->counter + cipher->cipher->block_size - len, counter, len);
|
||||
memset(cipher->counter->counter, 0, 4);
|
||||
cipher->counter->n = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_set_counter_key(cipher_t *cipher, void *key) {
|
||||
int result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, NULL);
|
||||
if(!result) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!cipher->counter)
|
||||
cipher->counter = xmalloc_and_zero(sizeof *cipher->counter);
|
||||
else
|
||||
cipher->counter->n = 0;
|
||||
|
||||
memcpy(cipher->counter->counter, (unsigned char *)key + cipher->cipher->key_len, cipher->cipher->block_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_counter_xor(cipher_t *cipher, const void *indata, size_t inlen, void *outdata) {
|
||||
if(!cipher->counter) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char *in = indata;
|
||||
unsigned char *out = outdata;
|
||||
|
||||
while(inlen--) {
|
||||
// Encrypt the new counter value if we need it
|
||||
if(!cipher->counter->n) {
|
||||
int len;
|
||||
if(!EVP_EncryptUpdate(&cipher->ctx, cipher->counter->block, &len, cipher->counter->counter, cipher->cipher->block_size)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the counter value
|
||||
for(int i = 0; i < cipher->cipher->block_size; i++)
|
||||
if(++cipher->counter->counter[i])
|
||||
break;
|
||||
}
|
||||
|
||||
*out++ = *in++ ^ cipher->counter->counter[cipher->counter->n++];
|
||||
|
||||
if(cipher->counter->n >= cipher->cipher->block_size)
|
||||
cipher->counter->n = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
*outlen = len + pad;
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
*outlen = len;
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -122,18 +194,18 @@ bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
*outlen = len + pad;
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
*outlen = len;
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
cipher.h -- header file cipher.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,6 +29,7 @@
|
|||
typedef struct cipher {
|
||||
EVP_CIPHER_CTX ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
struct cipher_counter *counter;
|
||||
} cipher_t;
|
||||
|
||||
extern bool cipher_open_by_name(cipher_t *, const char *);
|
||||
|
@ -38,8 +39,11 @@ extern void cipher_close(cipher_t *);
|
|||
extern size_t cipher_keylength(const cipher_t *);
|
||||
extern bool cipher_set_key(cipher_t *, void *, bool);
|
||||
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool);
|
||||
extern bool cipher_set_counter(cipher_t *, const void *, size_t);
|
||||
extern bool cipher_set_counter_key(cipher_t *, void *);
|
||||
extern bool cipher_encrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
|
||||
extern bool cipher_decrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool);
|
||||
extern bool cipher_counter_xor(cipher_t *, const void *indata, size_t inlen, void *outdata);
|
||||
extern int cipher_get_nid(const cipher_t *);
|
||||
extern bool cipher_active(const cipher_t *);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
digest.c -- Digest handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -41,7 +41,7 @@ bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
|
|||
digest->key = NULL;
|
||||
|
||||
if(!digest->digest) {
|
||||
logger(LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
|
|||
digest->key = NULL;
|
||||
|
||||
if(!digest->digest) {
|
||||
logger(LOG_DEBUG, "Unknown digest nid %d!", nid);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,6 @@ bool digest_set_key(digest_t *digest, const void *key, size_t len) {
|
|||
}
|
||||
|
||||
void digest_close(digest_t *digest) {
|
||||
if(digest->key)
|
||||
free(digest->key);
|
||||
digest->key = NULL;
|
||||
}
|
||||
|
@ -95,7 +94,7 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out
|
|||
if(!EVP_DigestInit(&ctx, digest->digest)
|
||||
|| !EVP_DigestUpdate(&ctx, indata, inlen)
|
||||
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
|
||||
logger(LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +114,10 @@ int digest_get_nid(const digest_t *digest) {
|
|||
return digest->digest ? digest->digest->type : 0;
|
||||
}
|
||||
|
||||
size_t digest_keylength(const digest_t *digest) {
|
||||
return digest->digest->md_size;
|
||||
}
|
||||
|
||||
size_t digest_length(const digest_t *digest) {
|
||||
return digest->maclength;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
digest.h -- header file digest.c
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -39,6 +39,7 @@ extern bool digest_create(struct digest *, const void *indata, size_t inlen, voi
|
|||
extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
|
||||
extern bool digest_set_key(struct digest *, const void *key, size_t len);
|
||||
extern int digest_get_nid(const struct digest *);
|
||||
extern size_t digest_keylength(const struct digest *);
|
||||
extern size_t digest_length(const struct digest *);
|
||||
extern bool digest_active(const struct digest *);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange handling
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -30,21 +30,32 @@
|
|||
|
||||
bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
|
||||
*ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!*ecdh) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EC_KEY_generate_key(*ecdh)) {
|
||||
logger(LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
const EC_POINT *point = EC_KEY_get0_public_key(*ecdh);
|
||||
if(!point) {
|
||||
logger(LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(*ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
logger(LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
EC_KEY_free(*ecdh);
|
||||
*ecdh = NULL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -53,14 +64,15 @@ bool ecdh_generate_public(ecdh_t *ecdh, void *pubkey) {
|
|||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(*ecdh));
|
||||
if(!point) {
|
||||
logger(LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = EC_POINT_oct2point(EC_KEY_get0_group(*ecdh), point, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
logger(LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
EC_POINT_free(point);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ECDH_compute_key(shared, ECDH_SIZE, point, *ecdh, NULL);
|
||||
|
@ -69,7 +81,7 @@ bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
|||
*ecdh = NULL;
|
||||
|
||||
if(!result) {
|
||||
logger(LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
ecdsa.c -- ECDSA key handling
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -30,15 +30,19 @@
|
|||
//
|
||||
bool ecdsa_set_base64_public_key(ecdsa_t *ecdsa, const char *p) {
|
||||
*ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!*ecdsa) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = strlen(p);
|
||||
unsigned char pubkey[len / 4 * 3 + 3];
|
||||
const unsigned char *ppubkey = pubkey;
|
||||
len = b64decode(p, pubkey, len);
|
||||
len = b64decode(p, (char *)pubkey, len);
|
||||
|
||||
if(!o2i_ECPublicKey(ecdsa, &ppubkey, len)) {
|
||||
logger(LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
abort();
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -49,7 +53,7 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
|||
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
|
||||
|
||||
char *base64 = malloc(len * 4 / 3 + 5);
|
||||
b64encode(pubkey, base64, len);
|
||||
b64encode((char *)pubkey, base64, len);
|
||||
|
||||
free(pubkey);
|
||||
|
||||
|
@ -64,7 +68,7 @@ bool ecdsa_read_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
|||
if(*ecdsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -74,7 +78,7 @@ bool ecdsa_read_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
|||
if(*ecdsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -87,31 +91,27 @@ size_t ecdsa_size(ecdsa_t *ecdsa) {
|
|||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
unsigned int siglen = ECDSA_size(*ecdsa);
|
||||
|
||||
char hash[SHA512_DIGEST_LENGTH];
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
memset(sig, 0, siglen);
|
||||
|
||||
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, *ecdsa)) {
|
||||
logger(LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(siglen != ECDSA_size(*ecdsa)) {
|
||||
logger(LOG_ERR, "Signature length %d != %d", siglen, ECDSA_size(*ecdsa));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
unsigned int siglen = ECDSA_size(*ecdsa);
|
||||
|
||||
char hash[SHA512_DIGEST_LENGTH];
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, *ecdsa)) {
|
||||
logger(LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
|||
int len = i2o_ECPublicKey(*ecdsa, &pubkey);
|
||||
|
||||
char *base64 = malloc(len * 4 / 3 + 5);
|
||||
b64encode(pubkey, base64, len);
|
||||
b64encode((char *)pubkey, base64, len);
|
||||
|
||||
free(pubkey);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
prf.c -- Pseudo-Random Function for key material generation
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,14 +19,16 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include "digest.h"
|
||||
#include "prf.h"
|
||||
|
||||
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
|
||||
We use SHA512 and Whirlpool instead of MD5 and SHA1.
|
||||
We use SHA512 instead of MD5 and SHA1.
|
||||
*/
|
||||
|
||||
static bool prf_xor(int nid, char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
|
||||
static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
|
||||
digest_t digest;
|
||||
|
||||
if(!digest_open_by_nid(&digest, nid, -1))
|
||||
|
@ -65,12 +67,9 @@ static bool prf_xor(int nid, char *secret, size_t secretlen, char *seed, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
|
||||
/* Split secret in half, generate outlen bits with two different hash algorithms,
|
||||
and XOR the results. */
|
||||
|
||||
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
|
||||
/* This construction allows us to easily switch back to a scheme where the PRF is calculated using two different digest algorithms. */
|
||||
memset(out, 0, outlen);
|
||||
|
||||
return prf_xor(NID_sha512, secret, (secretlen + 1) / 2, seed, seedlen, out, outlen)
|
||||
&& prf_xor(NID_whirlpool, secret + secretlen / 2, (secretlen + 1) / 2, seed, seedlen, out, outlen);
|
||||
return prf_xor(NID_sha512, secret, secretlen, seed, seedlen, out, outlen);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@
|
|||
#ifndef __TINC_PRF_H__
|
||||
#define __TINC_PRF_H__
|
||||
|
||||
extern bool prf(char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen);
|
||||
extern bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
rsa.c -- RSA key handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,16 +29,21 @@
|
|||
|
||||
bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
|
||||
*rsa = RSA_new();
|
||||
BN_hex2bn(&(*rsa)->n, n);
|
||||
BN_hex2bn(&(*rsa)->e, e);
|
||||
if(BN_hex2bn(&(*rsa)->n, n) != strlen(n))
|
||||
return false;
|
||||
if(BN_hex2bn(&(*rsa)->e, e) != strlen(e))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
|
||||
*rsa = RSA_new();
|
||||
BN_hex2bn(&(*rsa)->n, n);
|
||||
BN_hex2bn(&(*rsa)->e, e);
|
||||
BN_hex2bn(&(*rsa)->d, d);
|
||||
if(BN_hex2bn(&(*rsa)->n, n) != strlen(n))
|
||||
return false;
|
||||
if(BN_hex2bn(&(*rsa)->e, e) != strlen(e))
|
||||
return false;
|
||||
if(BN_hex2bn(&(*rsa)->d, d) != strlen(d))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,7 +60,7 @@ bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|
|||
if(*rsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to read RSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -65,7 +70,7 @@ bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|
|||
if(*rsa)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to read RSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -77,7 +82,7 @@ bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
|||
if(RSA_public_encrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to perform RSA encryption: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA encryption: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -85,7 +90,7 @@ bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
|||
if(RSA_private_decrypt(len, in, out, *rsa, RSA_NO_PADDING) == len)
|
||||
return true;
|
||||
|
||||
logger(LOG_ERR, "Unable to perform RSA decryption: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA decryption: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
rsa.h -- RSA key handling
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
75
src/prf.c
Normal file
75
src/prf.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
prf.c -- Pseudo-Random Function for key material generation
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include "digest.h"
|
||||
#include "prf.h"
|
||||
|
||||
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
|
||||
We use SHA512 instead of MD5 and SHA1.
|
||||
*/
|
||||
|
||||
static bool prf_xor(int nid, const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, ssize_t outlen) {
|
||||
digest_t digest;
|
||||
|
||||
if(!digest_open_by_nid(&digest, nid, -1))
|
||||
return false;
|
||||
|
||||
if(!digest_set_key(&digest, secret, secretlen))
|
||||
return false;
|
||||
|
||||
size_t len = digest_length(&digest);
|
||||
|
||||
/* Data is what the "inner" HMAC function processes.
|
||||
It consists of the previous HMAC result plus the seed.
|
||||
*/
|
||||
|
||||
char data[len + seedlen];
|
||||
memset(data, 0, len);
|
||||
memcpy(data + len, seed, seedlen);
|
||||
|
||||
char hash[len];
|
||||
|
||||
while(outlen > 0) {
|
||||
/* Inner HMAC */
|
||||
digest_create(&digest, data, len + seedlen, data);
|
||||
|
||||
/* Outer HMAC */
|
||||
digest_create(&digest, data, len + seedlen, hash);
|
||||
|
||||
/* XOR the results of the outer HMAC into the out buffer */
|
||||
for(int i = 0; i < len && i < outlen; i++)
|
||||
*out++ ^= hash[i];
|
||||
|
||||
outlen -= len;
|
||||
}
|
||||
|
||||
digest_close(&digest);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
|
||||
/* This construction allows us to easily switch back to a scheme where the PRF is calculated using two different digest algorithms. */
|
||||
memset(out, 0, outlen);
|
||||
|
||||
return prf_xor(NID_sha512, secret, secretlen, seed, seedlen, out, outlen);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
process.c -- process management functions
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -55,13 +55,11 @@ static SERVICE_STATUS_HANDLE statushandle = 0;
|
|||
|
||||
static bool install_service(void) {
|
||||
char command[4096] = "\"";
|
||||
char **argp;
|
||||
bool space;
|
||||
SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
|
||||
|
||||
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if(!manager) {
|
||||
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -74,8 +72,8 @@ static bool install_service(void) {
|
|||
|
||||
strncat(command, "\"", sizeof command - strlen(command));
|
||||
|
||||
for(argp = g_argv + 1; *argp; argp++) {
|
||||
space = strchr(*argp, ' ');
|
||||
for(char **argp = g_argv + 1; *argp; argp++) {
|
||||
char *space = strchr(*argp, ' ');
|
||||
strncat(command, " ", sizeof command - strlen(command));
|
||||
|
||||
if(space)
|
||||
|
@ -93,22 +91,22 @@ static bool install_service(void) {
|
|||
|
||||
if(!service) {
|
||||
DWORD lasterror = GetLastError();
|
||||
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
|
||||
if(lasterror != ERROR_SERVICE_EXISTS)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(service) {
|
||||
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
|
||||
logger(LOG_INFO, "%s service installed", identname);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s service installed", identname);
|
||||
} else {
|
||||
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
|
||||
}
|
||||
|
||||
if(!StartService(service, 0, NULL))
|
||||
logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
|
||||
else
|
||||
logger(LOG_INFO, "%s service started", identname);
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s service started", identname);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -119,13 +117,13 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
|||
SetServiceStatus(statushandle, &status);
|
||||
return NO_ERROR;
|
||||
case SERVICE_CONTROL_STOP:
|
||||
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
|
||||
break;
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
|
||||
break;
|
||||
default:
|
||||
logger(LOG_WARNING, "Got unexpected request %d", request);
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Got unexpected request %d", (int)request);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -137,10 +135,8 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
|||
}
|
||||
|
||||
VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
|
||||
int err = 1;
|
||||
extern int main2(int argc, char **argv);
|
||||
|
||||
|
||||
status.dwServiceType = SERVICE_WIN32;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
status.dwWin32ExitCode = 0;
|
||||
|
@ -150,8 +146,7 @@ VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
|
|||
statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
|
||||
|
||||
if (!statushandle) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
|
||||
err = 1;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
|
||||
} else {
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwCurrentState = SERVICE_START_PENDING;
|
||||
|
@ -161,11 +156,10 @@ VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
|
|||
status.dwCurrentState = SERVICE_RUNNING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
|
||||
err = main2(argc, argv);
|
||||
main2(argc, argv);
|
||||
|
||||
status.dwWaitHint = 0;
|
||||
status.dwCurrentState = SERVICE_STOPPED;
|
||||
//status.dwWin32ExitCode = err;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
}
|
||||
|
||||
|
@ -183,7 +177,7 @@ bool init_service(void) {
|
|||
return false;
|
||||
}
|
||||
else
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -206,19 +200,18 @@ bool detach(void) {
|
|||
if(do_detach) {
|
||||
#ifndef HAVE_MINGW
|
||||
if(daemon(0, 0)) {
|
||||
fprintf(stderr, "Couldn't detach from terminal: %s",
|
||||
strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if(!statushandle)
|
||||
exit(install_service());
|
||||
exit(!install_service());
|
||||
#endif
|
||||
}
|
||||
|
||||
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
|
||||
|
||||
logger(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
|
||||
VERSION, __DATE__, __TIME__, debug_level);
|
||||
|
||||
return true;
|
||||
|
@ -226,46 +219,40 @@ bool detach(void) {
|
|||
|
||||
bool execute_script(const char *name, char **envp) {
|
||||
#ifdef HAVE_SYSTEM
|
||||
int status, len;
|
||||
char *scriptname;
|
||||
int i;
|
||||
char *command;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
|
||||
#else
|
||||
len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
|
||||
#endif
|
||||
if(len < 0)
|
||||
return false;
|
||||
xasprintf(&scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension);
|
||||
|
||||
scriptname[len - 1] = '\0';
|
||||
|
||||
#ifndef HAVE_TUNEMU
|
||||
/* First check if there is a script */
|
||||
|
||||
if(access(scriptname + 1, F_OK)) {
|
||||
if(access(scriptname, F_OK)) {
|
||||
free(scriptname);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name);
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
/* Set environment */
|
||||
|
||||
for(i = 0; envp[i]; i++)
|
||||
for(int i = 0; envp[i]; i++)
|
||||
putenv(envp[i]);
|
||||
#endif
|
||||
|
||||
scriptname[len - 1] = '\"';
|
||||
status = system(scriptname);
|
||||
if(scriptinterpreter)
|
||||
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
|
||||
else
|
||||
xasprintf(&command, "\"%s\"", scriptname);
|
||||
|
||||
int status = system(command);
|
||||
|
||||
free(command);
|
||||
free(scriptname);
|
||||
|
||||
/* Unset environment */
|
||||
|
||||
for(i = 0; envp[i]; i++) {
|
||||
for(int i = 0; envp[i]; i++) {
|
||||
char *e = strchr(envp[i], '=');
|
||||
if(e) {
|
||||
char p[e - envp[i] + 1];
|
||||
|
@ -279,20 +266,20 @@ bool execute_script(const char *name, char **envp) {
|
|||
if(status != -1) {
|
||||
if(WIFEXITED(status)) { /* Child exited by itself */
|
||||
if(WEXITSTATUS(status)) {
|
||||
logger(LOG_ERR, "Script %s exited with non-zero status %d",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Script %s exited with non-zero status %d",
|
||||
name, WEXITSTATUS(status));
|
||||
return false;
|
||||
}
|
||||
} else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
|
||||
logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Script %s was killed by signal %d (%s)",
|
||||
name, WTERMSIG(status), strsignal(WTERMSIG(status)));
|
||||
return false;
|
||||
} else { /* Something strange happened */
|
||||
logger(LOG_ERR, "Script %s terminated abnormally", name);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Script %s terminated abnormally", name);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
process.h -- header file for process.c
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2010 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol.c -- handle the meta-protocol, basic functions
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -34,7 +34,7 @@ bool experimental = false;
|
|||
|
||||
/* Jumptable for the request handlers */
|
||||
|
||||
static bool (*request_handlers[])(connection_t *, char *) = {
|
||||
static bool (*request_handlers[])(connection_t *, const char *) = {
|
||||
id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
|
||||
status_h, error_h, termreq_h,
|
||||
ping_h, pong_h,
|
||||
|
@ -56,6 +56,9 @@ static char (*request_name[]) = {
|
|||
static splay_tree_t *past_request_tree;
|
||||
|
||||
bool check_id(const char *id) {
|
||||
if(!id || !*id)
|
||||
return false;
|
||||
|
||||
for(; *id; id++)
|
||||
if(!isalnum(*id) && *id != '_')
|
||||
return false;
|
||||
|
@ -80,85 +83,71 @@ bool send_request(connection_t *c, const char *format, ...) {
|
|||
va_end(args);
|
||||
|
||||
if(len < 0 || len > MAXBUFSIZE - 1) {
|
||||
logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
ifdebug(PROTOCOL) {
|
||||
ifdebug(META)
|
||||
logger(LOG_DEBUG, "Sending %s to %s (%s): %s",
|
||||
request_name[atoi(request)], c->name, c->hostname, request);
|
||||
else
|
||||
logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[atoi(request)],
|
||||
c->name, c->hostname);
|
||||
}
|
||||
logger(DEBUG_META, LOG_DEBUG, "Sending %s to %s (%s): %s", request_name[atoi(request)], c->name, c->hostname, request);
|
||||
|
||||
request[len++] = '\n';
|
||||
|
||||
if(c == broadcast) {
|
||||
if(c == everyone) {
|
||||
broadcast_meta(NULL, request, len);
|
||||
return true;
|
||||
} else
|
||||
return send_meta(c, request, len);
|
||||
}
|
||||
|
||||
void forward_request(connection_t *from, char *request) {
|
||||
/* Note: request is not zero terminated anymore after a call to this function! */
|
||||
ifdebug(PROTOCOL) {
|
||||
ifdebug(META)
|
||||
logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s",
|
||||
request_name[atoi(request)], from->name, from->hostname, request);
|
||||
else
|
||||
logger(LOG_DEBUG, "Forwarding %s from %s (%s)",
|
||||
request_name[atoi(request)], from->name, from->hostname);
|
||||
}
|
||||
void forward_request(connection_t *from, const char *request) {
|
||||
logger(DEBUG_META, LOG_DEBUG, "Forwarding %s from %s (%s): %s", request_name[atoi(request)], from->name, from->hostname, request);
|
||||
|
||||
// Create a temporary newline-terminated copy of the request
|
||||
int len = strlen(request);
|
||||
request[len++] = '\n';
|
||||
broadcast_meta(from, request, len);
|
||||
char tmp[len + 1];
|
||||
memcpy(tmp, request, len);
|
||||
tmp[len] = '\n';
|
||||
broadcast_meta(from, tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
bool receive_request(connection_t *c, char *request) {
|
||||
bool receive_request(connection_t *c, const char *request) {
|
||||
if(proxytype == PROXY_HTTP && c->allow_request == ID) {
|
||||
if(!request[0] || request[0] == '\r')
|
||||
return true;
|
||||
if(!strncasecmp(request, "HTTP/1.1 ", 9)) {
|
||||
if(!strncmp(request + 9, "200", 3)) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
return true;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Proxy request rejected: %s", request + 9);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int reqno = atoi(request);
|
||||
|
||||
if(reqno || *request == '0') {
|
||||
if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) {
|
||||
ifdebug(META)
|
||||
logger(LOG_DEBUG, "Unknown request from %s (%s): %s",
|
||||
c->name, c->hostname, request);
|
||||
else
|
||||
logger(LOG_ERR, "Unknown request from %s (%s)",
|
||||
c->name, c->hostname);
|
||||
|
||||
logger(DEBUG_META, LOG_DEBUG, "Unknown request from %s (%s): %s", c->name, c->hostname, request);
|
||||
return false;
|
||||
} else {
|
||||
ifdebug(PROTOCOL) {
|
||||
ifdebug(META)
|
||||
logger(LOG_DEBUG, "Got %s from %s (%s): %s",
|
||||
request_name[reqno], c->name, c->hostname, request);
|
||||
else
|
||||
logger(LOG_DEBUG, "Got %s from %s (%s)",
|
||||
request_name[reqno], c->name, c->hostname);
|
||||
}
|
||||
logger(DEBUG_META, LOG_DEBUG, "Got %s from %s (%s): %s", request_name[reqno], c->name, c->hostname, request);
|
||||
}
|
||||
|
||||
if((c->allow_request != ALL) && (c->allow_request != reqno)) {
|
||||
logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name,
|
||||
c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unauthorized request from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!request_handlers[reqno](c, request)) {
|
||||
/* Something went wrong. Probably scriptkiddies. Terminate. */
|
||||
|
||||
logger(LOG_ERR, "Error while processing %s from %s (%s)",
|
||||
request_name[reqno], c->name, c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while processing %s from %s (%s)", request_name[reqno], c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "Bogus data received from %s (%s)",
|
||||
c->name, c->hostname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Bogus data received from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,20 +160,20 @@ static int past_request_compare(const past_request_t *a, const past_request_t *b
|
|||
|
||||
static void free_past_request(past_request_t *r) {
|
||||
if(r->request)
|
||||
free(r->request);
|
||||
free((char *)r->request);
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
static struct event past_request_event;
|
||||
|
||||
bool seen_request(char *request) {
|
||||
bool seen_request(const char *request) {
|
||||
past_request_t *new, p = {NULL};
|
||||
|
||||
p.request = request;
|
||||
|
||||
if(splay_search(past_request_tree, &p)) {
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Already seen request");
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Already seen request");
|
||||
return true;
|
||||
} else {
|
||||
new = xmalloc(sizeof *new);
|
||||
|
@ -197,15 +186,10 @@ bool seen_request(char *request) {
|
|||
}
|
||||
|
||||
static void age_past_requests(int fd, short events, void *data) {
|
||||
splay_node_t *node, *next;
|
||||
past_request_t *p;
|
||||
int left = 0, deleted = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for(node = past_request_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
p = node->data;
|
||||
|
||||
for splay_each(past_request_t, p, past_request_tree) {
|
||||
if(p->firstseen + pinginterval <= now)
|
||||
splay_delete_node(past_request_tree, node), deleted++;
|
||||
else
|
||||
|
@ -213,7 +197,7 @@ static void age_past_requests(int fd, short events, void *data) {
|
|||
}
|
||||
|
||||
if(left || deleted)
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d",
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d",
|
||||
deleted, left);
|
||||
|
||||
if(left)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue