Import Upstream version 1.1~pre12

This commit is contained in:
Guus Sliepen 2019-08-26 13:44:52 +02:00
parent 1813f3157e
commit aa10d88732
134 changed files with 8673 additions and 4989 deletions

View file

@ -2,16 +2,25 @@
sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
## Make sure version.c is always rebuilt
.PHONY: version.c
version.c:
CLEANFILES = version_git.h
.PHONY: version-stamp
version-stamp:
version_git.h: version-stamp
$(AM_V_GEN)echo >$@
@-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||:
${srcdir}/version.c: version_git.h
## Now a hack to appease some versions of BSD make that don't understand that "./foo" is the same as "foo".
if BSD
version.c: ${srcdir}/version.c
endif
if LINUX
sbin_PROGRAMS += sptps_speed
endif
DEFAULT_INCLUDES =
ed25519_SOURCES = \
ed25519/add_scalar.c \
ed25519/ed25519.h \
@ -49,11 +58,6 @@ tincd_SOURCES = \
edge.c edge.h \
ethernet.h \
event.c event.h \
fake-gai-errnos.h \
fake-getaddrinfo.c fake-getaddrinfo.h \
fake-getnameinfo.c fake-getnameinfo.h \
getopt.c getopt.h \
getopt1.c \
graph.c graph.h \
hash.c hash.h \
have.h \
@ -92,13 +96,15 @@ tincd_SOURCES = \
utils.c utils.h \
xalloc.h \
version.c version.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
tinc_SOURCES = \
dropin.c dropin.h \
getopt.c getopt.h \
getopt1.c \
fsck.c fsck.h \
ifconfig.c ifconfig.h \
info.c info.h \
invitation.c invitation.h \
list.c list.h \
@ -111,6 +117,9 @@ tinc_SOURCES = \
top.c top.h \
utils.c utils.h \
version.c version.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
@ -119,12 +128,15 @@ sptps_test_SOURCES = \
sptps.c sptps.h \
sptps_test.c \
utils.c utils.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps_keypair_SOURCES = \
sptps_keypair.c \
utils.c utils.h \
ed25519/ecdsagen.c \
$(ed25519_SOURCES)
sptps_speed_SOURCES = \
@ -132,11 +144,29 @@ sptps_speed_SOURCES = \
sptps.c sptps.h \
sptps_speed.c \
utils.c utils.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
## Conditionally compile device drivers
if !GETOPT
tincd_SOURCES += \
getopt.c getopt.h \
getopt1.c
tinc_SOURCES += \
getopt.c getopt.h \
getopt1.c
sptps_test_SOURCES += \
getopt.c getopt.h \
getopt1.c
sptps_keypair_SOURCES += \
getopt.c getopt.h \
getopt1.c
endif
if LINUX
tincd_SOURCES += linux/device.c
endif
@ -173,54 +203,37 @@ tincd_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
openssl/prf.c \
openssl/rsa.c
tinc_SOURCES += \
openssl/cipher.c \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
openssl/prf.c \
openssl/rsa.c \
openssl/rsagen.c
sptps_test_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
openssl/prf.c
sptps_keypair_SOURCES += \
openssl/crypto.c \
ed25519/ecdsagen.c
openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
openssl/prf.c
endif
else
if GCRYPT
tincd_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/ecdh.c \
gcrypt/ecdsa.c \
gcrypt/prf.c \
gcrypt/rsa.c
tinc_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/ecdh.c \
gcrypt/ecdsa.c \
gcrypt/ecdsagen.c \
gcrypt/prf.c \
gcrypt/rsa.c \
gcrypt/rsagen.c
@ -228,18 +241,44 @@ sptps_test_SOURCES += \
gcrypt/cipher.c \
gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h \
gcrypt/ecdh.c \
gcrypt/ecdsa.c \
gcrypt/prf.c
sptps_keypair_SOURCES += \
openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c
else
tincd_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
tinc_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
sptps_test_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
sptps_keypair_SOURCES += \
nolegacy/crypto.c
sptps_speed_SOURCES += \
nolegacy/crypto.c \
nolegacy/prf.c
endif
endif
if MINIUPNPC
tincd_SOURCES += upnp.h upnp.c
tincd_LDADD = $(MINIUPNPC_LIBS)
tincd_LDFLAGS = -pthread
endif
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
sptps_speed_LDADD = -lrt
LIBS = @LIBS@
LIBS = @LIBS@ -lm
if TUNEMU
LIBS += -lpcap
endif
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote.

View file

@ -1,7 +1,7 @@
# Makefile.in generated by automake 1.14.1 from Makefile.am.
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -15,7 +15,17 @@
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@ -81,95 +91,120 @@ host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT) \
sptps_keypair$(EXEEXT) $(am__EXEEXT_1)
@LINUX_TRUE@am__append_1 = sptps_speed
@LINUX_TRUE@am__append_2 = linux/device.c
@BSD_TRUE@am__append_3 = bsd/device.c
@BSD_TRUE@@TUNEMU_TRUE@am__append_4 = bsd/tunemu.c bsd/tunemu.h
@SOLARIS_TRUE@am__append_5 = solaris/device.c
@MINGW_TRUE@am__append_6 = mingw/device.c mingw/common.h
@CYGWIN_TRUE@am__append_7 = cygwin/device.c
@UML_TRUE@am__append_8 = uml_device.c
@VDE_TRUE@am__append_9 = vde_device.c
@OPENSSL_TRUE@am__append_10 = \
@GETOPT_FALSE@am__append_2 = \
@GETOPT_FALSE@ getopt.c getopt.h \
@GETOPT_FALSE@ getopt1.c
@GETOPT_FALSE@am__append_3 = \
@GETOPT_FALSE@ getopt.c getopt.h \
@GETOPT_FALSE@ getopt1.c
@GETOPT_FALSE@am__append_4 = \
@GETOPT_FALSE@ getopt.c getopt.h \
@GETOPT_FALSE@ getopt1.c
@GETOPT_FALSE@am__append_5 = \
@GETOPT_FALSE@ getopt.c getopt.h \
@GETOPT_FALSE@ getopt1.c
@LINUX_TRUE@am__append_6 = linux/device.c
@BSD_TRUE@am__append_7 = bsd/device.c
@BSD_TRUE@@TUNEMU_TRUE@am__append_8 = bsd/tunemu.c bsd/tunemu.h
@SOLARIS_TRUE@am__append_9 = solaris/device.c
@MINGW_TRUE@am__append_10 = mingw/device.c mingw/common.h
@CYGWIN_TRUE@am__append_11 = cygwin/device.c
@UML_TRUE@am__append_12 = uml_device.c
@VDE_TRUE@am__append_13 = vde_device.c
@OPENSSL_TRUE@am__append_14 = \
@OPENSSL_TRUE@ openssl/cipher.c \
@OPENSSL_TRUE@ openssl/crypto.c \
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
@OPENSSL_TRUE@ ed25519/ecdh.c \
@OPENSSL_TRUE@ ed25519/ecdsa.c \
@OPENSSL_TRUE@ openssl/prf.c \
@OPENSSL_TRUE@ openssl/rsa.c
@OPENSSL_TRUE@am__append_11 = \
@OPENSSL_TRUE@am__append_15 = \
@OPENSSL_TRUE@ openssl/cipher.c \
@OPENSSL_TRUE@ openssl/crypto.c \
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
@OPENSSL_TRUE@ ed25519/ecdh.c \
@OPENSSL_TRUE@ ed25519/ecdsa.c \
@OPENSSL_TRUE@ ed25519/ecdsagen.c \
@OPENSSL_TRUE@ openssl/prf.c \
@OPENSSL_TRUE@ openssl/rsa.c \
@OPENSSL_TRUE@ openssl/rsagen.c
@OPENSSL_TRUE@am__append_12 = \
@OPENSSL_TRUE@am__append_16 = \
@OPENSSL_TRUE@ openssl/crypto.c \
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
@OPENSSL_TRUE@ ed25519/ecdh.c \
@OPENSSL_TRUE@ ed25519/ecdsa.c \
@OPENSSL_TRUE@ openssl/prf.c
@OPENSSL_TRUE@am__append_13 = \
@OPENSSL_TRUE@ openssl/crypto.c \
@OPENSSL_TRUE@ ed25519/ecdsagen.c
@OPENSSL_TRUE@am__append_17 = \
@OPENSSL_TRUE@ openssl/crypto.c
@OPENSSL_TRUE@am__append_14 = \
@OPENSSL_TRUE@am__append_18 = \
@OPENSSL_TRUE@ openssl/crypto.c \
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
@OPENSSL_TRUE@ ed25519/ecdh.c \
@OPENSSL_TRUE@ ed25519/ecdsa.c \
@OPENSSL_TRUE@ ed25519/ecdsagen.c \
@OPENSSL_TRUE@ openssl/prf.c
@GCRYPT_TRUE@am__append_15 = \
@GCRYPT_TRUE@ gcrypt/cipher.c \
@GCRYPT_TRUE@ gcrypt/crypto.c \
@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@ gcrypt/ecdh.c \
@GCRYPT_TRUE@ gcrypt/ecdsa.c \
@GCRYPT_TRUE@ gcrypt/prf.c \
@GCRYPT_TRUE@ gcrypt/rsa.c
@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_19 = \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.c
@GCRYPT_TRUE@am__append_16 = \
@GCRYPT_TRUE@ gcrypt/cipher.c \
@GCRYPT_TRUE@ gcrypt/crypto.c \
@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@ gcrypt/ecdh.c \
@GCRYPT_TRUE@ gcrypt/ecdsa.c \
@GCRYPT_TRUE@ gcrypt/ecdsagen.c \
@GCRYPT_TRUE@ gcrypt/prf.c \
@GCRYPT_TRUE@ gcrypt/rsa.c \
@GCRYPT_TRUE@ gcrypt/rsagen.c
@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_20 = \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsagen.c
@GCRYPT_TRUE@am__append_17 = \
@GCRYPT_TRUE@ gcrypt/cipher.c \
@GCRYPT_TRUE@ gcrypt/crypto.c \
@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@ gcrypt/ecdh.c \
@GCRYPT_TRUE@ gcrypt/ecdsa.c \
@GCRYPT_TRUE@ gcrypt/prf.c
@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_21 = \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/cipher.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.c gcrypt/digest.h \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.c
@TUNEMU_TRUE@am__append_18 = -lpcap
@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_22 = \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/crypto.c
@GCRYPT_TRUE@@OPENSSL_FALSE@am__append_23 = \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/crypto.c \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/digest.c openssl/digest.h \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/prf.c
@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_24 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c
@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_25 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c
@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_26 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c
@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_27 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c
@GCRYPT_FALSE@@OPENSSL_FALSE@am__append_28 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.c \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.c
@MINIUPNPC_TRUE@am__append_29 = upnp.h upnp.c
@TUNEMU_TRUE@am__append_30 = -lpcap
subdir = src
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_check_link_flag.m4 \
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.ac
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
@ -178,78 +213,91 @@ CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)"
PROGRAMS = $(sbin_PROGRAMS)
am__sptps_keypair_SOURCES_DIST = sptps_keypair.c utils.c utils.h \
ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \
ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \
ed25519/key_exchange.c ed25519/keypair.c \
ed25519/ecdsagen.c ed25519/add_scalar.c ed25519/ed25519.h \
ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \
ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \
ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
ed25519/verify.c openssl/crypto.c ed25519/ecdsagen.c
ed25519/verify.c getopt.c getopt.h getopt1.c openssl/crypto.c \
nolegacy/crypto.c
am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = ed25519/add_scalar.$(OBJEXT) ed25519/fe.$(OBJEXT) \
ed25519/ge.$(OBJEXT) ed25519/key_exchange.$(OBJEXT) \
ed25519/keypair.$(OBJEXT) ed25519/sc.$(OBJEXT) \
ed25519/sha512.$(OBJEXT) ed25519/sign.$(OBJEXT) \
ed25519/verify.$(OBJEXT)
@OPENSSL_TRUE@am__objects_2 = openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT)
@GETOPT_FALSE@am__objects_2 = getopt.$(OBJEXT) getopt1.$(OBJEXT)
@OPENSSL_TRUE@am__objects_3 = openssl/crypto.$(OBJEXT)
@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_4 = openssl/crypto.$(OBJEXT)
@GCRYPT_FALSE@@OPENSSL_FALSE@am__objects_5 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.$(OBJEXT)
am_sptps_keypair_OBJECTS = sptps_keypair.$(OBJEXT) utils.$(OBJEXT) \
$(am__objects_1) $(am__objects_2)
ed25519/ecdsagen.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
$(am__objects_3) $(am__objects_4) $(am__objects_5)
sptps_keypair_OBJECTS = $(am_sptps_keypair_OBJECTS)
sptps_keypair_LDADD = $(LDADD)
am__sptps_speed_SOURCES_DIST = logger.c logger.h sptps.c sptps.h \
sptps_speed.c utils.c utils.h ed25519/add_scalar.c \
ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \
ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \
ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \
ed25519/sc.h ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
sptps_speed.c utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \
ed25519/ecdsagen.c ed25519/add_scalar.c ed25519/ed25519.h \
ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \
ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \
ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
ed25519/verify.c chacha-poly1305/chacha.c \
chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \
chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \
chacha-poly1305/poly1305.h openssl/crypto.c openssl/digest.c \
openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c \
ed25519/ecdsagen.c openssl/prf.c
am__objects_3 = chacha-poly1305/chacha.$(OBJEXT) \
openssl/digest.h openssl/prf.c nolegacy/crypto.c \
nolegacy/prf.c
am__objects_6 = chacha-poly1305/chacha.$(OBJEXT) \
chacha-poly1305/chacha-poly1305.$(OBJEXT) \
chacha-poly1305/poly1305.$(OBJEXT)
@OPENSSL_TRUE@am__objects_4 = openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT) openssl/prf.$(OBJEXT)
@OPENSSL_TRUE@am__objects_7 = openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT)
@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_8 = openssl/crypto.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/digest.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ openssl/prf.$(OBJEXT)
@GCRYPT_FALSE@@OPENSSL_FALSE@am__objects_9 = \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/crypto.$(OBJEXT) \
@GCRYPT_FALSE@@OPENSSL_FALSE@ nolegacy/prf.$(OBJEXT)
am_sptps_speed_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \
sptps_speed.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
$(am__objects_3) $(am__objects_4)
sptps_speed.$(OBJEXT) utils.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
ed25519/ecdsa.$(OBJEXT) ed25519/ecdsagen.$(OBJEXT) \
$(am__objects_1) $(am__objects_6) $(am__objects_7) \
$(am__objects_8) $(am__objects_9)
sptps_speed_OBJECTS = $(am_sptps_speed_OBJECTS)
sptps_speed_DEPENDENCIES =
am__sptps_test_SOURCES_DIST = logger.c logger.h sptps.c sptps.h \
sptps_test.c utils.c utils.h ed25519/add_scalar.c \
ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \
ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \
ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \
ed25519/sc.h ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
sptps_test.c utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \
ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \
ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \
ed25519/key_exchange.c ed25519/keypair.c \
ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
ed25519/verify.c chacha-poly1305/chacha.c \
chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \
chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \
chacha-poly1305/poly1305.h openssl/crypto.c openssl/digest.c \
openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c openssl/prf.c \
gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \
gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c gcrypt/prf.c
@OPENSSL_TRUE@am__objects_5 = openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT)
@GCRYPT_TRUE@am__objects_6 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/prf.$(OBJEXT)
chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \
openssl/crypto.c openssl/digest.c openssl/digest.h \
openssl/prf.c gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \
gcrypt/digest.h gcrypt/prf.c nolegacy/crypto.c nolegacy/prf.c
@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_10 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT)
am_sptps_test_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \
sptps_test.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
$(am__objects_3) $(am__objects_5) $(am__objects_6)
sptps_test.$(OBJEXT) utils.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
ed25519/ecdsa.$(OBJEXT) $(am__objects_1) $(am__objects_6) \
$(am__objects_2) $(am__objects_7) $(am__objects_10) \
$(am__objects_9)
sptps_test_OBJECTS = $(am_sptps_test_OBJECTS)
sptps_test_LDADD = $(LDADD)
am__tinc_SOURCES_DIST = dropin.c dropin.h getopt.c getopt.h getopt1.c \
info.c info.h invitation.c invitation.h list.c list.h names.c \
names.h netutl.c netutl.h script.c script.h sptps.c sptps.h \
subnet_parse.c subnet.h tincctl.c tincctl.h top.c top.h \
utils.c utils.h version.c version.h ed25519/add_scalar.c \
am__tinc_SOURCES_DIST = dropin.c dropin.h fsck.c fsck.h ifconfig.c \
ifconfig.h info.c info.h invitation.c invitation.h list.c \
list.h names.c names.h netutl.c netutl.h script.c script.h \
sptps.c sptps.h subnet_parse.c subnet.h tincctl.c tincctl.h \
top.c top.h utils.c utils.h version.c version.h ed25519/ecdh.c \
ed25519/ecdsa.c ed25519/ecdsagen.c ed25519/add_scalar.c \
ed25519/ed25519.h ed25519/fe.c ed25519/fe.h ed25519/fixedint.h \
ed25519/ge.c ed25519/ge.h ed25519/key_exchange.c \
ed25519/keypair.c ed25519/precomp_data.h ed25519/sc.c \
@ -257,30 +305,31 @@ am__tinc_SOURCES_DIST = dropin.c dropin.h getopt.c getopt.h getopt1.c \
ed25519/verify.c chacha-poly1305/chacha.c \
chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \
chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \
chacha-poly1305/poly1305.h openssl/cipher.c openssl/crypto.c \
openssl/digest.c openssl/digest.h ed25519/ecdh.c \
ed25519/ecdsa.c ed25519/ecdsagen.c openssl/prf.c openssl/rsa.c \
openssl/rsagen.c gcrypt/cipher.c gcrypt/crypto.c \
gcrypt/digest.c gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c \
gcrypt/ecdsagen.c gcrypt/prf.c gcrypt/rsa.c gcrypt/rsagen.c
@OPENSSL_TRUE@am__objects_7 = openssl/cipher.$(OBJEXT) \
chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \
openssl/cipher.c openssl/crypto.c openssl/digest.c \
openssl/digest.h openssl/prf.c openssl/rsa.c openssl/rsagen.c \
gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \
gcrypt/digest.h gcrypt/prf.c gcrypt/rsa.c gcrypt/rsagen.c \
nolegacy/crypto.c nolegacy/prf.c
@OPENSSL_TRUE@am__objects_11 = openssl/cipher.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsagen.$(OBJEXT) openssl/prf.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/rsa.$(OBJEXT) openssl/rsagen.$(OBJEXT)
@GCRYPT_TRUE@am__objects_8 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/ecdsagen.$(OBJEXT) gcrypt/prf.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/rsa.$(OBJEXT) gcrypt/rsagen.$(OBJEXT)
am_tinc_OBJECTS = dropin.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_12 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsagen.$(OBJEXT)
am_tinc_OBJECTS = dropin.$(OBJEXT) fsck.$(OBJEXT) ifconfig.$(OBJEXT) \
info.$(OBJEXT) invitation.$(OBJEXT) list.$(OBJEXT) \
names.$(OBJEXT) netutl.$(OBJEXT) script.$(OBJEXT) \
sptps.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
top.$(OBJEXT) utils.$(OBJEXT) version.$(OBJEXT) \
$(am__objects_1) $(am__objects_3) $(am__objects_7) \
$(am__objects_8)
ed25519/ecdh.$(OBJEXT) ed25519/ecdsa.$(OBJEXT) \
ed25519/ecdsagen.$(OBJEXT) $(am__objects_1) $(am__objects_6) \
$(am__objects_2) $(am__objects_11) $(am__objects_12) \
$(am__objects_9)
tinc_OBJECTS = $(am_tinc_OBJECTS)
am__DEPENDENCIES_1 =
tinc_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@ -288,73 +337,74 @@ am__tincd_SOURCES_DIST = buffer.c buffer.h cipher.h conf.c conf.h \
connection.c connection.h control.c control.h control_common.h \
crypto.h device.h digest.h dropin.c dropin.h dummy_device.c \
ecdh.h ecdsa.h ecdsagen.h edge.c edge.h ethernet.h event.c \
event.h fake-gai-errnos.h fake-getaddrinfo.c \
fake-getaddrinfo.h fake-getnameinfo.c fake-getnameinfo.h \
getopt.c getopt.h getopt1.c graph.c graph.h hash.c hash.h \
have.h ipv4.h ipv6.h list.c list.h logger.c logger.h meta.c \
meta.h multicast_device.c names.c names.h net.c net.h \
net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
node.h prf.h process.c process.h protocol.c protocol.h \
protocol_auth.c protocol_edge.c protocol_key.c protocol_misc.c \
event.h graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h \
list.c list.h logger.c logger.h meta.c meta.h \
multicast_device.c names.c names.h net.c net.h net_packet.c \
net_setup.c net_socket.c netutl.c netutl.h node.c node.h prf.h \
process.c process.h protocol.c protocol.h protocol_auth.c \
protocol_edge.c protocol_key.c protocol_misc.c \
protocol_subnet.c raw_socket_device.c route.c route.h rsa.h \
rsagen.h script.c script.h splay_tree.c splay_tree.h sptps.c \
sptps.h subnet.c subnet.h subnet_parse.c system.h tincd.c \
utils.c utils.h xalloc.h version.c version.h \
ed25519/add_scalar.c ed25519/ed25519.h ed25519/fe.c \
ed25519/fe.h ed25519/fixedint.h ed25519/ge.c ed25519/ge.h \
ed25519/key_exchange.c ed25519/keypair.c \
utils.c utils.h xalloc.h version.c version.h ed25519/ecdh.c \
ed25519/ecdsa.c ed25519/add_scalar.c ed25519/ed25519.h \
ed25519/fe.c ed25519/fe.h ed25519/fixedint.h ed25519/ge.c \
ed25519/ge.h ed25519/key_exchange.c ed25519/keypair.c \
ed25519/precomp_data.h ed25519/sc.c ed25519/sc.h \
ed25519/sha512.c ed25519/sha512.h ed25519/sign.c \
ed25519/verify.c chacha-poly1305/chacha.c \
chacha-poly1305/chacha.h chacha-poly1305/chacha-poly1305.c \
chacha-poly1305/chacha-poly1305.h chacha-poly1305/poly1305.c \
chacha-poly1305/poly1305.h linux/device.c bsd/device.c \
bsd/tunemu.c bsd/tunemu.h solaris/device.c mingw/device.c \
mingw/common.h cygwin/device.c uml_device.c vde_device.c \
openssl/cipher.c openssl/crypto.c openssl/digest.c \
openssl/digest.h ed25519/ecdh.c ed25519/ecdsa.c openssl/prf.c \
openssl/rsa.c gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \
gcrypt/digest.h gcrypt/ecdh.c gcrypt/ecdsa.c gcrypt/prf.c \
gcrypt/rsa.c
@LINUX_TRUE@am__objects_9 = linux/device.$(OBJEXT)
@BSD_TRUE@am__objects_10 = bsd/device.$(OBJEXT)
@BSD_TRUE@@TUNEMU_TRUE@am__objects_11 = bsd/tunemu.$(OBJEXT)
@SOLARIS_TRUE@am__objects_12 = solaris/device.$(OBJEXT)
@MINGW_TRUE@am__objects_13 = mingw/device.$(OBJEXT)
@CYGWIN_TRUE@am__objects_14 = cygwin/device.$(OBJEXT)
@UML_TRUE@am__objects_15 = uml_device.$(OBJEXT)
@VDE_TRUE@am__objects_16 = vde_device.$(OBJEXT)
@OPENSSL_TRUE@am__objects_17 = openssl/cipher.$(OBJEXT) \
chacha-poly1305/poly1305.h getopt.c getopt.h getopt1.c \
linux/device.c bsd/device.c bsd/tunemu.c bsd/tunemu.h \
solaris/device.c mingw/device.c mingw/common.h cygwin/device.c \
uml_device.c vde_device.c openssl/cipher.c openssl/crypto.c \
openssl/digest.c openssl/digest.h openssl/prf.c openssl/rsa.c \
gcrypt/cipher.c gcrypt/crypto.c gcrypt/digest.c \
gcrypt/digest.h gcrypt/prf.c gcrypt/rsa.c nolegacy/crypto.c \
nolegacy/prf.c upnp.h upnp.c
@LINUX_TRUE@am__objects_13 = linux/device.$(OBJEXT)
@BSD_TRUE@am__objects_14 = bsd/device.$(OBJEXT)
@BSD_TRUE@@TUNEMU_TRUE@am__objects_15 = bsd/tunemu.$(OBJEXT)
@SOLARIS_TRUE@am__objects_16 = solaris/device.$(OBJEXT)
@MINGW_TRUE@am__objects_17 = mingw/device.$(OBJEXT)
@CYGWIN_TRUE@am__objects_18 = cygwin/device.$(OBJEXT)
@UML_TRUE@am__objects_19 = uml_device.$(OBJEXT)
@VDE_TRUE@am__objects_20 = vde_device.$(OBJEXT)
@OPENSSL_TRUE@am__objects_21 = openssl/cipher.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/prf.$(OBJEXT) \
@OPENSSL_TRUE@ openssl/rsa.$(OBJEXT)
@GCRYPT_TRUE@am__objects_18 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/crypto.$(OBJEXT) gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/ecdh.$(OBJEXT) gcrypt/ecdsa.$(OBJEXT) \
@GCRYPT_TRUE@ gcrypt/prf.$(OBJEXT) gcrypt/rsa.$(OBJEXT)
@GCRYPT_TRUE@@OPENSSL_FALSE@am__objects_22 = gcrypt/cipher.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/crypto.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/digest.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/prf.$(OBJEXT) \
@GCRYPT_TRUE@@OPENSSL_FALSE@ gcrypt/rsa.$(OBJEXT)
@MINIUPNPC_TRUE@am__objects_23 = upnp.$(OBJEXT)
am_tincd_OBJECTS = buffer.$(OBJEXT) conf.$(OBJEXT) \
connection.$(OBJEXT) control.$(OBJEXT) dropin.$(OBJEXT) \
dummy_device.$(OBJEXT) edge.$(OBJEXT) event.$(OBJEXT) \
fake-getaddrinfo.$(OBJEXT) fake-getnameinfo.$(OBJEXT) \
getopt.$(OBJEXT) getopt1.$(OBJEXT) graph.$(OBJEXT) \
hash.$(OBJEXT) list.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) \
multicast_device.$(OBJEXT) names.$(OBJEXT) net.$(OBJEXT) \
net_packet.$(OBJEXT) net_setup.$(OBJEXT) net_socket.$(OBJEXT) \
netutl.$(OBJEXT) node.$(OBJEXT) process.$(OBJEXT) \
protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
graph.$(OBJEXT) hash.$(OBJEXT) list.$(OBJEXT) logger.$(OBJEXT) \
meta.$(OBJEXT) multicast_device.$(OBJEXT) names.$(OBJEXT) \
net.$(OBJEXT) net_packet.$(OBJEXT) net_setup.$(OBJEXT) \
net_socket.$(OBJEXT) netutl.$(OBJEXT) node.$(OBJEXT) \
process.$(OBJEXT) protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
protocol_edge.$(OBJEXT) protocol_key.$(OBJEXT) \
protocol_misc.$(OBJEXT) protocol_subnet.$(OBJEXT) \
raw_socket_device.$(OBJEXT) route.$(OBJEXT) script.$(OBJEXT) \
splay_tree.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
subnet_parse.$(OBJEXT) tincd.$(OBJEXT) utils.$(OBJEXT) \
version.$(OBJEXT) $(am__objects_1) $(am__objects_3) \
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
$(am__objects_12) $(am__objects_13) $(am__objects_14) \
version.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
ed25519/ecdsa.$(OBJEXT) $(am__objects_1) $(am__objects_6) \
$(am__objects_2) $(am__objects_13) $(am__objects_14) \
$(am__objects_15) $(am__objects_16) $(am__objects_17) \
$(am__objects_18)
$(am__objects_18) $(am__objects_19) $(am__objects_20) \
$(am__objects_21) $(am__objects_22) $(am__objects_9) \
$(am__objects_23)
tincd_OBJECTS = $(am_tincd_OBJECTS)
tincd_LDADD = $(LDADD)
@MINIUPNPC_TRUE@tincd_DEPENDENCIES = $(am__DEPENDENCIES_1)
tincd_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(tincd_LDFLAGS) \
$(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@ -367,6 +417,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES =
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@ -411,6 +462,7 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@ -441,10 +493,11 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ $(am__append_18)
LIBS = @LIBS@ -lm $(am__append_30)
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MINIUPNPC_LIBS = @MINIUPNPC_LIBS@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
@ -502,15 +555,17 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
systemd_path = @systemd_path@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
DEFAULT_INCLUDES =
CLEANFILES = version_git.h
ed25519_SOURCES = \
ed25519/add_scalar.c \
ed25519/ed25519.h \
@ -534,39 +589,47 @@ tincd_SOURCES = buffer.c buffer.h cipher.h conf.c conf.h connection.c \
connection.h control.c control.h control_common.h crypto.h \
device.h digest.h dropin.c dropin.h dummy_device.c ecdh.h \
ecdsa.h ecdsagen.h edge.c edge.h ethernet.h event.c event.h \
fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \
fake-getnameinfo.c fake-getnameinfo.h getopt.c getopt.h \
getopt1.c graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h \
list.c list.h logger.c logger.h meta.c meta.h \
multicast_device.c names.c names.h net.c net.h net_packet.c \
net_setup.c net_socket.c netutl.c netutl.h node.c node.h prf.h \
process.c process.h protocol.c protocol.h protocol_auth.c \
graph.c graph.h hash.c hash.h have.h ipv4.h ipv6.h list.c \
list.h logger.c logger.h meta.c meta.h multicast_device.c \
names.c names.h net.c net.h net_packet.c net_setup.c \
net_socket.c netutl.c netutl.h node.c node.h prf.h process.c \
process.h protocol.c protocol.h protocol_auth.c \
protocol_edge.c protocol_key.c protocol_misc.c \
protocol_subnet.c raw_socket_device.c route.c route.h rsa.h \
rsagen.h script.c script.h splay_tree.c splay_tree.h sptps.c \
sptps.h subnet.c subnet.h subnet_parse.c system.h tincd.c \
utils.c utils.h xalloc.h version.c version.h \
$(ed25519_SOURCES) $(chacha_poly1305_SOURCES) $(am__append_2) \
$(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_6) $(am__append_7) $(am__append_8) \
$(am__append_9) $(am__append_10) $(am__append_15)
tinc_SOURCES = dropin.c dropin.h getopt.c getopt.h getopt1.c info.c \
info.h invitation.c invitation.h list.c list.h names.c names.h \
netutl.c netutl.h script.c script.h sptps.c sptps.h \
utils.c utils.h xalloc.h version.c version.h ed25519/ecdh.c \
ed25519/ecdsa.c $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \
$(am__append_2) $(am__append_6) $(am__append_7) \
$(am__append_8) $(am__append_9) $(am__append_10) \
$(am__append_11) $(am__append_12) $(am__append_13) \
$(am__append_14) $(am__append_19) $(am__append_24) \
$(am__append_29)
tinc_SOURCES = dropin.c dropin.h fsck.c fsck.h ifconfig.c ifconfig.h \
info.c info.h invitation.c invitation.h list.c list.h names.c \
names.h netutl.c netutl.h script.c script.h sptps.c sptps.h \
subnet_parse.c subnet.h tincctl.c tincctl.h top.c top.h \
utils.c utils.h version.c version.h $(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES) $(am__append_11) $(am__append_16)
utils.c utils.h version.c version.h ed25519/ecdh.c \
ed25519/ecdsa.c ed25519/ecdsagen.c $(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES) $(am__append_3) $(am__append_15) \
$(am__append_20) $(am__append_25)
sptps_test_SOURCES = logger.c logger.h sptps.c sptps.h sptps_test.c \
utils.c utils.h $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \
$(am__append_12) $(am__append_17)
utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \
$(ed25519_SOURCES) $(chacha_poly1305_SOURCES) $(am__append_4) \
$(am__append_16) $(am__append_21) $(am__append_26)
sptps_keypair_SOURCES = sptps_keypair.c utils.c utils.h \
$(ed25519_SOURCES) $(am__append_13)
ed25519/ecdsagen.c $(ed25519_SOURCES) $(am__append_5) \
$(am__append_17) $(am__append_22) $(am__append_27)
sptps_speed_SOURCES = logger.c logger.h sptps.c sptps.h sptps_speed.c \
utils.c utils.h $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \
$(am__append_14)
utils.c utils.h ed25519/ecdh.c ed25519/ecdsa.c \
ed25519/ecdsagen.c $(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES) $(am__append_18) $(am__append_23) \
$(am__append_28)
@MINIUPNPC_TRUE@tincd_LDADD = $(MINIUPNPC_LIBS)
@MINIUPNPC_TRUE@tincd_LDFLAGS = -pthread
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
sptps_speed_LDADD = -lrt
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote.
all: all-am
.SUFFIXES:
@ -583,7 +646,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@ -665,6 +727,8 @@ ed25519/$(am__dirstamp):
ed25519/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) ed25519/$(DEPDIR)
@: > ed25519/$(DEPDIR)/$(am__dirstamp)
ed25519/ecdsagen.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
ed25519/add_scalar.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
ed25519/fe.$(OBJEXT): ed25519/$(am__dirstamp) \
@ -691,12 +755,22 @@ openssl/$(DEPDIR)/$(am__dirstamp):
@: > openssl/$(DEPDIR)/$(am__dirstamp)
openssl/crypto.$(OBJEXT): openssl/$(am__dirstamp) \
openssl/$(DEPDIR)/$(am__dirstamp)
ed25519/ecdsagen.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
nolegacy/$(am__dirstamp):
@$(MKDIR_P) nolegacy
@: > nolegacy/$(am__dirstamp)
nolegacy/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) nolegacy/$(DEPDIR)
@: > nolegacy/$(DEPDIR)/$(am__dirstamp)
nolegacy/crypto.$(OBJEXT): nolegacy/$(am__dirstamp) \
nolegacy/$(DEPDIR)/$(am__dirstamp)
sptps_keypair$(EXEEXT): $(sptps_keypair_OBJECTS) $(sptps_keypair_DEPENDENCIES) $(EXTRA_sptps_keypair_DEPENDENCIES)
@rm -f sptps_keypair$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sptps_keypair_OBJECTS) $(sptps_keypair_LDADD) $(LIBS)
ed25519/ecdh.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
ed25519/ecdsa.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
chacha-poly1305/$(am__dirstamp):
@$(MKDIR_P) chacha-poly1305
@: > chacha-poly1305/$(am__dirstamp)
@ -712,12 +786,10 @@ chacha-poly1305/poly1305.$(OBJEXT): chacha-poly1305/$(am__dirstamp) \
chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
openssl/digest.$(OBJEXT): openssl/$(am__dirstamp) \
openssl/$(DEPDIR)/$(am__dirstamp)
ed25519/ecdh.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
ed25519/ecdsa.$(OBJEXT): ed25519/$(am__dirstamp) \
ed25519/$(DEPDIR)/$(am__dirstamp)
openssl/prf.$(OBJEXT): openssl/$(am__dirstamp) \
openssl/$(DEPDIR)/$(am__dirstamp)
nolegacy/prf.$(OBJEXT): nolegacy/$(am__dirstamp) \
nolegacy/$(DEPDIR)/$(am__dirstamp)
sptps_speed$(EXEEXT): $(sptps_speed_OBJECTS) $(sptps_speed_DEPENDENCIES) $(EXTRA_sptps_speed_DEPENDENCIES)
@rm -f sptps_speed$(EXEEXT)
@ -734,10 +806,6 @@ gcrypt/crypto.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/digest.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/ecdh.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/ecdsa.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/prf.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
@ -750,8 +818,6 @@ openssl/rsa.$(OBJEXT): openssl/$(am__dirstamp) \
openssl/$(DEPDIR)/$(am__dirstamp)
openssl/rsagen.$(OBJEXT): openssl/$(am__dirstamp) \
openssl/$(DEPDIR)/$(am__dirstamp)
gcrypt/ecdsagen.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/rsa.$(OBJEXT): gcrypt/$(am__dirstamp) \
gcrypt/$(DEPDIR)/$(am__dirstamp)
gcrypt/rsagen.$(OBJEXT): gcrypt/$(am__dirstamp) \
@ -805,7 +871,7 @@ cygwin/device.$(OBJEXT): cygwin/$(am__dirstamp) \
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
@rm -f tincd$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
$(AM_V_CCLD)$(tincd_LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -816,6 +882,7 @@ mostlyclean-compile:
-rm -f gcrypt/*.$(OBJEXT)
-rm -f linux/*.$(OBJEXT)
-rm -f mingw/*.$(OBJEXT)
-rm -f nolegacy/*.$(OBJEXT)
-rm -f openssl/*.$(OBJEXT)
-rm -f solaris/*.$(OBJEXT)
@ -830,12 +897,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edge.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getaddrinfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getnameinfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsck.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/graph.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifconfig.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invitation.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@ -870,6 +937,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/top.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upnp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
@ -894,14 +962,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/cipher.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/crypto.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/digest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdh.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdsa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/ecdsagen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/prf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/rsa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gcrypt/$(DEPDIR)/rsagen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@linux/$(DEPDIR)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@mingw/$(DEPDIR)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@nolegacy/$(DEPDIR)/crypto.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@nolegacy/$(DEPDIR)/prf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/cipher.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/crypto.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/digest.Po@am__quote@
@ -1037,6 +1104,7 @@ install-strip:
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@ -1055,6 +1123,8 @@ distclean-generic:
-rm -f linux/$(am__dirstamp)
-rm -f mingw/$(DEPDIR)/$(am__dirstamp)
-rm -f mingw/$(am__dirstamp)
-rm -f nolegacy/$(DEPDIR)/$(am__dirstamp)
-rm -f nolegacy/$(am__dirstamp)
-rm -f openssl/$(DEPDIR)/$(am__dirstamp)
-rm -f openssl/$(am__dirstamp)
-rm -f solaris/$(DEPDIR)/$(am__dirstamp)
@ -1068,7 +1138,7 @@ clean: clean-am
clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR)
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) nolegacy/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@ -1114,7 +1184,7 @@ install-ps-am:
installcheck-am: installcheck-sbinPROGRAMS
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR)
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) chacha-poly1305/$(DEPDIR) cygwin/$(DEPDIR) ed25519/$(DEPDIR) gcrypt/$(DEPDIR) linux/$(DEPDIR) mingw/$(DEPDIR) nolegacy/$(DEPDIR) openssl/$(DEPDIR) solaris/$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@ -1148,9 +1218,18 @@ uninstall-am: uninstall-sbinPROGRAMS
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-sbinPROGRAMS
.PRECIOUS: Makefile
.PHONY: version.c
version.c:
.PHONY: version-stamp
version-stamp:
version_git.h: version-stamp
$(AM_V_GEN)echo >$@
@-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||:
${srcdir}/version.c: version_git.h
@BSD_TRUE@version.c: ${srcdir}/version.c
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
This program is free software; you can redistribute it and/or modify
@ -34,13 +34,15 @@
#include "bsd/tunemu.h"
#endif
#define DEFAULT_TUN_DEVICE "/dev/tun0"
#if defined(HAVE_DARWIN) || defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
#define DEFAULT_TAP_DEVICE "/dev/tap0"
#else
#define DEFAULT_TAP_DEVICE "/dev/tun0"
#ifdef HAVE_NET_IF_UTUN_H
#include <sys/sys_domain.h>
#include <sys/kern_control.h>
#include <net/if_utun.h>
#endif
#define DEFAULT_TUN_DEVICE "/dev/tun0"
#define DEFAULT_TAP_DEVICE "/dev/tap0"
typedef enum device_type {
DEVICE_TYPE_TUN,
DEVICE_TYPE_TUNIFHEAD,
@ -48,6 +50,7 @@ typedef enum device_type {
#ifdef ENABLE_TUNEMU
DEVICE_TYPE_TUNEMU,
#endif
DEVICE_TYPE_UTUN,
} device_type_t;
int device_fd = -1;
@ -62,9 +65,64 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
static device_type_t device_type = DEVICE_TYPE_TUN;
#endif
#ifdef HAVE_NET_IF_UTUN_H
static bool setup_utun(void) {
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if(device_fd == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
return false;
}
struct ctl_info info = {};
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof info.ctl_name);
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
return false;
}
int unit = -1;
char *p = strstr(device, "utun"), *e = NULL;
if(p) {
unit = strtol(p + 4, &e, 10);
if(!e)
unit = -1;
}
struct sockaddr_ctl sc = {
.sc_id = info.ctl_id,
.sc_len = sizeof sc,
.sc_family = AF_SYSTEM,
.ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = unit + 1,
};
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
return false;
}
char name[64] = "";
socklen_t len = sizeof name;
if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) {
iface = xstrdup(device);
} else {
iface = xstrdup(name);
}
device_info = "OS X utun device";
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
}
#endif
static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
// Find out if it's supposed to be a tun or a tap device
char *type;
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "tun"))
@ -72,6 +130,10 @@ static bool setup_device(void) {
#ifdef ENABLE_TUNEMU
else if(!strcasecmp(type, "tunemu"))
device_type = DEVICE_TYPE_TUNEMU;
#endif
#ifdef HAVE_NET_IF_UTUN_H
else if(!strcasecmp(type, "utun"))
device_type = DEVICE_TYPE_UTUN;
#endif
else if(!strcasecmp(type, "tunnohead"))
device_type = DEVICE_TYPE_TUN;
@ -84,10 +146,22 @@ static bool setup_device(void) {
return false;
}
} else {
#ifdef HAVE_NET_IF_UTUN_H
if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0))
device_type = DEVICE_TYPE_UTUN;
else
#endif
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER)
device_type = DEVICE_TYPE_TAP;
}
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
logger(DEBUG_ALWAYS, LOG_ERR, "Only tap devices support switch mode!");
return false;
}
// Find out which device file to open
if(!device) {
if(device_type == DEVICE_TYPE_TAP)
device = xstrdup(DEFAULT_TAP_DEVICE);
@ -95,17 +169,7 @@ static bool setup_device(void) {
device = xstrdup(DEFAULT_TUN_DEVICE);
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = NULL;
#ifndef TAPGIFNAME
if (iface) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring specified interface name '%s' as device rename is not supported on this platform", iface);
free(iface);
iface = NULL;
}
#endif
if (!iface)
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
// Open the device
switch(device_type) {
#ifdef ENABLE_TUNEMU
@ -114,6 +178,10 @@ static bool setup_device(void) {
device_fd = tunemu_open(dynamic_name);
}
break;
#endif
#ifdef HAVE_NET_IF_UTUN_H
case DEVICE_TYPE_UTUN:
return setup_utun();
#endif
default:
device_fd = open(device, O_RDWR | O_NONBLOCK);
@ -128,6 +196,27 @@ static bool setup_device(void) {
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
#endif
// Guess what the corresponding interface is called
char *realname;
#if defined(HAVE_FDEVNAME)
realname = fdevname(device_fd) ? : device;
#elif defined(HAVE_DEVNAME)
struct stat buf;
if(!fstat(device_fd, &buf))
realname = devname(buf.st_rdev, S_IFCHR) ? : device;
#else
realname = device;
#endif
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname))
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
// Configure the device as best as we can
switch(device_type) {
default:
device_type = DEVICE_TYPE_TUN;
@ -192,6 +281,11 @@ static bool setup_device(void) {
#endif
}
#ifdef SIOCGIFADDR
if(overwrite_mac)
ioctl(device_fd, SIOCGIFADDR, mymac.x);
#endif
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
return true;
@ -253,31 +347,29 @@ static bool read_packet(vpn_packet_t *packet) {
packet->len = inlen + 14;
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}};
if((inlen = readv(device_fd, vector, 2)) <= 0) {
if((inlen = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
switch (ntohl(type)) {
case AF_INET:
switch (packet->data[14] >> 4) {
case 4:
DATA(packet)[12] = 0x08;
DATA(packet)[13] = 0x00;
break;
case AF_INET6:
case 6:
DATA(packet)[12] = 0x86;
DATA(packet)[13] = 0xDD;
break;
default:
logger(DEBUG_TRAFFIC, LOG_ERR,
"Unknown address family %x while reading packet from %s %s",
ntohl(type), device_info, device);
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
@ -319,12 +411,10 @@ static bool write_packet(vpn_packet_t *packet) {
}
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
u_int32_t type;
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}};
int af;
af = (DATA(packet)[12] << 8) + DATA(packet)[13];
int af = (DATA(packet)[12] << 8) + DATA(packet)[13];
uint32_t type;
switch (af) {
case 0x0800:
@ -340,7 +430,9 @@ static bool write_packet(vpn_packet_t *packet) {
return false;
}
if(writev(device_fd, vector, 2) < 0) {
memcpy(packet->data + 10, &type, sizeof type);
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;

View file

@ -24,6 +24,8 @@
#define CIPHER_MAX_IV_SIZE 16
#define CIPHER_MAX_KEY_SIZE 32
#ifndef DISABLE_LEGACY
typedef struct cipher cipher_t;
extern cipher_t *cipher_open_by_name(const char *) __attribute__ ((__malloc__));
@ -31,6 +33,7 @@ extern cipher_t *cipher_open_by_nid(int) __attribute__ ((__malloc__));
extern cipher_t *cipher_open_blowfish_ofb(void) __attribute__ ((__malloc__));
extern void cipher_close(cipher_t *);
extern size_t cipher_keylength(const cipher_t *);
extern size_t cipher_blocksize(const cipher_t *);
extern void cipher_get_key(const cipher_t *, void *);
extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__));
extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__));
@ -40,3 +43,5 @@ extern int cipher_get_nid(const cipher_t *);
extern bool cipher_active(const cipher_t *);
#endif
#endif

View file

@ -4,7 +4,7 @@
1998-2005 Ivo Timmermans
2000 Cris van Pelt
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2013 Florent Clairambault <florent@clairambault.fr>
This program is free software; you can redistribute it and/or modify
@ -298,7 +298,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname) {
fp = fopen(fname, "r");
if(!fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno));
return false;
}
@ -368,19 +368,19 @@ void read_config_options(splay_tree_t *config_tree, const char *prefix) {
}
bool read_server_config(void) {
char *fname;
char fname[PATH_MAX];
bool x;
read_config_options(config_tree, NULL);
xasprintf(&fname, "%s" SLASH "tinc.conf", confbase);
snprintf(fname, sizeof fname, "%s" SLASH "tinc.conf", confbase);
errno = 0;
x = read_config_file(config_tree, fname);
// We will try to read the conf files in the "conf.d" dir
if (x) {
char * dname;
xasprintf(&dname, "%s" SLASH "conf.d", confbase);
char dname[PATH_MAX];
snprintf(dname, sizeof dname, "%s" SLASH "conf.d", confbase);
DIR *dir = opendir (dname);
// If we can find this dir
if (dir) {
@ -390,51 +390,44 @@ bool read_server_config(void) {
size_t l = strlen(ep->d_name);
// And we try to read the ones that end with ".conf"
if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
free(fname);
xasprintf(&fname, "%s" SLASH "%s", dname, ep->d_name);
snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ep->d_name);
x = read_config_file(config_tree, fname);
}
}
closedir (dir);
}
free(dname);
}
if(!x && errno)
logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
free(fname);
return x;
}
bool read_host_config(splay_tree_t *config_tree, const char *name) {
char *fname;
char fname[PATH_MAX];
bool x;
read_config_options(config_tree, name);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
x = read_config_file(config_tree, fname);
free(fname);
return x;
}
bool append_config_file(const char *name, const char *key, const char *value) {
char *fname;
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
FILE *fp = fopen(fname, "a");
if(!fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
} else {
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
fclose(fp);
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno));
return false;
}
free(fname);
return fp != NULL;
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
fclose(fp);
return true;
}

View file

@ -21,8 +21,9 @@
#ifndef __TINC_CONF_H__
#define __TINC_CONF_H__
#include "splay_tree.h"
#include "list.h"
#include "splay_tree.h"
#include "subnet.h"
typedef struct config_t {
char *variable;
@ -31,7 +32,6 @@ typedef struct config_t {
int line;
} config_t;
#include "subnet.h"
extern splay_tree_t *config_tree;

View file

@ -55,14 +55,16 @@ void free_connection(connection_t *c) {
if(!c)
return;
#ifndef DISABLE_LEGACY
cipher_close(c->incipher);
digest_close(c->indigest);
cipher_close(c->outcipher);
digest_close(c->outdigest);
rsa_free(c->rsa);
#endif
sptps_stop(&c->sptps);
ecdsa_free(c->ecdsa);
rsa_free(c->rsa);
free(c->hischallenge);

View file

@ -59,9 +59,9 @@ typedef struct connection_status_t {
typedef struct connection_t {
char *name; /* name he claims to have */
char *hostname; /* the hostname of its real ip */
union sockaddr_t address; /* his real (internet) ip */
char *hostname; /* the hostname of its real ip */
int protocol_major; /* used protocol */
int protocol_minor; /* used protocol */
@ -75,12 +75,15 @@ typedef struct connection_t {
struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */
#ifndef DISABLE_LEGACY
rsa_t *rsa; /* his public RSA key */
ecdsa_t *ecdsa; /* his public ECDSA key */
cipher_t *incipher; /* Cipher he will use to send data to us */
cipher_t *outcipher; /* Cipher we will use to send data to him */
digest_t *indigest;
digest_t *outdigest;
#endif
ecdsa_t *ecdsa; /* his public ECDSA key */
sptps_t sptps;
int inmaclength;
@ -94,6 +97,7 @@ typedef struct connection_t {
struct buffer_t outbuf;
io_t io; /* input/output event on this metadata connection */
int tcplen; /* length of incoming TCPpacket */
int sptpslen; /* length of incoming SPTPS packet */
int allow_request; /* defined if there's only one request possible */
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */

View file

@ -19,6 +19,7 @@
*/
#include "../system.h"
#include "../net.h"
#include <w32api/windows.h>
#include <w32api/winioctl.h>
@ -27,7 +28,6 @@
#include "../device.h"
#include "../logger.h"
#include "../names.h"
#include "../net.h"
#include "../route.h"
#include "../utils.h"
#include "../xalloc.h"
@ -59,6 +59,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface)
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {

View file

@ -22,6 +22,8 @@
#define DIGEST_MAX_SIZE 64
#ifndef DISABLE_LEGACY
typedef struct digest digest_t;
extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__ ((__malloc__));
@ -37,3 +39,5 @@ extern size_t digest_length(const digest_t *);
extern bool digest_active(const digest_t *);
#endif
#endif

View file

@ -1,7 +1,7 @@
/*
dropin.c -- a set of drop-in replacements for libc functions
Copyright (C) 2000-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -86,40 +86,6 @@ int daemon(int nochdir, int noclose) {
}
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
/*
Replacement for the GNU get_current_dir_name function:
get_current_dir_name will malloc(3) an array big enough to hold the
current directory name. If the environment variable PWD is set, and
its value is correct, then that value will be returned.
*/
char *get_current_dir_name(void) {
size_t size;
char *buf;
char *r;
/* Start with 100 bytes. If this turns out to be insufficient to
contain the working directory, double the size. */
size = 100;
buf = xmalloc(size);
errno = 0; /* Success */
r = getcwd(buf, size);
/* getcwd returns NULL and sets errno to ERANGE if the bufferspace
is insufficient to contain the entire working directory. */
while(r == NULL && errno == ERANGE) {
free(buf);
size <<= 1; /* double the size */
buf = xmalloc(size);
r = getcwd(buf, size);
}
return buf;
}
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **buf, const char *fmt, ...) {
int result;
@ -174,10 +140,9 @@ int gettimeofday(struct timeval *tv, void *tz) {
}
#endif
#ifndef HAVE_USLEEP
int usleep(long long usec) {
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
select(0, NULL, NULL, NULL, &tv);
return 0;
#ifndef HAVE_NANOSLEEP
int nanosleep(const struct timespec *req, struct timespec *rem) {
struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
return select(0, NULL, NULL, NULL, &tv);
}
#endif

View file

@ -1,7 +1,7 @@
/*
dropin.h -- header file for dropin.c
Copyright (C) 2000-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,17 +21,10 @@
#ifndef __DROPIN_H__
#define __DROPIN_H__
#include "fake-getaddrinfo.h"
#include "fake-getnameinfo.h"
#ifndef HAVE_DAEMON
extern int daemon(int, int);
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
extern char *get_current_dir_name(void);
#endif
#ifndef HAVE_ASPRINTF
extern int asprintf(char **, const char *, ...);
extern int vasprintf(char **, const char *, va_list ap);
@ -41,8 +34,8 @@ extern int vasprintf(char **, const char *, va_list ap);
extern int gettimeofday(struct timeval *, void *);
#endif
#ifndef HAVE_USLEEP
extern int usleep(long long usec);
#ifndef HAVE_NANOSLEEP
extern int nanosleep(const struct timespec *req, struct timespec *rem);
#endif
#ifndef timeradd
@ -70,4 +63,8 @@ extern int usleep(long long usec);
#endif
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM 0
#endif
#endif /* __DROPIN_H__ */

View file

@ -84,11 +84,13 @@ static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) {
size_t len = b64decode(line, line, linelen);
if(!len) {
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n");
errno = EINVAL;
return false;
}
if(len > size) {
logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n");
errno = EINVAL;
return false;
}
@ -98,7 +100,12 @@ static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) {
}
if(size) {
logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n");
if(data) {
errno = EINVAL;
logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n");
} else {
errno = ENOENT;
}
return false;
}

View file

@ -8,9 +8,9 @@
static uint64_t load_3(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
result = in[0];
result |= shlu64(in[1], 8);
result |= shlu64(in[2], 16);
return result;
}
@ -18,10 +18,10 @@ static uint64_t load_3(const unsigned char *in) {
static uint64_t load_4(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
result |= ((uint64_t) in[3]) << 24;
result = in[0];
result |= shlu64(in[1], 8);
result |= shlu64(in[2], 16);
result |= shlu64(in[3], 24);
return result;
}
@ -316,47 +316,47 @@ void fe_frombytes(fe h, const unsigned char *s) {
int64_t carry8;
int64_t carry9;
carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
carry9 = (h9 + (1L << 24)) >> 25;
h0 += carry9 * 19;
h9 -= carry9 << 25;
carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
h9 -= shl64(carry9, 25);
carry1 = (h1 + (1L << 24)) >> 25;
h2 += carry1;
h1 -= carry1 << 25;
carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
h1 -= shl64(carry1, 25);
carry3 = (h3 + (1L << 24)) >> 25;
h4 += carry3;
h3 -= carry3 << 25;
carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
h3 -= shl64(carry3, 25);
carry5 = (h5 + (1L << 24)) >> 25;
h6 += carry5;
h5 -= carry5 << 25;
carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
h5 -= shl64(carry5, 25);
carry7 = (h7 + (1L << 24)) >> 25;
h8 += carry7;
h7 -= carry7 << 25;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
h7 -= shl64(carry7, 25);
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
h0 -= shl64(carry0, 26);
carry2 = (h2 + (1L << 25)) >> 26;
h3 += carry2;
h2 -= carry2 << 26;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h2 -= shl64(carry2, 26);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
h4 -= shl64(carry4, 26);
carry6 = (h6 + (1L << 25)) >> 26;
h7 += carry6;
h6 -= carry6 << 26;
carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
h6 -= shl64(carry6, 26);
carry8 = (h8 + (1L << 25)) >> 26;
h9 += carry8;
h8 -= carry8 << 26;
h8 -= shl64(carry8, 26);
h[0] = (int32_t) h0;
h[1] = (int32_t) h1;
h[2] = (int32_t) h2;
h[3] = (int32_t) h3;
h[4] = (int32_t) h4;
h[5] = (int32_t) h5;
h[6] = (int32_t) h6;
h[7] = (int32_t) h7;
h[8] = (int32_t) h8;
h[9] = (int32_t) h9;
h[0] = h0;
h[1] = h1;
h[2] = h2;
h[3] = h3;
h[4] = h4;
h[5] = h5;
h[6] = h6;
h[7] = h7;
h[8] = h8;
h[9] = h9;
}
@ -709,48 +709,48 @@ void fe_mul(fe h, const fe f, const fe g) {
int64_t carry8;
int64_t carry9;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h0 -= shl64(carry0, 26);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
h4 -= shl64(carry4, 26);
carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
carry1 = (h1 + (1L << 24)) >> 25;
h2 += carry1;
h1 -= carry1 << 25;
carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
h1 -= shl64(carry1, 25);
carry5 = (h5 + (1L << 24)) >> 25;
h6 += carry5;
h5 -= carry5 << 25;
h5 -= shl64(carry5, 25);
carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
carry2 = (h2 + (1L << 25)) >> 26;
h3 += carry2;
h2 -= carry2 << 26;
carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
h2 -= shl64(carry2, 26);
carry6 = (h6 + (1L << 25)) >> 26;
h7 += carry6;
h6 -= carry6 << 26;
h6 -= shl64(carry6, 26);
carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
carry3 = (h3 + (1L << 24)) >> 25;
h4 += carry3;
h3 -= carry3 << 25;
carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
h3 -= shl64(carry3, 25);
carry7 = (h7 + (1L << 24)) >> 25;
h8 += carry7;
h7 -= carry7 << 25;
h7 -= shl64(carry7, 25);
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
h4 -= shl64(carry4, 26);
carry8 = (h8 + (1L << 25)) >> 26;
h9 += carry8;
h8 -= carry8 << 26;
h8 -= shl64(carry8, 26);
carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
carry9 = (h9 + (1L << 24)) >> 25;
h0 += carry9 * 19;
h9 -= carry9 << 25;
h9 -= shl64(carry9, 25);
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
h0 -= shl64(carry0, 26);
h[0] = (int32_t) h0;
h[1] = (int32_t) h1;
@ -808,17 +808,17 @@ void fe_mul121666(fe h, fe f) {
int64_t carry8;
int64_t carry9;
carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= shl64(carry9, 25);
carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= shl64(carry1, 25);
carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= shl64(carry3, 25);
carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= shl64(carry5, 25);
carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= shl64(carry7, 25);
carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= shl64(carry0, 26);
carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= shl64(carry2, 26);
carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= shl64(carry4, 26);
carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= shl64(carry6, 26);
carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= shl64(carry8, 26);
h[0] = h0;
h[1] = h1;
@ -1078,42 +1078,42 @@ void fe_sq(fe h, const fe f) {
int64_t carry7;
int64_t carry8;
int64_t carry9;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h0 -= shl64(carry0, 26);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
h4 -= shl64(carry4, 26);
carry1 = (h1 + (1L << 24)) >> 25;
h2 += carry1;
h1 -= carry1 << 25;
carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
h1 -= shl64(carry1, 25);
carry5 = (h5 + (1L << 24)) >> 25;
h6 += carry5;
h5 -= carry5 << 25;
carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
h5 -= shl64(carry5, 25);
carry2 = (h2 + (1L << 25)) >> 26;
h3 += carry2;
h2 -= carry2 << 26;
carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
h2 -= shl64(carry2, 26);
carry6 = (h6 + (1L << 25)) >> 26;
h7 += carry6;
h6 -= carry6 << 26;
carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
h6 -= shl64(carry6, 26);
carry3 = (h3 + (1L << 24)) >> 25;
h4 += carry3;
h3 -= carry3 << 25;
carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
h3 -= shl64(carry3, 25);
carry7 = (h7 + (1L << 24)) >> 25;
h8 += carry7;
h7 -= carry7 << 25;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h7 -= shl64(carry7, 25);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
h4 -= shl64(carry4, 26);
carry8 = (h8 + (1L << 25)) >> 26;
h9 += carry8;
h8 -= carry8 << 26;
carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
h8 -= shl64(carry8, 26);
carry9 = (h9 + (1L << 24)) >> 25;
h0 += carry9 * 19;
h9 -= carry9 << 25;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
h9 -= shl64(carry9, 25);
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
h0 -= shl64(carry0, 26);
h[0] = (int32_t) h0;
h[1] = (int32_t) h1;
h[2] = (int32_t) h2;
@ -1251,42 +1251,42 @@ void fe_sq2(fe h, const fe f) {
h7 += h7;
h8 += h8;
h9 += h9;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h0 -= shl64(carry0, 26);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
h4 -= shl64(carry4, 26);
carry1 = (h1 + (1L << 24)) >> 25;
h2 += carry1;
h1 -= carry1 << 25;
carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
h1 -= shl64(carry1, 25);
carry5 = (h5 + (1L << 24)) >> 25;
h6 += carry5;
h5 -= carry5 << 25;
carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
h5 -= shl64(carry5, 25);
carry2 = (h2 + (1L << 25)) >> 26;
h3 += carry2;
h2 -= carry2 << 26;
carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
h2 -= shl64(carry2, 26);
carry6 = (h6 + (1L << 25)) >> 26;
h7 += carry6;
h6 -= carry6 << 26;
carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
h6 -= shl64(carry6, 26);
carry3 = (h3 + (1L << 24)) >> 25;
h4 += carry3;
h3 -= carry3 << 25;
carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
h3 -= shl64(carry3, 25);
carry7 = (h7 + (1L << 24)) >> 25;
h8 += carry7;
h7 -= carry7 << 25;
carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
h7 -= shl64(carry7, 25);
carry4 = (h4 + (1L << 25)) >> 26;
h5 += carry4;
h4 -= carry4 << 26;
carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
h4 -= shl64(carry4, 26);
carry8 = (h8 + (1L << 25)) >> 26;
h9 += carry8;
h8 -= carry8 << 26;
carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
h8 -= shl64(carry8, 26);
carry9 = (h9 + (1L << 24)) >> 25;
h0 += carry9 * 19;
h9 -= carry9 << 25;
carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
h9 -= shl64(carry9, 25);
carry0 = (h0 + (1L << 25)) >> 26;
h1 += carry0;
h0 -= carry0 << 26;
h0 -= shl64(carry0, 26);
h[0] = (int32_t) h0;
h[1] = (int32_t) h1;
h[2] = (int32_t) h2;
@ -1421,33 +1421,33 @@ void fe_tobytes(unsigned char *s, const fe h) {
/* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
carry0 = h0 >> 26;
h1 += carry0;
h0 -= carry0 << 26;
h0 -= shl32(carry0, 26);
carry1 = h1 >> 25;
h2 += carry1;
h1 -= carry1 << 25;
h1 -= shl32(carry1, 25);
carry2 = h2 >> 26;
h3 += carry2;
h2 -= carry2 << 26;
h2 -= shl32(carry2, 26);
carry3 = h3 >> 25;
h4 += carry3;
h3 -= carry3 << 25;
h3 -= shl32(carry3, 25);
carry4 = h4 >> 26;
h5 += carry4;
h4 -= carry4 << 26;
h4 -= shl32(carry4, 26);
carry5 = h5 >> 25;
h6 += carry5;
h5 -= carry5 << 25;
h5 -= shl32(carry5, 25);
carry6 = h6 >> 26;
h7 += carry6;
h6 -= carry6 << 26;
h6 -= shl32(carry6, 26);
carry7 = h7 >> 25;
h8 += carry7;
h7 -= carry7 << 25;
h7 -= shl32(carry7, 25);
carry8 = h8 >> 26;
h9 += carry8;
h8 -= carry8 << 26;
h8 -= shl32(carry8, 26);
carry9 = h9 >> 25;
h9 -= carry9 << 25;
h9 -= shl32(carry9, 25);
/* h10 = carry9 */
/*
@ -1459,32 +1459,32 @@ void fe_tobytes(unsigned char *s, const fe h) {
s[0] = (unsigned char) (h0 >> 0);
s[1] = (unsigned char) (h0 >> 8);
s[2] = (unsigned char) (h0 >> 16);
s[3] = (unsigned char) ((h0 >> 24) | (h1 << 2));
s[3] = (unsigned char) ((h0 >> 24) | shl32(h1, 2));
s[4] = (unsigned char) (h1 >> 6);
s[5] = (unsigned char) (h1 >> 14);
s[6] = (unsigned char) ((h1 >> 22) | (h2 << 3));
s[6] = (unsigned char) ((h1 >> 22) | shl32(h2, 3));
s[7] = (unsigned char) (h2 >> 5);
s[8] = (unsigned char) (h2 >> 13);
s[9] = (unsigned char) ((h2 >> 21) | (h3 << 5));
s[9] = (unsigned char) ((h2 >> 21) | shl32(h3, 5));
s[10] = (unsigned char) (h3 >> 3);
s[11] = (unsigned char) (h3 >> 11);
s[12] = (unsigned char) ((h3 >> 19) | (h4 << 6));
s[12] = (unsigned char) ((h3 >> 19) | shl32(h4, 6));
s[13] = (unsigned char) (h4 >> 2);
s[14] = (unsigned char) (h4 >> 10);
s[15] = (unsigned char) (h4 >> 18);
s[16] = (unsigned char) (h5 >> 0);
s[17] = (unsigned char) (h5 >> 8);
s[18] = (unsigned char) (h5 >> 16);
s[19] = (unsigned char) ((h5 >> 24) | (h6 << 1));
s[19] = (unsigned char) ((h5 >> 24) | shl32(h6, 1));
s[20] = (unsigned char) (h6 >> 7);
s[21] = (unsigned char) (h6 >> 15);
s[22] = (unsigned char) ((h6 >> 23) | (h7 << 3));
s[22] = (unsigned char) ((h6 >> 23) | shl32(h7, 3));
s[23] = (unsigned char) (h7 >> 5);
s[24] = (unsigned char) (h7 >> 13);
s[25] = (unsigned char) ((h7 >> 21) | (h8 << 4));
s[25] = (unsigned char) ((h7 >> 21) | shl32(h8, 4));
s[26] = (unsigned char) (h8 >> 4);
s[27] = (unsigned char) (h8 >> 12);
s[28] = (unsigned char) ((h8 >> 20) | (h9 << 6));
s[28] = (unsigned char) ((h8 >> 20) | shl32(h9, 6));
s[29] = (unsigned char) (h9 >> 2);
s[30] = (unsigned char) (h9 >> 10);
s[31] = (unsigned char) (h9 >> 18);

View file

@ -4,6 +4,9 @@
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
*/
#ifndef __TINC_FIXEDINT_H__
#define __TINC_FIXEDINT_H__
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
#include <stdint.h>
#define FIXEDINT_H_INCLUDED
@ -68,3 +71,21 @@
#define INT64_C(v) v ##I64
#endif
#endif
static inline unsigned char shlu8(unsigned char a, uint32_t b) {
return a << b;
}
static inline int32_t shl32(uint32_t a, uint32_t b) {
return a << b;
}
static inline int64_t shl64(uint64_t a, uint32_t b) {
return a << b;
}
static inline uint64_t shlu64(uint64_t a, uint32_t b) {
return a << b;
}
#endif

View file

@ -356,7 +356,7 @@ static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
static void select(ge_precomp *t, int pos, signed char b) {
ge_precomp minust;
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
unsigned char babs = b - shlu8(((-bnegative) & b), 1);
fe_1(t->yplusx);
fe_1(t->yminusx);
fe_0(t->xy2d);
@ -404,7 +404,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
e[i] -= shl32(carry, 4);
}
e[63] += carry;

View file

@ -1388,4 +1388,4 @@ static ge_precomp base[32][8] = {
{ -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 },
},
},
};
};

View file

@ -4,9 +4,9 @@
static uint64_t load_3(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
result = in[0];
result |= shlu64(in[1], 8);
result |= shlu64(in[2], 16);
return result;
}
@ -14,10 +14,10 @@ static uint64_t load_3(const unsigned char *in) {
static uint64_t load_4(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
result |= ((uint64_t) in[3]) << 24;
result = in[0];
result |= shlu64(in[1], 8);
result |= shlu64(in[2], 16);
result |= shlu64(in[3], 24);
return result;
}
@ -119,37 +119,37 @@ void sc_reduce(unsigned char *s) {
s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
s12 -= shl64(carry12, 21);
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
s14 -= shl64(carry14, 21);
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
s16 -= shl64(carry16, 21);
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
s13 -= shl64(carry13, 21);
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s15 -= shl64(carry15, 21);
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
@ -194,40 +194,40 @@ void sc_reduce(unsigned char *s) {
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
@ -237,40 +237,40 @@ void sc_reduce(unsigned char *s) {
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
@ -280,67 +280,67 @@ void sc_reduce(unsigned char *s) {
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
s[0] = (unsigned char) (s0 >> 0);
s[1] = (unsigned char) (s0 >> 8);
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5));
s[3] = (unsigned char) (s1 >> 3);
s[4] = (unsigned char) (s1 >> 11);
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2));
s[6] = (unsigned char) (s2 >> 6);
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7));
s[8] = (unsigned char) (s3 >> 1);
s[9] = (unsigned char) (s3 >> 9);
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4));
s[11] = (unsigned char) (s4 >> 4);
s[12] = (unsigned char) (s4 >> 12);
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1));
s[14] = (unsigned char) (s5 >> 7);
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6));
s[16] = (unsigned char) (s6 >> 2);
s[17] = (unsigned char) (s6 >> 10);
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3));
s[19] = (unsigned char) (s7 >> 5);
s[20] = (unsigned char) (s7 >> 13);
s[21] = (unsigned char) (s8 >> 0);
s[22] = (unsigned char) (s8 >> 8);
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5));
s[24] = (unsigned char) (s9 >> 3);
s[25] = (unsigned char) (s9 >> 11);
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2));
s[27] = (unsigned char) (s10 >> 6);
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7));
s[29] = (unsigned char) (s11 >> 1);
s[30] = (unsigned char) (s11 >> 9);
s[31] = (unsigned char) (s11 >> 17);
@ -470,73 +470,73 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
s23 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
s12 -= shl64(carry12, 21);
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
s14 -= shl64(carry14, 21);
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
s16 -= shl64(carry16, 21);
carry18 = (s18 + (1 << 20)) >> 21;
s19 += carry18;
s18 -= carry18 << 21;
s18 -= shl64(carry18, 21);
carry20 = (s20 + (1 << 20)) >> 21;
s21 += carry20;
s20 -= carry20 << 21;
s20 -= shl64(carry20, 21);
carry22 = (s22 + (1 << 20)) >> 21;
s23 += carry22;
s22 -= carry22 << 21;
s22 -= shl64(carry22, 21);
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
s13 -= shl64(carry13, 21);
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s15 -= shl64(carry15, 21);
carry17 = (s17 + (1 << 20)) >> 21;
s18 += carry17;
s17 -= carry17 << 21;
s17 -= shl64(carry17, 21);
carry19 = (s19 + (1 << 20)) >> 21;
s20 += carry19;
s19 -= carry19 << 21;
s19 -= shl64(carry19, 21);
carry21 = (s21 + (1 << 20)) >> 21;
s22 += carry21;
s21 -= carry21 << 21;
s21 -= shl64(carry21, 21);
s11 += s23 * 666643;
s12 += s23 * 470296;
s13 += s23 * 654183;
@ -581,37 +581,37 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
s12 -= shl64(carry12, 21);
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
s14 -= shl64(carry14, 21);
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
s16 -= shl64(carry16, 21);
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
s13 -= shl64(carry13, 21);
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s15 -= shl64(carry15, 21);
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
@ -656,40 +656,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
@ -699,40 +699,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s11 -= shl64(carry11, 21);
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
@ -742,67 +742,67 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
s0 -= shl64(carry0, 21);
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
s1 -= shl64(carry1, 21);
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
s2 -= shl64(carry2, 21);
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
s3 -= shl64(carry3, 21);
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
s4 -= shl64(carry4, 21);
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
s5 -= shl64(carry5, 21);
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
s6 -= shl64(carry6, 21);
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
s7 -= shl64(carry7, 21);
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
s8 -= shl64(carry8, 21);
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
s9 -= shl64(carry9, 21);
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s10 -= shl64(carry10, 21);
s[0] = (unsigned char) (s0 >> 0);
s[1] = (unsigned char) (s0 >> 8);
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5));
s[3] = (unsigned char) (s1 >> 3);
s[4] = (unsigned char) (s1 >> 11);
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2));
s[6] = (unsigned char) (s2 >> 6);
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7));
s[8] = (unsigned char) (s3 >> 1);
s[9] = (unsigned char) (s3 >> 9);
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4));
s[11] = (unsigned char) (s4 >> 4);
s[12] = (unsigned char) (s4 >> 12);
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1));
s[14] = (unsigned char) (s5 >> 7);
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6));
s[16] = (unsigned char) (s6 >> 2);
s[17] = (unsigned char) (s6 >> 10);
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3));
s[19] = (unsigned char) (s7 >> 5);
s[20] = (unsigned char) (s7 >> 13);
s[21] = (unsigned char) (s8 >> 0);
s[22] = (unsigned char) (s8 >> 8);
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5));
s[24] = (unsigned char) (s9 >> 3);
s[25] = (unsigned char) (s9 >> 11);
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2));
s[27] = (unsigned char) (s10 >> 6);
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7));
s[29] = (unsigned char) (s11 >> 1);
s[30] = (unsigned char) (s11 >> 9);
s[31] = (unsigned char) (s11 >> 17);

View file

@ -9,4 +9,4 @@ where l = 2^252 + 27742317777372353535851937790883648493.
void sc_reduce(unsigned char *s);
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
#endif
#endif

View file

@ -14,45 +14,45 @@
/* the K array */
static const uint64_t K[80] = {
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
};
@ -76,7 +76,7 @@ static const uint64_t K[80] = {
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
@ -88,7 +88,7 @@ static const uint64_t K[80] = {
#endif
/* compress 1024-bits */
static int sha512_compress(sha512_context *md, unsigned char *buf)
static int sha512_compress(sha512_context *md, const unsigned char *buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
@ -106,7 +106,7 @@ static int sha512_compress(sha512_context *md, unsigned char *buf)
/* fill W[16..79] */
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
}
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
@ -168,25 +168,26 @@ int sha512_init(sha512_context * md) {
@param inlen The length of the data (octets)
@return 0 if successful
*/
int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
{
int sha512_update(sha512_context *md, const void *vin, size_t inlen)
{
const unsigned char *in = vin;
size_t n;
size_t i;
int err;
if (md == NULL) return 1;
if (in == NULL) return 1;
if (md->curlen > sizeof(md->buf)) {
return 1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
return err;
}
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
size_t i;
int err;
if (md == NULL) return 1;
if (in == NULL) return 1;
if (md->curlen > sizeof(md->buf)) {
return 1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
if ((err = sha512_compress (md, in)) != 0) {
return err;
}
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
n = MIN(inlen, (128 - md->curlen));
for (i = 0; i < n; i++) {
@ -194,19 +195,19 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
}
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
if ((err = sha512_compress (md, md->buf)) != 0) {
return err;
}
md->length += 8*128;
md->curlen = 0;
}
}
}
return 0;
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
if ((err = sha512_compress (md, md->buf)) != 0) {
return err;
}
md->length += 8*128;
md->curlen = 0;
}
}
}
return 0;
}
/**
@ -215,22 +216,23 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
@param out [out] The destination of the hash (64 bytes)
@return 0 if successful
*/
int sha512_final(sha512_context * md, unsigned char *out)
{
int sha512_final(sha512_context * md, void *vout)
{
int i;
unsigned char *out = vout;
if (md == NULL) return 1;
if (out == NULL) return 1;
if (md->curlen >= sizeof(md->buf)) {
return 1;
}
return 1;
}
/* increase the length of the message */
md->length += md->curlen * UINT64_C(8);
md->length += md->curlen * UINT64_C(8);
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char)0x80;
md->buf[md->curlen++] = (unsigned char)0x80;
/* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
@ -244,27 +246,27 @@ int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
md->curlen = 0;
}
/* pad upto 120 bytes of zeroes
/* pad upto 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
* > 2^64 bits of data... :-)
*/
while (md->curlen < 120) {
md->buf[md->curlen++] = (unsigned char)0;
}
while (md->curlen < 120) {
md->buf[md->curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->length, md->buf+120);
sha512_compress(md, md->buf);
STORE64H(md->length, md->buf+120);
sha512_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
}
return 0;
}
return 0;
}
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
int sha512(const void *message, size_t message_len, void *out)
{
sha512_context ctx;
int ret;

View file

@ -14,8 +14,8 @@ typedef struct sha512_context_ {
int sha512_init(sha512_context * md);
int sha512_final(sha512_context * md, unsigned char *out);
int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
int sha512_final(sha512_context * md, void *out);
int sha512_update(sha512_context * md, const void *in, size_t inlen);
int sha512(const void *message, size_t message_len, void *out);
#endif
#endif

View file

@ -75,6 +75,7 @@ edge_t *new_edge(void) {
void free_edge(edge_t *e) {
sockaddrfree(&e->address);
sockaddrfree(&e->local_address);
free(e);
}

View file

@ -50,7 +50,7 @@ struct ether_header {
uint8_t ether_dhost[ETH_ALEN];
uint8_t ether_shost[ETH_ALEN];
uint16_t ether_type;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#endif
#ifndef HAVE_STRUCT_ARPHDR
@ -60,7 +60,7 @@ struct arphdr {
uint8_t ar_hln;
uint8_t ar_pln;
uint16_t ar_op;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#define ARPOP_REQUEST 1
#define ARPOP_REPLY 2
@ -78,7 +78,7 @@ struct ether_arp {
uint8_t arp_spa[4];
uint8_t arp_tha[ETH_ALEN];
uint8_t arp_tpa[4];
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#define arp_hrd ea_hdr.ar_hrd
#define arp_pro ea_hdr.ar_pro
#define arp_hln ea_hdr.ar_hln

View file

@ -285,6 +285,16 @@ bool event_loop(void) {
io->cb(io->data, IO_WRITE);
else if(FD_ISSET(io->fd, &readable))
io->cb(io->data, IO_READ);
else
continue;
/*
There are scenarios in which the callback will remove another io_t from the tree
(e.g. closing a double connection). Since splay_each does not support that, we
need to exit the loop now. That's okay, since any remaining events will get picked
up by the next select() call.
*/
break;
}
}
#else

View file

@ -1,23 +0,0 @@
/*
* fake library for ssh
*
* This file is included in getaddrinfo.c and getnameinfo.c.
* See getaddrinfo.c and getnameinfo.c.
*/
/* for old netdb.h */
#ifndef EAI_NODATA
#define EAI_NODATA 1
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY 2
#endif
#ifndef EAI_FAMILY
#define EAI_FAMILY 3
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM 4
#endif

View file

@ -1,102 +0,0 @@
/*
* fake library for ssh
*
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
* These funtions are defined in rfc2133.
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For exapmle, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include "system.h"
#include "ipv4.h"
#include "ipv6.h"
#include "fake-getaddrinfo.h"
#include "xalloc.h"
#if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode) {
switch (ecode) {
case EAI_NODATA:
return "No address associated with hostname";
case EAI_MEMORY:
return "Memory allocation failure";
case EAI_FAMILY:
return "Address family not supported";
default:
return "Unknown error";
}
}
#endif /* !HAVE_GAI_STRERROR */
#if !HAVE_DECL_FREEADDRINFO
void freeaddrinfo(struct addrinfo *ai) {
struct addrinfo *next;
while(ai) {
next = ai->ai_next;
free(ai);
ai = next;
}
}
#endif /* !HAVE_FREEADDRINFO */
#if !HAVE_DECL_GETADDRINFO
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
struct addrinfo *ai;
ai = xzalloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
ai->ai_addr = (struct sockaddr *)(ai + 1);
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
return ai;
}
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
struct addrinfo *prev = NULL;
struct hostent *hp;
struct in_addr in = {0};
int i;
uint16_t port = 0;
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)
return EAI_FAMILY;
if (servname)
port = htons(atoi(servname));
if (hints && hints->ai_flags & AI_PASSIVE) {
*res = malloc_ai(port, htonl(0x00000000));
return 0;
}
if (!hostname) {
*res = malloc_ai(port, htonl(0x7f000001));
return 0;
}
hp = gethostbyname(hostname);
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
return EAI_NODATA;
for (i = 0; hp->h_addr_list[i]; i++) {
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
if(prev)
prev->ai_next = *res;
prev = *res;
}
return 0;
}
#endif /* !HAVE_GETADDRINFO */

View file

@ -1,46 +0,0 @@
#ifndef _FAKE_GETADDRINFO_H
#define _FAKE_GETADDRINFO_H
#include "fake-gai-errnos.h"
#ifndef AI_PASSIVE
# define AI_PASSIVE 1
# define AI_CANONNAME 2
#endif
#ifndef NI_NUMERICHOST
# define NI_NUMERICHOST 2
# define NI_NAMEREQD 4
# define NI_NUMERICSERV 8
#endif
#ifndef AI_NUMERICHOST
#define AI_NUMERICHOST 4
#endif
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
#endif /* !HAVE_STRUCT_ADDRINFO */
#if !HAVE_DECL_GETADDRINFO
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
#endif /* !HAVE_GETADDRINFO */
#if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode);
#endif /* !HAVE_GAI_STRERROR */
#if !HAVE_DECL_FREEADDRINFO
void freeaddrinfo(struct addrinfo *ai);
#endif /* !HAVE_FREEADDRINFO */
#endif /* _FAKE_GETADDRINFO_H */

View file

@ -1,54 +0,0 @@
/*
* fake library for ssh
*
* This file includes getnameinfo().
* These funtions are defined in rfc2133.
*
* But these functions are not implemented correctly. The minimum subset
* is implemented for ssh use only. For exapmle, this routine assumes
* that ai_family is AF_INET. Don't use it for another purpose.
*/
#include "system.h"
#include "fake-getnameinfo.h"
#include "fake-getaddrinfo.h"
#if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct hostent *hp;
int len;
if(sa->sa_family != AF_INET)
return EAI_FAMILY;
if(serv && servlen) {
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
if(len < 0 || len >= servlen)
return EAI_MEMORY;
}
if(!host || !hostlen)
return 0;
if(flags & NI_NUMERICHOST) {
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
if(len < 0 || len >= hostlen)
return EAI_MEMORY;
return 0;
}
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
if(!hp || !hp->h_name || !hp->h_name[0])
return EAI_NODATA;
len = snprintf(host, hostlen, "%s", hp->h_name);
if(len < 0 || len >= hostlen)
return EAI_MEMORY;
return 0;
}
#endif /* !HAVE_GETNAMEINFO */

View file

@ -1,15 +0,0 @@
#ifndef _FAKE_GETNAMEINFO_H
#define _FAKE_GETNAMEINFO_H
#if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
#endif /* !HAVE_GETNAMEINFO */
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif /* !NI_MAXSERV */
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif /* !NI_MAXHOST */
#endif /* _FAKE_GETNAMEINFO_H */

498
src/fsck.c Normal file
View file

@ -0,0 +1,498 @@
/*
fsck.c -- Check the configuration files for problems
Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include "crypto.h"
#include "ecdsa.h"
#include "ecdsagen.h"
#include "fsck.h"
#include "names.h"
#ifndef DISABLE_LEGACY
#include "rsa.h"
#include "rsagen.h"
#endif
#include "tincctl.h"
#include "utils.h"
static bool ask_fix(void) {
if(force)
return true;
if(!tty)
return false;
again:
fprintf(stderr, "Fix y/n? ");
char buf[1024];
if(!fgets(buf, sizeof buf, stdin)) {
tty = false;
return false;
}
if(buf[0] == 'y' || buf[0] == 'Y')
return true;
if(buf[0] == 'n' || buf[0] == 'N')
return false;
goto again;
}
static void print_tinc_cmd(const char *argv0, const char *format, ...) {
if(confbasegiven)
fprintf(stderr, "%s -c %s ", argv0, confbase);
else if(netname)
fprintf(stderr, "%s -n %s ", argv0, netname);
else
fprintf(stderr, "%s ", argv0);
va_list va;
va_start(va, format);
vfprintf(stderr, format, va);
va_end(va);
fputc('\n', stderr);
}
static int strtailcmp(const char *str, const char *tail) {
size_t slen = strlen(str);
size_t tlen = strlen(tail);
if(tlen > slen)
return -1;
return memcmp(str + slen - tlen, tail, tlen);
}
static void check_conffile(const char *fname, bool server) {
FILE *f = fopen(fname, "r");
if(!f) {
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
return;
}
char line[2048];
int lineno = 0;
bool skip = false;
const int maxvariables = 50;
int count[maxvariables];
memset(count, 0, sizeof count);
while(fgets(line, sizeof line, f)) {
if(skip) {
if(!strncmp(line, "-----END", 8))
skip = false;
continue;
} else {
if(!strncmp(line, "-----BEGIN", 10)) {
skip = true;
continue;
}
}
int len;
char *variable, *value, *eol;
variable = value = line;
lineno++;
eol = line + strlen(line);
while(strchr("\t \r\n", *--eol))
*eol = '\0';
if(!line[0] || line[0] == '#')
continue;
len = strcspn(value, "\t =");
value += len;
value += strspn(value, "\t ");
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
variable[len] = '\0';
bool found = false;
for(int i = 0; variables[i].name; i++) {
if(strcasecmp(variables[i].name, variable))
continue;
found = true;
if(variables[i].type & VAR_OBSOLETE) {
fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n", variable, fname, lineno);
}
if(i < maxvariables)
count[i]++;
}
if(!found)
fprintf(stderr, "WARNING: unknown variable %s in %s line %d\n", variable, fname, lineno);
if(!*value)
fprintf(stderr, "ERROR: no value for variable %s in %s line %d\n", variable, fname, lineno);
}
for(int i = 0; variables[i].name && i < maxvariables; i++) {
if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE))
fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n", variables[i].name, fname);
}
if(ferror(f))
fprintf(stderr, "ERROR: while reading %s: %s\n", fname, strerror(errno));
fclose(f);
}
int fsck(const char *argv0) {
#ifdef HAVE_MINGW
int uid = 0;
#else
uid_t uid = getuid();
#endif
// Check that tinc.conf is readable.
if(access(tinc_conf, R_OK)) {
fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
if(errno == ENOENT) {
fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
print_tinc_cmd(argv0, "init");
} else if(errno == EACCES) {
if(uid != 0)
fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
else
fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
}
return 1;
}
char *name = get_my_name(true);
if(!name) {
fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
return 1;
}
// Check for private keys.
// TODO: use RSAPrivateKeyFile and Ed25519PrivateKeyFile variables if present.
struct stat st;
char fname[PATH_MAX];
char dname[PATH_MAX];
#ifndef DISABLE_LEGACY
rsa_t *rsa_priv = NULL;
snprintf(fname, sizeof fname, "%s/rsa_key.priv", confbase);
if(stat(fname, &st)) {
if(errno != ENOENT) {
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
fprintf(stderr, "Please correct this error.\n");
return 1;
}
} else {
FILE *f = fopen(fname, "r");
if(!f) {
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
return 1;
}
rsa_priv = rsa_read_pem_private_key(f);
fclose(f);
if(!rsa_priv) {
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
fprintf(stderr, "You can generate a new RSA key with:\n\n");
print_tinc_cmd(argv0, "generate-rsa-keys");
return 1;
}
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
if(st.st_mode & 077) {
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
if(st.st_uid != uid) {
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
} else if(ask_fix()) {
if(chmod(fname, st.st_mode & ~077))
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
else
fprintf(stderr, "Fixed permissions of %s.\n", fname);
}
}
#endif
}
#endif
ecdsa_t *ecdsa_priv = NULL;
snprintf(fname, sizeof fname, "%s/ed25519_key.priv", confbase);
if(stat(fname, &st)) {
if(errno != ENOENT) {
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
fprintf(stderr, "Please correct this error.\n");
return 1;
}
} else {
FILE *f = fopen(fname, "r");
if(!f) {
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
return 1;
}
ecdsa_priv = ecdsa_read_pem_private_key(f);
fclose(f);
if(!ecdsa_priv) {
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
fprintf(stderr, "You can generate a new Ed25519 key with:\n\n");
print_tinc_cmd(argv0, "generate-ed25519-keys");
return 1;
}
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
if(st.st_mode & 077) {
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
if(st.st_uid != uid) {
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
} else if(ask_fix()) {
if(chmod(fname, st.st_mode & ~077))
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
else
fprintf(stderr, "Fixed permissions of %s.\n", fname);
}
}
#endif
}
#ifdef DISABLE_LEGACY
if(!ecdsa_priv) {
fprintf(stderr, "ERROR: No Ed25519 private key found.\n");
#else
if(!rsa_priv && !ecdsa_priv) {
fprintf(stderr, "ERROR: Neither RSA or Ed25519 private key found.\n");
#endif
fprintf(stderr, "You can generate new keys with:\n\n");
print_tinc_cmd(argv0, "generate-keys");
return 1;
}
// Check for public keys.
// TODO: use RSAPublicKeyFile variable if present.
snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, name);
if(access(fname, R_OK))
fprintf(stderr, "WARNING: cannot read %s\n", fname);
FILE *f;
#ifndef DISABLE_LEGACY
rsa_t *rsa_pub = NULL;
f = fopen(fname, "r");
if(f)
rsa_pub = rsa_read_pem_public_key(f);
fclose(f);
if(rsa_priv) {
if(!rsa_pub) {
fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
if(ask_fix()) {
FILE *f = fopen(fname, "a");
if(f) {
if(rsa_write_pem_public_key(rsa_priv, f))
fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
else
fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
fclose(f);
} else {
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
}
}
} else {
// TODO: suggest remedies
size_t len = rsa_size(rsa_priv);
if(len != rsa_size(rsa_pub)) {
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
return 1;
}
char buf1[len], buf2[len], buf3[len];
randomize(buf1, sizeof buf1);
buf1[0] &= 0x7f;
memset(buf2, 0, sizeof buf2);
memset(buf3, 0, sizeof buf2);
if(!rsa_public_encrypt(rsa_pub, buf1, sizeof buf1, buf2)) {
fprintf(stderr, "ERROR: public RSA key does not work.\n");
return 1;
}
if(!rsa_private_decrypt(rsa_priv, buf2, sizeof buf2, buf3)) {
fprintf(stderr, "ERROR: private RSA key does not work.\n");
return 1;
}
if(memcmp(buf1, buf3, sizeof buf1)) {
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
return 1;
}
}
} else {
if(rsa_pub)
fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
}
#endif
ecdsa_t *ecdsa_pub = NULL;
f = fopen(fname, "r");
if(f) {
ecdsa_pub = get_pubkey(f);
if(!f) {
rewind(f);
ecdsa_pub = ecdsa_read_pem_public_key(f);
}
}
fclose(f);
if(ecdsa_priv) {
if(!ecdsa_pub) {
fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
if(ask_fix()) {
FILE *f = fopen(fname, "a");
if(f) {
if(ecdsa_write_pem_public_key(ecdsa_priv, f))
fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
else
fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
fclose(f);
} else {
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
}
}
} else {
// TODO: suggest remedies
char *key1 = ecdsa_get_base64_public_key(ecdsa_pub);
if(!key1) {
fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
return 1;
}
char *key2 = ecdsa_get_base64_public_key(ecdsa_priv);
if(!key2) {
free(key1);
fprintf(stderr, "ERROR: private Ed25519 key does not work.\n");
return 1;
}
int result = strcmp(key1, key2);
free(key1);
free(key2);
if(result) {
fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
return 1;
}
}
} else {
if(ecdsa_pub)
fprintf(stderr, "WARNING: A public Ed25519 key was found but no private key is known.\n");
}
// Check whether scripts are executable
struct dirent *ent;
DIR *dir = opendir(confbase);
if(!dir) {
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
return 1;
}
while((ent = readdir(dir))) {
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down"))
continue;
strncpy(fname, ent->d_name, sizeof fname);
char *dash = strrchr(fname, '-');
if(!dash)
continue;
*dash = 0;
if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
static bool explained = false;
fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
if(!explained) {
fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
explained = true;
}
continue;
}
snprintf(fname, sizeof fname, "%s" SLASH "%s", confbase, ent->d_name);
if(access(fname, R_OK | X_OK)) {
if(errno != EACCES) {
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
continue;
}
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
if(ask_fix()) {
if(chmod(fname, 0755))
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
}
}
}
closedir(dir);
snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase);
dir = opendir(dname);
if(!dir) {
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", dname, strerror(errno));
return 1;
}
while((ent = readdir(dir))) {
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down"))
continue;
strncpy(fname, ent->d_name, sizeof fname);
char *dash = strrchr(fname, '-');
if(!dash)
continue;
*dash = 0;
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
if(access(fname, R_OK | X_OK)) {
if(errno != EACCES) {
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
continue;
}
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
if(ask_fix()) {
if(chmod(fname, 0755))
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
}
}
}
closedir(dir);
// Check for obsolete / unsafe / unknown configuration variables.
check_conffile(tinc_conf, true);
dir = opendir(dname);
if(dir) {
while((ent = readdir(dir))) {
if(!check_id(ent->d_name))
continue;
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
check_conffile(fname, false);
}
closedir(dir);
}
return 0;
}

View file

@ -1,6 +1,6 @@
/*
ecdh.c -- Diffie-Hellman key exchange handling
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
fsck.h -- header for fsck.c.
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,21 +17,10 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#ifndef __TINC_FSCK_H__
#define __TINC_FSCK_H__
#include "../ecdh.h"
#include "../logger.h"
#include "../utils.h"
#include "../xalloc.h"
extern int fsck(const char *argv0);
ecdh_t *ecdh_generate_public(void *pubkey) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
#endif
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
return false
}
void ecdh_free(ecdh_t *ecdh) {
}

View file

@ -1,67 +0,0 @@
/*
ecdsa.c -- ECDSA key handling
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../logger.h"
#include "../ecdsa.h"
#include "../utils.h"
#include "../xalloc.h"
// Get and set ECDSA keys
//
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
return NULL;
}
// Read PEM ECDSA keys
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
size_t ecdsa_size(ecdsa_t *ecdsa) {
return 0;
}
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
return false;
}
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
return false;
}
bool ecdsa_active(ecdsa_t *ecdsa) {
return false;
}
void ecdsa_free(ecdsa_t *ecdsa) {
}

View file

@ -19,11 +19,88 @@
#include "../system.h"
#include "digest.h"
#include "../digest.h"
#include "../prf.h"
#include "../ed25519/sha512.h"
static void memxor(char *buf, char c, size_t len) {
for(size_t i = 0; i < len; i++)
buf[i] ^= c;
}
static const size_t mdlen = 64;
static const size_t blklen = 128;
static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) {
char tmp[blklen + mdlen];
sha512_context md;
if(keylen <= blklen) {
memcpy(tmp, key, keylen);
memset(tmp + keylen, 0, blklen - keylen);
} else {
if(sha512(key, keylen, tmp) != 0)
return false;
memset(tmp + mdlen, 0, blklen - mdlen);
}
if(sha512_init(&md) != 0)
return false;
// ipad
memxor(tmp, 0x36, blklen);
if(sha512_update(&md, tmp, blklen) != 0)
return false;
// message
if(sha512_update(&md, msg, msglen) != 0)
return false;
if(sha512_final(&md, tmp + blklen) != 0)
return false;
// opad
memxor(tmp, 0x36 ^ 0x5c, blklen);
if(sha512(tmp, sizeof tmp, out) != 0)
return false;
return true;
}
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
We use SHA512 instead of MD5 and SHA1.
*/
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
logger(DEBUG_ALWAYS, LOG_ERR, "PRF support using libgcrypt not implemented");
return false;
/* Data is what the "inner" HMAC function processes.
It consists of the previous HMAC result plus the seed.
*/
char data[mdlen + seedlen];
memset(data, 0, mdlen);
memcpy(data + mdlen, seed, seedlen);
char hash[mdlen];
while(outlen > 0) {
/* Inner HMAC */
if(!hmac_sha512(secret, secretlen, data, sizeof data, data))
return false;
/* Outer HMAC */
if(outlen >= mdlen) {
if(!hmac_sha512(secret, secretlen, data, sizeof data, out))
return false;
out += mdlen;
outlen -= mdlen;
} else {
if(!hmac_sha512(secret, secretlen, data, sizeof data, hash))
return false;
memcpy(out, hash, outlen);
out += outlen;
outlen = 0;
}
}
return true;
}

View file

@ -149,7 +149,7 @@ static void sssp_bfs(void) {
abort();
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
if(!e->reverse)
if(!e->reverse || e->to == myself)
continue;
/* Situation:
@ -238,10 +238,11 @@ static void check_reachability(void) {
n->status.udp_confirmed = false;
n->maxmtu = MTU;
n->maxrecentlen = 0;
n->minmtu = 0;
n->mtuprobes = 0;
timeout_del(&n->mtutimeout);
timeout_del(&n->udp_ping_timeout);
char *name;
char *address;
@ -275,6 +276,10 @@ static void check_reachability(void) {
update_node_udp(n, NULL);
memset(&n->status, 0, sizeof n->status);
n->options = 0;
} else if(n->connection) {
// Speed up UDP probing by sending our key.
if(!n->status.sptps)
send_ans_key(n);
}
}

View file

@ -29,7 +29,7 @@ static uint32_t hash_function(const void *p, size_t len) {
uint32_t hash = 0;
while(true) {
for(int i = len > 4 ? 4 : len; --i;)
hash += q[len - i] << (8 * i);
hash += (uint32_t)q[len - i] << (8 * i);
hash *= 0x9e370001UL; // Golden ratio prime.
if(len <= 4)
break;

View file

@ -1,7 +1,7 @@
/*
have.h -- include headers which are known to exist
Copyright (C) 1998-2005 Ivo Timmermans
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,17 +22,14 @@
#define __TINC_HAVE_H__
#ifdef HAVE_MINGW
#ifdef WITH_WINDOWS2000
#define WINVER Windows2000
#else
#define WINVER WindowsXP
#endif
#define WIN32_LEAN_AND_MEAN
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
@ -40,6 +37,8 @@
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#ifdef HAVE_MINGW
#include <w32api.h>
@ -48,10 +47,6 @@
#include <ws2tcpip.h>
#endif
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
@ -70,9 +65,6 @@
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -102,10 +94,6 @@
#include <sys/resource.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
@ -197,6 +185,28 @@
#include <netinet/if_ether.h>
#endif
#ifdef HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h>
#endif
#ifdef HAVE_RESOLV_H
#include <resolv.h>
#endif
#ifdef HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "getopt.h"
#endif
#ifdef STATUS
#undef STATUS
#endif
#ifdef HAVE_MINGW
#define SLASH "\\"
#else

198
src/ifconfig.c Normal file
View file

@ -0,0 +1,198 @@
/*
ifconfig.c -- Generate platform specific interface configuration commands
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include "conf.h"
#include "ifconfig.h"
#include "subnet.h"
static long start;
#ifndef HAVE_MINGW
void ifconfig_header(FILE *out) {
fprintf(out, "#!/bin/sh\n");
start = ftell(out);
}
void ifconfig_dhcp(FILE *out) {
fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
}
void ifconfig_dhcp6(FILE *out) {
fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
}
void ifconfig_slaac(FILE *out) {
#ifdef HAVE_LINUX
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
#else
fprintf(out, "rtsol \"$INTERFACE\" &\n");
#endif
}
bool ifconfig_footer(FILE *out) {
if(ftell(out) == start) {
fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
return false;
} else {
#ifdef HAVE_LINUX
fprintf(out, "ip link set \"$INTERFACE\" up\n");
#else
fprintf(out, "ifconfig \"$INTERFACE\" up\n");
#endif
return true;
}
}
#else
void ifconfig_header(FILE *out) {
start = ftell(out);
}
void ifconfig_dhcp(FILE *out) {
fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n");
}
void ifconfig_dhcp6(FILE *out) {
fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
}
void ifconfig_slaac(FILE *out) {
// It's the default?
}
bool ifconfig_footer(FILE *out) {
return ftell(out) != start;
}
#endif
static subnet_t ipv4, ipv6;
void ifconfig_address(FILE *out, const char *value) {
subnet_t address = {};
char address_str[MAXNETSTR];
if(!str2net(&address, value) || !net2str(address_str, sizeof address_str, &address)) {
fprintf(stderr, "Could not parse address in Ifconfig statement\n");
return;
}
switch(address.type) {
case SUBNET_IPV4: ipv4 = address; break;
case SUBNET_IPV6: ipv6 = address; break;
default: return;
}
#if defined(HAVE_LINUX)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
default: return;
}
#elif defined(HAVE_BSD)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str); break;
default: return;
}
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
switch(address.type) {
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", address_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", address_str); break;
default: return;
}
#endif
}
void ifconfig_route(FILE *out, const char *value) {
subnet_t subnet = {}, gateway = {};
char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
char *sep = strchr(value, ' ');
if(sep)
*sep++ = 0;
if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof subnet_str, &subnet) || subnet.type == SUBNET_MAC) {
fprintf(stderr, "Could not parse subnet in Route statement\n");
return;
}
if(sep) {
if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof gateway_str, &gateway) || gateway.type != subnet.type) {
fprintf(stderr, "Could not parse gateway in Route statement\n");
return;
}
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
}
#if defined(HAVE_LINUX)
if(*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
default: return;
}
} else {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
case SUBNET_IPV6: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
default: return;
}
}
#elif defined(HAVE_BSD)
// BSD route command is silly and doesn't accept an interface name as a destination.
if(!*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4:
if(!ipv4.type) {
fprintf(stderr, "Route requested but no Ifconfig\n");
return;
}
net2str(gateway_str, sizeof gateway_str, &ipv4);
break;
case SUBNET_IPV6:
if(!ipv6.type) {
fprintf(stderr, "Route requested but no Ifconfig\n");
return;
}
net2str(gateway_str, sizeof gateway_str, &ipv6);
break;
default: return;
}
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
}
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "route add %s %s\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str); break;
default: return;
}
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
if(*gateway_str) {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
default: return;
}
} else {
switch(subnet.type) {
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
default: return;
}
}
#endif
}

31
src/ifconfig.h Normal file
View file

@ -0,0 +1,31 @@
/*
ifconfig.h -- header for ifconfig.c.
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_IFCONFIG_H__
#define __TINC_IFCONFIG_H__
extern void ifconfig_dhcp(FILE *out);
extern void ifconfig_dhcp6(FILE *out);
extern void ifconfig_slaac(FILE *out);
extern void ifconfig_address(FILE *out, const char *value);
extern void ifconfig_route(FILE *out, const char *value);
extern void ifconfig_header(FILE *out);
extern bool ifconfig_footer(FILE *out);
#endif

View file

@ -1,6 +1,6 @@
/*
invitation.c -- Create and accept invitations
Copyright (C) 2013-2014 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2013-2015 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
@ -23,16 +23,20 @@
#include "crypto.h"
#include "ecdsa.h"
#include "ecdsagen.h"
#include "ifconfig.h"
#include "invitation.h"
#include "names.h"
#include "netutl.h"
#include "rsagen.h"
#include "script.h"
#include "sptps.h"
#include "subnet.h"
#include "tincctl.h"
#include "utils.h"
#include "xalloc.h"
#include "ed25519/sha512.h"
int addressfamily = AF_UNSPEC;
static void scan_for_hostname(const char *filename, char **hostname, char **port) {
@ -82,11 +86,11 @@ char *get_my_hostname() {
char *port = NULL;
char *hostport = NULL;
char *name = get_my_name(false);
char *filename = NULL;
char filename[PATH_MAX] = {0};
// Use first Address statement in own host config file
if(check_id(name)) {
xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
scan_for_hostname(filename, &hostname, &port);
scan_for_hostname(tinc_conf, &hostname, &port);
}
@ -180,7 +184,7 @@ again:
hostname = xstrdup(line);
save:
if(filename) {
if(*filename) {
FILE *f = fopen(filename, "a");
if(f) {
fprintf(f, "\nAddress = %s\n", hostname);
@ -205,7 +209,6 @@ done:
free(hostname);
free(port);
free(filename);
return hostport;
}
@ -241,14 +244,12 @@ int cmd_invite(int argc, char *argv[]) {
return 1;
// Ensure no host configuration file with that name exists
char *filename = NULL;
xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]);
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]);
if(!access(filename, F_OK)) {
free(filename);
fprintf(stderr, "A host config file for %s already exists!\n", argv[1]);
return 1;
}
free(filename);
// If a daemon is running, ensure no other nodes know about this name
bool found = false;
@ -270,12 +271,9 @@ int cmd_invite(int argc, char *argv[]) {
}
}
char hash[25];
xasprintf(&filename, "%s" SLASH "invitations", confbase);
snprintf(filename, sizeof filename, "%s" SLASH "invitations", confbase);
if(mkdir(filename, 0700) && errno != EEXIST) {
fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno));
free(filename);
return 1;
}
@ -283,7 +281,6 @@ int cmd_invite(int argc, char *argv[]) {
DIR *dir = opendir(filename);
if(!dir) {
fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno));
free(filename);
return 1;
}
@ -295,9 +292,9 @@ int cmd_invite(int argc, char *argv[]) {
while((ent = readdir(dir))) {
if(strlen(ent->d_name) != 24)
continue;
char *invname;
char invname[PATH_MAX];
struct stat st;
xasprintf(&invname, "%s" SLASH "%s", filename, ent->d_name);
snprintf(invname, sizeof invname, "%s" SLASH "%s", filename, ent->d_name);
if(!stat(invname, &st)) {
if(deadline < st.st_mtime)
count++;
@ -307,21 +304,17 @@ int cmd_invite(int argc, char *argv[]) {
fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno));
errno = 0;
}
free(invname);
}
closedir(dir);
if(errno) {
fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno));
closedir(dir);
free(filename);
return 1;
}
closedir(dir);
free(filename);
ecdsa_t *key;
xasprintf(&filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
// Remove the key if there are no outstanding invitations.
if(!count)
@ -332,23 +325,23 @@ int cmd_invite(int argc, char *argv[]) {
if(!f) {
if(errno != ENOENT) {
fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno));
free(filename);
return 1;
}
key = ecdsa_generate();
if(!key) {
free(filename);
if(!key)
return 1;
}
f = fopen(filename, "w");
if(!f) {
fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno));
free(filename);
return 1;
}
chmod(filename, 0600);
ecdsa_write_pem_private_key(key, f);
if(!ecdsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Could not write ECDSA private key\n");
fclose(f);
return 1;
}
fclose(f);
if(connect_tincd(false))
@ -360,16 +353,13 @@ int cmd_invite(int argc, char *argv[]) {
fprintf(stderr, "Could not read private key from %s\n", filename);
}
free(filename);
if(!key)
return 1;
// Create a hash of the key.
char hash[64];
char *fingerprint = ecdsa_get_base64_public_key(key);
digest_t *digest = digest_open_by_name("sha256", 18);
if(!digest)
abort();
digest_create(digest, fingerprint, strlen(fingerprint), hash);
sha512(fingerprint, strlen(fingerprint), hash);
b64encode_urlsafe(hash, hash, 18);
// Create a random cookie for this invitation.
@ -378,20 +368,19 @@ int cmd_invite(int argc, char *argv[]) {
// Create a filename that doesn't reveal the cookie itself
char buf[18 + strlen(fingerprint)];
char cookiehash[25];
char cookiehash[64];
memcpy(buf, cookie, 18);
memcpy(buf + 18, fingerprint, sizeof buf - 18);
digest_create(digest, buf, sizeof buf, cookiehash);
sha512(buf, sizeof buf, cookiehash);
b64encode_urlsafe(cookiehash, cookiehash, 18);
b64encode_urlsafe(cookie, cookie, 18);
// Create a file containing the details of the invitation.
xasprintf(&filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash);
snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash);
int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
if(!ifd) {
fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno));
free(filename);
return 1;
}
f = fdopen(ifd, "w");
@ -403,7 +392,7 @@ int cmd_invite(int argc, char *argv[]) {
// Fill in the details.
fprintf(f, "Name = %s\n", argv[1]);
if(netname)
if(check_netname(netname, true))
fprintf(f, "NetName = %s\n", netname);
fprintf(f, "ConnectTo = %s\n", myname);
@ -426,11 +415,10 @@ int cmd_invite(int argc, char *argv[]) {
fprintf(f, "#---------------------------------------------------------------#\n");
fprintf(f, "Name = %s\n", myname);
char *filename2;
xasprintf(&filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname);
char filename2[PATH_MAX];
snprintf(filename2, sizeof filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname);
fcopy(f, filename2);
fclose(f);
free(filename2);
// Create an URL from the local address, key hash and cookie
char *url;
@ -449,7 +437,6 @@ int cmd_invite(int argc, char *argv[]) {
puts(url);
free(url);
free(filename);
free(address);
return 0;
@ -554,12 +541,17 @@ static bool finalize_join(void) {
}
if(!check_id(name)) {
fprintf(stderr, "Invalid Name found in invitation: %s!\n", name);
fprintf(stderr, "Invalid Name found in invitation!\n");
return false;
}
if(!netname)
if(!netname) {
netname = grep(data, "NetName");
if(netname && !check_netname(netname, true)) {
fprintf(stderr, "Unsafe NetName found in invitation!\n");
return false;
}
}
bool ask_netname = false;
char temp_netname[32];
@ -570,7 +562,7 @@ make_names:
confbase = NULL;
}
make_names();
make_names(false);
free(tinc_conf);
free(hosts_dir);
@ -608,8 +600,8 @@ make_names:
fprintf(f, "Name = %s\n", name);
char *filename;
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name);
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
FILE *fh = fopen(filename, "w");
if(!fh) {
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
@ -617,7 +609,19 @@ make_names:
return false;
}
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
FILE *fup = fopen(filename, "w");
if(!fup) {
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
fclose(f);
fclose(fh);
return false;
}
ifconfig_header(fup);
// Filter first chunk on approved keywords, split between tinc.conf and hosts/Name
// Generate a tinc-up script from Ifconfig and Route keywords.
// Other chunks go unfiltered to their respective host config files
const char *p = data;
char *l, *value;
@ -656,6 +660,24 @@ make_names:
break;
}
// Handle Ifconfig and Route statements
if(!found) {
if(!strcasecmp(l, "Ifconfig")) {
if(!strcasecmp(value, "dhcp"))
ifconfig_dhcp(fup);
else if(!strcasecmp(value, "dhcp6"))
ifconfig_dhcp6(fup);
else if(!strcasecmp(value, "slaac"))
ifconfig_slaac(fup);
else
ifconfig_address(fup, value);
continue;
} else if(!strcasecmp(l, "Route")) {
ifconfig_route(fup, value);
continue;
}
}
// Ignore unknown and unsafe variables
if(!found) {
fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l);
@ -670,7 +692,8 @@ make_names:
}
fclose(f);
free(filename);
bool valid_tinc_up = ifconfig_footer(fup);
fclose(fup);
while(l && !strcasecmp(l, "Name")) {
if(!check_id(value)) {
@ -683,7 +706,7 @@ make_names:
return false;
}
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, value);
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, value);
f = fopen(filename, "w");
if(!f) {
@ -711,7 +734,6 @@ make_names:
}
fclose(f);
free(filename);
}
// Generate our key and send a copy to the server
@ -723,8 +745,10 @@ make_names:
if(!b64key)
return false;
xasprintf(&filename, "%s" SLASH "ed25519_key.priv", confbase);
snprintf(filename, sizeof filename, "%s" SLASH "ed25519_key.priv", confbase);
f = fopenmask(filename, "w", 0600);
if(!f)
return false;
if(!ecdsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Error writing private key!\n");
@ -739,20 +763,25 @@ make_names:
sptps_send_record(&sptps, 1, b64key, strlen(b64key));
free(b64key);
ecdsa_free(key);
#ifndef DISABLE_LEGACY
rsa_t *rsa = rsa_generate(2048, 0x1001);
xasprintf(&filename, "%s" SLASH "rsa_key.priv", confbase);
snprintf(filename, sizeof filename, "%s" SLASH "rsa_key.priv", confbase);
f = fopenmask(filename, "w", 0600);
rsa_write_pem_private_key(rsa, f);
if(!f || !rsa_write_pem_private_key(rsa, f)) {
fprintf(stderr, "Could not write private RSA key\n");
} else if(!rsa_write_pem_public_key(rsa, fh)) {
fprintf(stderr, "Could not write public RSA key\n");
}
fclose(f);
rsa_write_pem_public_key(rsa, fh);
fclose(fh);
ecdsa_free(key);
rsa_free(rsa);
#endif
check_port(name);
@ -768,17 +797,69 @@ ask_netname:
line[strlen(line) - 1] = 0;
char *newbase;
xasprintf(&newbase, CONFDIR SLASH "tinc" SLASH "%s", line);
char newbase[PATH_MAX];
snprintf(newbase, sizeof newbase, CONFDIR SLASH "tinc" SLASH "%s", line);
if(rename(confbase, newbase)) {
fprintf(stderr, "Error trying to rename %s to %s: %s\n", confbase, newbase, strerror(errno));
free(newbase);
goto ask_netname;
}
free(newbase);
netname = line;
make_names();
make_names(false);
}
char filename2[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
snprintf(filename2, sizeof filename2, "%s" SLASH "tinc-up", confbase);
if(valid_tinc_up) {
if(tty) {
FILE *fup = fopen(filename, "r");
if(fup) {
fprintf(stderr, "\nPlease review the following tinc-up script:\n\n");
char buf[MAXSIZE];
while(fgets(buf, sizeof buf, fup))
fputs(buf, stderr);
fclose(fup);
int response = 0;
do {
fprintf(stderr, "\nDo you want to use this script [y]es/[n]o/[e]dit? ");
response = tolower(getchar());
} while(!strchr("yne", response));
fprintf(stderr, "\n");
if(response == 'e') {
char *command;
#ifndef HAVE_MINGW
xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
#else
xasprintf(&command, "edit \"%s\"", filename);
#endif
if(system(command))
response = 'n';
else
response = 'y';
free(command);
}
if(response == 'y') {
rename(filename, filename2);
chmod(filename2, 0755);
fprintf(stderr, "tinc-up enabled.\n");
} else {
fprintf(stderr, "tinc-up has been left disabled.\n");
}
}
} else {
fprintf(stderr, "A tinc-up script was generated, but has been left disabled.\n");
}
} else {
// A placeholder was generated.
rename(filename, filename2);
chmod(filename2, 0755);
}
fprintf(stderr, "Configuration stored in: %s\n", confbase);
@ -922,16 +1003,31 @@ int cmd_join(int argc, char *argv[]) {
if(!ai)
return 1;
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sock <= 0) {
fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
return 1;
struct addrinfo *aip = NULL;
next:
if(!aip)
aip = ai;
else {
aip = aip->ai_next;
if(!aip)
return 1;
}
if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
fprintf(stderr, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
if(sock <= 0) {
fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
goto next;
}
if(connect(sock, aip->ai_addr, aip->ai_addrlen)) {
char *addrstr, *portstr;
sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr);
fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno));
free(addrstr);
free(portstr);
closesocket(sock);
return 1;
goto next;
}
fprintf(stderr, "Connected to %s port %s...\n", address, port);
@ -944,7 +1040,7 @@ int cmd_join(int argc, char *argv[]) {
if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
closesocket(sock);
return 1;
goto next;
}
char hisname[4096] = "";
@ -953,16 +1049,13 @@ int cmd_join(int argc, char *argv[]) {
if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) {
fprintf(stderr, "Cannot read greeting from peer\n");
closesocket(sock);
return 1;
goto next;
}
// Check if the hash of the key he gave us matches the hash in the URL.
char *fingerprint = line + 2;
digest_t *digest = digest_open_by_name("sha256", 18);
if(!digest)
abort();
char hishash[18];
if(!digest_create(digest, fingerprint, strlen(fingerprint), hishash)) {
char hishash[64];
if(sha512(fingerprint, strlen(fingerprint), hishash)) {
fprintf(stderr, "Could not create digest\n%s\n", line + 2);
return 1;
}
@ -992,8 +1085,14 @@ int cmd_join(int argc, char *argv[]) {
return 1;
}
if(!sptps_receive_data(&sptps, line, len))
return 1;
char *p = line;
while(len) {
int done = sptps_receive_data(&sptps, p, len);
if(!done)
return 1;
len -= done;
p += done;
}
}
sptps_stop(&sptps);

View file

@ -81,7 +81,7 @@ struct ip {
uint8_t ip_p;
uint16_t ip_sum;
struct in_addr ip_src, ip_dst;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#endif
#ifndef IP_OFFMASK
@ -143,7 +143,7 @@ struct icmp {
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#endif
#endif /* __TINC_IPV4_H__ */

View file

@ -1,7 +1,7 @@
/*
ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
2006-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -29,29 +29,6 @@
#define IPPROTO_ICMPV6 58
#endif
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} in6_u;
} __attribute__ ((__packed__));
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
#endif
#ifndef HAVE_STRUCT_SOCKADDR_IN6
struct sockaddr_in6 {
uint16_t sin6_family;
uint16_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
} __attribute__ ((__packed__));
#endif
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \
((((__const uint32_t *) (a))[0] == 0) \
@ -72,7 +49,7 @@ struct ip6_hdr {
} ip6_ctlun;
struct in6_addr ip6_src;
struct in6_addr ip6_dst;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
@ -91,7 +68,7 @@ struct icmp6_hdr {
uint16_t icmp6_un_data16[2];
uint8_t icmp6_un_data8[4];
} icmp6_dataun;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#define ICMP6_DST_UNREACH_NOROUTE 0
#define ICMP6_DST_UNREACH 1
#define ICMP6_PACKET_TOO_BIG 2
@ -111,7 +88,7 @@ struct icmp6_hdr {
struct nd_neighbor_solicit {
struct icmp6_hdr nd_ns_hdr;
struct in6_addr nd_ns_target;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#define ND_OPT_SOURCE_LINKADDR 1
#define ND_OPT_TARGET_LINKADDR 2
#define nd_ns_type nd_ns_hdr.icmp6_type
@ -124,7 +101,7 @@ struct nd_neighbor_solicit {
struct nd_opt_hdr {
uint8_t nd_opt_type;
uint8_t nd_opt_len;
} __attribute__ ((__packed__));
} __attribute__ ((__gcc_struct__, __packed__));
#endif
#endif /* __TINC_IPV6_H__ */

View file

@ -101,6 +101,9 @@ static bool setup_device(void) {
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
free(iface);
iface = xstrdup(ifrname);
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create a tun/tap interface from %s: %s", device, strerror(errno));
return false;
}
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);

View file

@ -79,6 +79,12 @@ extern void list_delete_list(list_t *);
extern void list_foreach(list_t *, list_action_t);
extern void list_foreach_node(list_t *, list_action_node_t);
/*
Iterates over a list.
CAUTION: while this construct supports deleting the current item,
it does *not* support deleting *other* nodes while iterating on the list.
*/
#define list_each(type, item, list) (type *item = (type *)1; item; item = NULL) for(list_node_t *node = (list)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
#endif /* __TINC_LIST_H__ */

View file

@ -1,6 +1,6 @@
/*
logger.c -- logging code
Copyright (C) 2004-2013 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2004-2015 Guus Sliepen <guus@tinc-vpn.org>
2004-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -26,6 +26,7 @@
#include "logger.h"
#include "connection.h"
#include "control_common.h"
#include "process.h"
#include "sptps.h"
debug_t debug_level = DEBUG_NOTHING;
@ -37,7 +38,7 @@ static HANDLE loghandle = NULL;
#endif
static const char *logident = NULL;
bool logcontrol = false;
int umbilical = 0;
static void real_logger(int level, int priority, const char *message) {
char timestr[32] = "";
@ -79,6 +80,11 @@ static void real_logger(int level, int priority, const char *message) {
case LOGMODE_NULL:
break;
}
if(umbilical && do_detach) {
write(umbilical, message, strlen(message));
write(umbilical, "\n", 1);
}
}
if(logcontrol) {
@ -114,9 +120,19 @@ void logger(int level, int priority, const char *format, ...) {
static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) {
char message[1024] = "";
int len = vsnprintf(message, sizeof message, format, ap);
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
message[len - 1] = 0;
size_t msglen = sizeof message;
int len = vsnprintf(message, msglen, format, ap);
if(len > 0 && len < sizeof message) {
if(message[len - 1] == '\n')
message[--len] = 0;
// WARNING: s->handle can point to a connection_t or a node_t,
// but both types have the name and hostname fields at the same offsets.
connection_t *c = s->handle;
if(c)
snprintf(message + len, sizeof message - len, " from %s (%s)", c->name, c->hostname);
}
real_logger(DEBUG_ALWAYS, LOG_ERR, message);
}
@ -194,6 +210,5 @@ void closelogger(void) {
case LOGMODE_NULL:
case LOGMODE_STDERR:
break;
break;
}
}

View file

@ -69,6 +69,7 @@ enum {
extern debug_t debug_level;
extern bool logcontrol;
extern int umbilical;
extern void openlogger(const char *, logmode_t);
extern void reopenlogger(void);
extern void logger(int, int, const char *, ...) __attribute__ ((__format__(printf, 3, 4)));

View file

@ -30,6 +30,10 @@
#include "utils.h"
#include "xalloc.h"
#ifndef MIN
#define MIN(x, y) (((x)<(y))?(x):(y))
#endif
bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) {
connection_t *c = handle;
@ -58,6 +62,9 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
/* Add our data to buffer */
if(c->status.encryptout) {
#ifdef DISABLE_LEGACY
return false;
#else
size_t outlen = length;
if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
@ -65,6 +72,7 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
c->name, c->hostname);
return false;
}
#endif
} else {
buffer_add(&c->outbuf, buffer, length);
}
@ -74,6 +82,20 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
return true;
}
void send_meta_raw(connection_t *c, const char *buffer, int length) {
if(!c) {
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
abort();
}
logger(DEBUG_META, LOG_DEBUG, "Sending %d bytes of raw metadata to %s (%s)", length,
c->name, c->hostname);
buffer_add(&c->outbuf, buffer, length);
io_set(&c->io, IO_READ | IO_WRITE);
}
void broadcast_meta(connection_t *from, const char *buffer, int length) {
for list_each(connection_t, c, connection_list)
if(c != from && c->edge)
@ -155,8 +177,33 @@ bool receive_meta(connection_t *c) {
}
do {
if(c->protocol_minor >= 2)
return sptps_receive_data(&c->sptps, bufp, inlen);
/* Are we receiving a SPTPS packet? */
if(c->sptpslen) {
int len = MIN(inlen, c->sptpslen - c->inbuf.len);
buffer_add(&c->inbuf, bufp, len);
char *sptpspacket = buffer_read(&c->inbuf, c->sptpslen);
if(!sptpspacket)
return true;
if(!receive_tcppacket_sptps(c, sptpspacket, c->sptpslen))
return false;
c->sptpslen = 0;
bufp += len;
inlen -= len;
continue;
}
if(c->protocol_minor >= 2) {
int len = sptps_receive_data(&c->sptps, bufp, inlen);
if(!len)
return false;
bufp += len;
inlen -= len;
continue;
}
if(!c->status.decryptin) {
endp = memchr(bufp, '\n', inlen);
@ -170,6 +217,9 @@ bool receive_meta(connection_t *c) {
inlen -= endp - bufp;
bufp = endp;
} else {
#ifdef DISABLE_LEGACY
return false;
#else
size_t outlen = inlen;
if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || inlen != outlen) {
@ -179,6 +229,7 @@ bool receive_meta(connection_t *c) {
}
inlen = 0;
#endif
}
while(c->inbuf.len) {

View file

@ -24,6 +24,7 @@
#include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int);
extern void send_meta_raw(struct connection_t *, const char *, int);
extern bool send_meta_sptps(void *, uint8_t, const void *, size_t);
extern bool receive_meta_sptps(void *, uint8_t, const void *, uint16_t);
extern void broadcast_meta(struct connection_t *, const char *, int);

View file

@ -38,7 +38,9 @@ int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE;
static io_t device_read_io;
static OVERLAPPED device_read_overlapped;
static OVERLAPPED device_write_overlapped;
static vpn_packet_t device_read_packet;
static vpn_packet_t device_write_packet;
char *device = NULL;
char *iface = NULL;
static char *device_info = NULL;
@ -99,6 +101,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface)
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
@ -175,6 +180,25 @@ static bool setup_device(void) {
return false;
}
/* Get version information from tap device */
{
ULONG info[3] = {0};
DWORD len;
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof info, &info, sizeof info, &len, NULL))
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
else {
logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : "");
/* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */
if(info[0] == 9 && info[1] >= 21)
logger(DEBUG_ALWAYS, LOG_WARNING,
"You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. "
"Using these drivers with tinc is not recommanded as it can result in poor performance. "
"You might want to revert back to 9.0.0.9 instead.");
}
}
/* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
@ -200,8 +224,12 @@ static void enable_device(void) {
DWORD len;
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
io_add_event(&device_read_io, device_handle_read, NULL, CreateEvent(NULL, TRUE, FALSE, NULL));
device_read_overlapped.hEvent = device_read_io.event;
/* We don't use the write event directly, but GetOverlappedResult() does, internally. */
device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent);
device_issue_read();
}
@ -210,10 +238,22 @@ static void disable_device(void) {
io_del(&device_read_io);
CancelIo(device_handle);
/* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
To prevent race conditions, make sure the operation is complete
before we close the event it's referencing. */
DWORD len;
if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED)
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError()));
if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED)
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError()));
device_write_packet.len = 0;
CloseHandle(device_read_overlapped.hEvent);
CloseHandle(device_write_overlapped.hEvent);
ULONG status = 0;
DWORD len;
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
}
@ -231,12 +271,29 @@ static bool read_packet(vpn_packet_t *packet) {
static bool write_packet(vpn_packet_t *packet) {
DWORD outlen;
OVERLAPPED overlapped = {0};
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, &overlapped)) {
if(device_write_packet.len > 0) {
/* Make sure the previous write operation is finished before we start the next one;
otherwise we end up with multiple write ops referencing the same OVERLAPPED structure,
which according to MSDN is a no-no. */
if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) {
int log_level = (GetLastError() == ERROR_IO_INCOMPLETE) ? DEBUG_TRAFFIC : DEBUG_ALWAYS;
logger(log_level, LOG_ERR, "Error while checking previous write to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
}
/* Copy the packet, since the write operation might still be ongoing after we return. */
memcpy(&device_write_packet, packet, sizeof *packet);
if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped))
device_write_packet.len = 0;
else if (GetLastError() != ERROR_IO_PENDING) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}

View file

@ -162,7 +162,7 @@ static void close_device(void) {
static bool read_packet(vpn_packet_t *packet) {
int lenin;
if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) {
if((lenin = recv(device_fd, (void *)DATA(packet), MTU, 0)) <= 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, sockstrerror(sockerrno));
return false;
@ -185,7 +185,7 @@ static bool write_packet(vpn_packet_t *packet) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(sendto(device_fd, DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
if(sendto(device_fd, (void *)DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
sockstrerror(sockerrno));
return false;

View file

@ -1,7 +1,7 @@
/*
names.c -- generate commonly used (file)names
Copyright (C) 1998-2005 Ivo Timmermans
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2015 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
@ -21,6 +21,7 @@
#include "system.h"
#include "logger.h"
#include "names.h"
#include "xalloc.h"
char *netname = NULL;
@ -36,7 +37,7 @@ char *program_name = NULL;
/*
Set all files and paths according to netname
*/
void make_names(void) {
void make_names(bool daemon) {
#ifdef HAVE_MINGW
HKEY key;
char installdir[1024] = "";
@ -56,14 +57,14 @@ void make_names(void) {
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) {
confdir = xstrdup(installdir);
if(!logfilename)
xasprintf(&logfilename, "%s" SLASH "log" SLASH "%s.log", installdir, identname);
if(!confbase) {
if(netname)
xasprintf(&confbase, "%s" SLASH "%s", installdir, netname);
else
xasprintf(&confbase, "%s", installdir);
}
if(!logfilename)
xasprintf(&logfilename, "%s" SLASH "tinc.log", confbase);
}
RegCloseKey(key);
}
@ -85,21 +86,46 @@ void make_names(void) {
if(!pidfilename)
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
#else
if(!logfilename)
xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname);
bool fallback = false;
if(daemon) {
if(access(LOCALSTATEDIR, R_OK | W_OK | X_OK))
fallback = true;
} else {
char fname[PATH_MAX];
snprintf(fname, sizeof fname, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
if(access(fname, R_OK)) {
snprintf(fname, sizeof fname, "%s" SLASH "pid", confbase);
if(!access(fname, R_OK))
fallback = true;
}
}
if(!pidfilename)
xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
if(!fallback) {
if(!logfilename)
xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname);
if(!pidfilename)
xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
} else {
if(!logfilename)
xasprintf(&logfilename, "%s" SLASH "log", confbase);
if(!pidfilename) {
if(daemon)
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not access " LOCALSTATEDIR SLASH " (%s), storing pid and socket files in %s" SLASH, strerror(errno), confbase);
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
}
}
#endif
if(!unixsocketname) {
int len = strlen(pidfilename);
unixsocketname = xmalloc(len + 8);
strcpy(unixsocketname, pidfilename);
memcpy(unixsocketname, pidfilename, len);
if(len > 4 && !strcmp(pidfilename + len - 4, ".pid"))
strcpy(unixsocketname + len - 4, ".socket");
strncpy(unixsocketname + len - 4, ".socket", 8);
else
strcpy(unixsocketname + len, ".socket");
strncpy(unixsocketname + len, ".socket", 8);
}
}
@ -111,4 +137,12 @@ void free_names(void) {
free(logfilename);
free(confbase);
free(confdir);
identname = NULL;
netname = NULL;
unixsocketname = NULL;
pidfilename = NULL;
logfilename = NULL;
confbase = NULL;
confdir = NULL;
}

View file

@ -1,7 +1,7 @@
/*
names.h -- header for names.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2015 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,7 +31,7 @@ extern char *logfilename;
extern char *pidfilename;
extern char *program_name;
extern void make_names(void);
extern void make_names(bool daemon);
extern void free_names(void);
#endif /* __TINC_NAMES_H__ */

View file

@ -1,7 +1,7 @@
/*
net.c -- most of the network code
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2011 Loïc Grenié <loic.grenie@gmail.com>
@ -36,10 +36,6 @@
#include "subnet.h"
#include "xalloc.h"
#ifdef HAVE_RESOLV_H
#include <resolv.h>
#endif
int contradicting_add_edge = 0;
int contradicting_del_edge = 0;
static int sleeptime = 10;
@ -154,8 +150,9 @@ static void timeout_handler(void *data) {
if(c->last_ping_time + pingtimeout <= now.tv_sec) {
if(c->edge) {
try_tx(c->node, false);
if(c->status.pinged) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time);
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)(now.tv_sec - c->last_ping_time));
} else if(c->last_ping_time + pinginterval <= now.tv_sec) {
send_ping(c);
continue;
@ -170,9 +167,10 @@ static void timeout_handler(void *data) {
}
terminate_connection(c, c->edge);
}
}
timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000});
timeout_set(data, &(struct timeval){1, rand() % 100000});
}
static void periodic_handler(void *data) {
@ -183,7 +181,7 @@ static void periodic_handler(void *data) {
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
usleep(sleeptime * 1000000LL);
nanosleep(&(struct timespec){sleeptime, 0}, NULL);
sleeptime *= 2;
if(sleeptime < 0)
sleeptime = 3600;
@ -212,10 +210,13 @@ static void periodic_handler(void *data) {
and we are not already trying to make one, create an
outgoing connection to this node.
*/
int r = rand() % node_tree->count;
int r = rand() % (node_tree->count - 1);
int i = 0;
for splay_each(node_t, n, node_tree) {
if(n == myself)
continue;
if(i++ != r)
continue;
@ -311,15 +312,12 @@ static void sighup_handler(void *data) {
static void sigalrm_handler(void *data) {
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
#ifdef HAVE_DECL_RES_INIT
res_init();
#endif
retry();
}
#endif
int reload_configuration(void) {
char *fname = NULL;
char fname[PATH_MAX];
/* Reread our own configuration file */
@ -333,9 +331,8 @@ int reload_configuration(void) {
read_config_options(config_tree, NULL);
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, myself->name);
read_config_file(config_tree, fname);
free(fname);
/* Parse some options that are allowed to be changed while tinc is running */
@ -412,13 +409,12 @@ int reload_configuration(void) {
if(c->status.control)
continue;
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
struct stat s;
if(stat(fname, &s) || s.st_mtime > last_config_check) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Host config file of %s has been changed", c->name);
terminate_connection(c, c->edge);
}
free(fname);
}
last_config_check = now.tv_sec;
@ -449,7 +445,7 @@ void retry(void) {
*/
int main_loop(void) {
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000});
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){0, 0});
#ifndef HAVE_MINGW
signal_t sighup = {0};

View file

@ -1,7 +1,7 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -115,6 +115,7 @@ typedef struct listen_socket_t {
io_t udp;
sockaddr_t sa;
bool bindto;
int priority;
} listen_socket_t;
#include "conf.h"
@ -138,6 +139,14 @@ extern int addressfamily;
extern unsigned replaywin;
extern bool localdiscovery;
extern bool udp_discovery;
extern int udp_discovery_keepalive_interval;
extern int udp_discovery_interval;
extern int udp_discovery_timeout;
extern int mtu_info_interval;
extern int udp_info_interval;
extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets;
extern io_t unix_socket;
@ -183,10 +192,11 @@ extern void handle_new_meta_connection(void *, int);
extern void handle_new_unix_connection(void *, int);
extern int setup_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_socket(const sockaddr_t *);
extern bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len);
extern bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len);
extern bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len);
extern void send_packet(struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, const char *, int);
extern bool receive_tcppacket_sptps(struct connection_t *, const char *, int);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
extern char *get_name(void);
extern void device_enable(void);
@ -201,7 +211,6 @@ extern void terminate_connection(struct connection_t *, bool);
extern bool node_read_ecdsa_public_key(struct node_t *);
extern bool read_ecdsa_public_key(struct connection_t *);
extern bool read_rsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_t *);
extern void handle_device_data(void *, int);
extern void handle_meta_connection_data(struct connection_t *);
extern void regenerate_key(void);
@ -210,6 +219,7 @@ extern void retry(void);
extern int reload_configuration(void);
extern void load_all_subnets(void);
extern void load_all_nodes(void);
extern void try_tx(struct node_t *n, bool);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2010 Brandon Black <blblack@gmail.com>
@ -43,6 +43,10 @@
#include "utils.h"
#include "xalloc.h"
#ifdef HAVE_MINIUPNPC
#include "upnp.h"
#endif
char *myport;
static char *myname;
static io_t device_io;
@ -137,18 +141,17 @@ bool read_ecdsa_public_key(connection_t *c) {
}
c->ecdsa = ecdsa_read_pem_public_key(fp);
fclose(fp);
if(!c->ecdsa)
if(!c->ecdsa && errno != ENOENT)
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
fclose(fp);
free(fname);
return c->ecdsa;
}
#ifndef DISABLE_LEGACY
bool read_rsa_public_key(connection_t *c) {
if(ecdsa_active(c->ecdsa))
return true;
FILE *fp;
char *fname;
char *n;
@ -182,6 +185,7 @@ bool read_rsa_public_key(connection_t *c) {
free(fname);
return c->rsa;
}
#endif
static bool read_ecdsa_private_key(void) {
FILE *fp;
@ -226,14 +230,14 @@ static bool read_ecdsa_private_key(void) {
static bool read_invitation_key(void) {
FILE *fp;
char *fname;
char fname[PATH_MAX];
if(invitation_key) {
ecdsa_free(invitation_key);
invitation_key = NULL;
}
xasprintf(&fname, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
snprintf(fname, sizeof fname, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
fp = fopen(fname, "r");
@ -244,10 +248,10 @@ static bool read_invitation_key(void) {
logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
}
free(fname);
return invitation_key;
}
#ifndef DISABLE_LEGACY
static bool read_rsa_private_key(void) {
FILE *fp;
char *fname;
@ -304,6 +308,7 @@ static bool read_rsa_private_key(void) {
free(fname);
return myself->connection->rsa;
}
#endif
static timeout_t keyexpire_timeout;
@ -315,6 +320,8 @@ static void keyexpire_handler(void *data) {
void regenerate_key(void) {
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
send_key_changed();
for splay_each(node_t, n, node_tree)
n->status.validkey_in = false;
}
/*
@ -323,13 +330,12 @@ void regenerate_key(void) {
void load_all_subnets(void) {
DIR *dir;
struct dirent *ent;
char *dname;
char dname[PATH_MAX];
xasprintf(&dname, "%s" SLASH "hosts", confbase);
snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase);
dir = opendir(dname);
if(!dir) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
free(dname);
return;
}
@ -362,6 +368,7 @@ void load_all_subnets(void) {
if((s2 = lookup_subnet(n, s))) {
s2->expires = -1;
free(s);
} else {
subnet_add(n, s);
}
@ -376,13 +383,12 @@ void load_all_subnets(void) {
void load_all_nodes(void) {
DIR *dir;
struct dirent *ent;
char *dname;
char dname[PATH_MAX];
xasprintf(&dname, "%s" SLASH "hosts", confbase);
snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase);
dir = opendir(dname);
if(!dir) {
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
free(dname);
return;
}
@ -506,6 +512,14 @@ bool setup_myself_reloadable(void) {
if(myself->options & OPTION_TCPONLY)
myself->options |= OPTION_INDIRECT;
get_config_bool(lookup_config(config_tree, "UDPDiscovery"), &udp_discovery);
get_config_int(lookup_config(config_tree, "UDPDiscoveryKeepaliveInterval"), &udp_discovery_keepalive_interval);
get_config_int(lookup_config(config_tree, "UDPDiscoveryInterval"), &udp_discovery_interval);
get_config_int(lookup_config(config_tree, "UDPDiscoveryTimeout"), &udp_discovery_timeout);
get_config_int(lookup_config(config_tree, "MTUInfoInterval"), &mtu_info_interval);
get_config_int(lookup_config(config_tree, "UDPInfoInterval"), &udp_info_interval);
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
@ -577,9 +591,14 @@ bool setup_myself_reloadable(void) {
subnet_add(NULL, s);
}
#if !defined(SOL_IP) || !defined(IP_TOS)
#if !defined(IPPROTO_IP) || !defined(IP_TOS)
if(priorityinheritance)
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv4 connections", "PriorityInheritance");
#endif
#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS)
if(priorityinheritance)
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv6 connections", "PriorityInheritance");
#endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
@ -652,6 +671,9 @@ static bool add_listen_address(char *address, bool bindto) {
hint.ai_protocol = IPPROTO_TCP;
hint.ai_flags = AI_PASSIVE;
#if HAVE_DECL_RES_INIT
res_init();
#endif
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
free(address);
@ -773,6 +795,13 @@ static bool setup_myself(void) {
myself->options |= PROT_MINOR << 24;
#ifdef DISABLE_LEGACY
experimental = read_ecdsa_private_key();
if(!experimental) {
logger(DEBUG_ALWAYS, LOG_ERR, "No private key available, cannot start tinc!");
return false;
}
#else
if(!get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental)) {
experimental = read_ecdsa_private_key();
if(!experimental)
@ -790,6 +819,7 @@ static bool setup_myself(void) {
return false;
}
}
#endif
/* Ensure myport is numeric */
@ -831,14 +861,14 @@ static bool setup_myself(void) {
}
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
if(udp_rcvbuf <= 0) {
if(udp_rcvbuf < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "UDPRcvBuf cannot be negative!");
return false;
}
}
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
if(udp_sndbuf <= 0) {
if(udp_sndbuf < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "UDPSndBuf cannot be negative!");
return false;
}
@ -854,6 +884,7 @@ static bool setup_myself(void) {
sptps_replaywin = replaywin;
}
#ifndef DISABLE_LEGACY
/* Generate packet encryption key */
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
@ -891,6 +922,7 @@ static bool setup_myself(void) {
}
free(digest);
#endif
/* Compression */
@ -939,6 +971,7 @@ static bool setup_myself(void) {
else if(!strcasecmp(type, "vde"))
devops = vde_devops;
#endif
free(type);
}
get_config_bool(lookup_config(config_tree, "DeviceStandby"), &device_standby);
@ -1035,6 +1068,25 @@ static bool setup_myself(void) {
xasprintf(&myself->hostname, "MYSELF port %s", myport);
myself->connection->hostname = xstrdup(myself->hostname);
char *upnp = NULL;
get_config_string(lookup_config(config_tree, "UPnP"), &upnp);
bool upnp_tcp = false;
bool upnp_udp = false;
if (upnp) {
if (!strcasecmp(upnp, "yes"))
upnp_tcp = upnp_udp = true;
else if (!strcasecmp(upnp, "udponly"))
upnp_udp = true;
free(upnp);
}
if (upnp_tcp || upnp_udp) {
#ifdef HAVE_MINIUPNPC
upnp_init(upnp_tcp, upnp_udp);
#else
logger(DEBUG_ALWAYS, LOG_WARNING, "UPnP was requested, but tinc isn't built with miniupnpc support!");
#endif
}
/* Done. */
last_config_check = now.tv_sec;
@ -1102,8 +1154,7 @@ void close_network_connections(void) {
if(myself && myself->connection) {
subnet_update(myself, NULL, false);
terminate_connection(myself->connection, false);
free_connection(myself->connection);
connection_del(myself->connection);
}
for(int i = 0; i < listen_sockets; i++) {

View file

@ -1,7 +1,7 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
@ -35,16 +35,11 @@
#include "utils.h"
#include "xalloc.h"
/* Needed on Mac OS/X */
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
#endif
int addressfamily = AF_UNSPEC;
int maxtimeout = 900;
int seconds_till_retry = 5;
int udp_rcvbuf = 0;
int udp_sndbuf = 0;
int udp_rcvbuf = 1024 * 1024;
int udp_sndbuf = 1024 * 1024;
int max_connection_burst = 100;
listen_socket_t listen_socket[MAXSOCKETS];
@ -73,14 +68,19 @@ static void configure_tcp(connection_t *c) {
}
#endif
#if defined(SOL_TCP) && defined(TCP_NODELAY)
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
option = 1;
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_TCP, TCP_NODELAY, (void *)&option, sizeof option);
#endif
#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY;
setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_IP, IP_TOS, (void *)&option, sizeof option);
#endif
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY)
option = IPTOS_LOWDELAY;
setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof option);
#endif
}
@ -163,9 +163,9 @@ int setup_listen_socket(const sockaddr_t *sa) {
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
if(get_config_string
@ -261,10 +261,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
#define IP_DONTFRAGMENT IP_DONTFRAG
#endif
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
#if defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
if(myself->options & OPTION_PMTU_DISCOVERY) {
@ -273,10 +273,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
}
#endif
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
}
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
if(myself->options & OPTION_PMTU_DISCOVERY) {
@ -517,10 +517,10 @@ begin:
#endif
if(proxytype != PROXY_EXEC) {
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
int option = 1;
if(c->address.sa.sa_family == AF_INET6)
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
#endif
bind_to_interface(c->socket);
@ -547,10 +547,13 @@ begin:
/* Now that there is a working socket, fill in the rest and register this connection. */
c->last_ping_time = time(NULL);
c->status.connecting = true;
c->name = xstrdup(outgoing->name);
#ifndef DISABLE_LEGACY
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
#endif
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
c->last_ping_time = now.tv_sec;
@ -602,9 +605,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
if(n && n->connection) {
logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
n->connection->outgoing = outgoing;
return;
if(!n->connection->outgoing) {
n->connection->outgoing = outgoing;
return;
} else {
goto remove;
}
}
init_configuration(&outgoing->config_tree);
@ -615,12 +621,16 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
if(n)
outgoing->aip = outgoing->ai = get_known_addresses(n);
if(!outgoing->ai) {
logger(DEBUG_ALWAYS, LOG_ERR, "No address known for %s", outgoing->name);
return;
logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
goto remove;
}
}
do_outgoing_connection(outgoing);
return;
remove:
list_delete(outgoing_list, outgoing);
}
/*
@ -696,8 +706,10 @@ void handle_new_meta_connection(void *data, int flags) {
c = new_connection();
c->name = xstrdup("<unknown>");
#ifndef DISABLE_LEGACY
c->outcipher = myself->connection->outcipher;
c->outdigest = myself->connection->outdigest;
#endif
c->outmaclength = myself->connection->outmaclength;
c->outcompression = myself->connection->outcompression;
@ -796,6 +808,11 @@ void try_outgoing_connections(void) {
continue;
}
if(!strcmp(name, myself->name)) {
free(name);
continue;
}
bool found = false;
for list_each(outgoing_t, outgoing, outgoing_list) {

View file

@ -39,6 +39,9 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
hint.ai_family = addressfamily;
hint.ai_socktype = socktype;
#if HAVE_DECL_RES_INIT
res_init();
#endif
err = getaddrinfo(address, service, &hint, &ai);
if(err) {
@ -80,7 +83,13 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
char *scopeid;
int err;
if(sa->sa.sa_family == AF_UNKNOWN) {
if(sa->sa.sa_family == AF_UNSPEC) {
if(addrstr)
*addrstr = xstrdup("unspec");
if(portstr)
*portstr = xstrdup("unspec");
return;
} else if(sa->sa.sa_family == AF_UNKNOWN) {
if(addrstr)
*addrstr = xstrdup(sa->unknown.address);
if(portstr)
@ -112,7 +121,10 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
char port[NI_MAXSERV] = "unknown";
int err;
if(sa->sa.sa_family == AF_UNKNOWN) {
if(sa->sa.sa_family == AF_UNSPEC) {
xasprintf(&str, "unspec port unspec");
return str;
} else if(sa->sa.sa_family == AF_UNKNOWN) {
xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port);
return str;
}

View file

@ -30,12 +30,11 @@
#include "utils.h"
#include "xalloc.h"
static digest_t *sha256;
#include "ed25519/sha512.h"
splay_tree_t *node_tree;
static splay_tree_t *node_id_tree;
static hash_t *node_udp_cache;
static hash_t *node_id_cache;
static splay_tree_t *node_udp_tree;
node_t *myself;
@ -47,22 +46,23 @@ static int node_id_compare(const node_t *a, const node_t *b) {
return memcmp(&a->id, &b->id, sizeof(node_id_t));
}
void init_nodes(void) {
sha256 = digest_open_by_name("sha256", sizeof(node_id_t));
static int node_udp_compare(const node_t *a, const node_t *b) {
int result = sockaddrcmp(&a->address, &b->address);
if (result)
return result;
return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
}
void init_nodes(void) {
node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
node_id_tree = splay_alloc_tree((splay_compare_t) node_id_compare, NULL);
node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
node_id_cache = hash_alloc(0x100, sizeof(node_id_t));
node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
}
void exit_nodes(void) {
hash_free(node_id_cache);
hash_free(node_udp_cache);
splay_delete_tree(node_udp_tree);
splay_delete_tree(node_id_tree);
splay_delete_tree(node_tree);
digest_close(sha256);
}
node_t *new_node(void) {
@ -86,15 +86,17 @@ void free_node(node_t *n) {
sockaddrfree(&n->address);
#ifndef DISABLE_LEGACY
cipher_close(n->incipher);
digest_close(n->indigest);
cipher_close(n->outcipher);
digest_close(n->outdigest);
#endif
ecdsa_free(n->ecdsa);
sptps_stop(&n->sptps);
timeout_del(&n->mtutimeout);
timeout_del(&n->udp_ping_timeout);
if(n->hostname)
free(n->hostname);
@ -109,15 +111,16 @@ void free_node(node_t *n) {
}
void node_add(node_t *n) {
digest_create(sha256, n->name, strlen(n->name), &n->id);
unsigned char buf[64];
sha512(n->name, strlen(n->name),buf);
memcpy(&n->id, buf, sizeof n->id);
splay_insert(node_tree, n);
splay_insert(node_id_tree, n);
}
void node_del(node_t *n) {
hash_delete(node_udp_cache, &n->address);
hash_delete(node_id_cache, &n->id);
splay_delete(node_udp_tree, n);
for splay_each(subnet_t, s, n->subnet_tree)
subnet_del(n, s);
@ -138,19 +141,13 @@ node_t *lookup_node(char *name) {
}
node_t *lookup_node_id(const node_id_t *id) {
node_t *n = hash_search(node_id_cache, id);
if(!n) {
node_t tmp = {.id = *id};
n = splay_search(node_id_tree, &tmp);
if(n)
hash_insert(node_id_cache, id, n);
}
return n;
node_t n = {.id = *id};
return splay_search(node_id_tree, &n);
}
node_t *lookup_node_udp(const sockaddr_t *sa) {
return hash_search(node_udp_cache, sa);
node_t tmp = {.address = *sa};
return splay_search(node_udp_tree, &tmp);
}
void update_node_udp(node_t *n, const sockaddr_t *sa) {
@ -159,7 +156,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
return;
}
hash_delete(node_udp_cache, &n->address);
splay_delete(node_udp_tree, n);
if(sa) {
n->address = *sa;
@ -170,7 +167,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
break;
}
}
hash_insert(node_udp_cache, sa, n);
splay_insert(node_udp_tree, n);
free(n->hostname);
n->hostname = sockaddr2hostname(&n->address);
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
@ -179,6 +176,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
/* invalidate UDP information - note that this is a security feature as well to make sure
we can't be tricked into flooding any random address with UDP packets */
n->status.udp_confirmed = false;
n->maxrecentlen = 0;
n->mtuprobes = 0;
n->minmtu = 0;
n->maxmtu = MTU;
@ -188,13 +186,18 @@ bool dump_nodes(connection_t *c) {
for splay_each(node_t, n, node_tree) {
char id[2 * sizeof n->id + 1];
for (size_t c = 0; c < sizeof n->id; ++c)
sprintf(id + 2 * c, "%02hhx", n->id.x[c]);
snprintf(id + 2 * c, 3, "%02hhx", n->id.x[c]);
id[sizeof id - 1] = 0;
send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
n->name, id, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
digest_get_nid(n->outdigest), (int)digest_length(n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
n->name, id, n->hostname ?: "unknown port unknown",
#ifdef DISABLE_LEGACY
0, 0, 0,
#else
cipher_get_nid(n->outcipher), digest_get_nid(n->outdigest), (int)digest_length(n->outdigest),
#endif
n->outcompression, n->options, bitfield_to_int(&n->status, sizeof n->status),
n->nexthop ? n->nexthop->name : "-", n->via ? n->via->name ?: "-" : "-", n->distance,
n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);

View file

@ -38,17 +38,19 @@ typedef struct node_status_t {
unsigned int sptps:1; /* 1 if this node supports SPTPS */
unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */
unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */
unsigned int unused:23;
unsigned int udppacket:1; /* 1 if the most recently received packet was UDP */
unsigned int validkey_in:1; /* 1 if we have sent a valid key to him */
unsigned int unused:21;
} node_status_t;
typedef struct node_t {
char *name; /* name of this node */
char *hostname; /* the hostname of its real ip */
node_id_t id; /* unique node ID (name hash) */
uint32_t options; /* options turned on for this node */
int sock; /* Socket to use for outgoing UDP packets */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */
node_status_t status;
time_t last_state_change;
@ -57,11 +59,13 @@ typedef struct node_t {
ecdsa_t *ecdsa; /* His public ECDSA key */
sptps_t sptps;
#ifndef DISABLE_LEGACY
cipher_t *incipher; /* Cipher for UDP packets */
digest_t *indigest; /* Digest for UDP packets */
cipher_t *outcipher; /* Cipher for UDP packets */
digest_t *outdigest; /* Digest for UDP packets */
#endif
int incompression; /* Compressionlevel, 0 = no compression */
int outcompression; /* Compressionlevel, 0 = no compression */
@ -85,16 +89,21 @@ typedef struct node_t {
uint32_t farfuture; /* Packets in a row that have arrived from the far future */
unsigned char* late; /* Bitfield marking late packets */
struct timeval udp_reply_sent; /* Last time a (gratuitous) UDP probe reply was sent */
struct timeval udp_ping_sent; /* Last time a UDP probe was sent */
timeout_t udp_ping_timeout; /* Ping timeout event */
struct timeval mtu_ping_sent; /* Last time a MTU probe was sent */
struct timeval mtu_info_sent; /* Last time a MTU_INFO message was sent */
struct timeval udp_info_sent; /* Last time a UDP_INFO message was sent */
length_t maxrecentlen; /* Maximum size of recently received packets */
length_t mtu; /* Maximum size of packets to send to this node */
length_t minmtu; /* Probed minimum MTU */
length_t maxmtu; /* Probed maximum MTU */
int mtuprobes; /* Number of probes */
timeout_t mtutimeout; /* Probe event */
struct timeval probe_time; /* Time the last probe was sent or received */
int probe_counter; /* Number of probes received since last burst was sent */
float rtt; /* Last measured round trip time */
float bandwidth; /* Last measured bandwidth */
float packetloss; /* Last measured packet loss rate */
uint64_t in_packets;
uint64_t in_bytes;

87
src/nolegacy/crypto.c Normal file
View file

@ -0,0 +1,87 @@
/*
crypto.c -- Cryptographic miscellaneous functions and initialisation
Copyright (C) 2007-2014 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../crypto.h"
#ifndef HAVE_MINGW
static int random_fd = -1;
static void random_init(void) {
random_fd = open("/dev/urandom", O_RDONLY);
if(random_fd < 0)
random_fd = open("/dev/random", O_RDONLY);
if(random_fd < 0) {
fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno));
abort();
}
}
static void random_exit(void) {
close(random_fd);
}
void randomize(void *out, size_t outlen) {
while(outlen) {
size_t len = read(random_fd, out, outlen);
if(len <= 0) {
if(errno == EAGAIN || errno == EINTR)
continue;
fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno));
abort();
}
out += len;
outlen -= len;
}
}
#else
#include <wincrypt.h>
HCRYPTPROV prov;
void random_init(void) {
if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
fprintf(stderr, "CryptAcquireContext() failed!\n");
abort();
}
}
void random_exit(void) {
CryptReleaseContext(prov, 0);
}
void randomize(void *out, size_t outlen) {
if(!CryptGenRandom(prov, outlen, out)) {
fprintf(stderr, "CryptGenRandom() failed\n");
abort();
}
}
#endif
void crypto_init(void) {
random_init();
}
void crypto_exit(void) {
random_exit();
}

106
src/nolegacy/prf.c Normal file
View file

@ -0,0 +1,106 @@
/*
prf.c -- Pseudo-Random Function for key material generation
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#include "../prf.h"
#include "../ed25519/sha512.h"
static void memxor(char *buf, char c, size_t len) {
for(size_t i = 0; i < len; i++)
buf[i] ^= c;
}
static const size_t mdlen = 64;
static const size_t blklen = 128;
static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) {
char tmp[blklen + mdlen];
sha512_context md;
if(keylen <= blklen) {
memcpy(tmp, key, keylen);
memset(tmp + keylen, 0, blklen - keylen);
} else {
if(sha512(key, keylen, tmp) != 0)
return false;
memset(tmp + mdlen, 0, blklen - mdlen);
}
if(sha512_init(&md) != 0)
return false;
// ipad
memxor(tmp, 0x36, blklen);
if(sha512_update(&md, tmp, blklen) != 0)
return false;
// message
if(sha512_update(&md, msg, msglen) != 0)
return false;
if(sha512_final(&md, tmp + blklen) != 0)
return false;
// opad
memxor(tmp, 0x36 ^ 0x5c, blklen);
if(sha512(tmp, sizeof tmp, out) != 0)
return false;
return true;
}
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
We use SHA512 instead of MD5 and SHA1.
*/
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
/* Data is what the "inner" HMAC function processes.
It consists of the previous HMAC result plus the seed.
*/
char data[mdlen + seedlen];
memset(data, 0, mdlen);
memcpy(data + mdlen, seed, seedlen);
char hash[mdlen];
while(outlen > 0) {
/* Inner HMAC */
if(!hmac_sha512(secret, secretlen, data, sizeof data, data))
return false;
/* Outer HMAC */
if(outlen >= mdlen) {
if(!hmac_sha512(secret, secretlen, data, sizeof data, out))
return false;
out += mdlen;
outlen -= mdlen;
} else {
if(!hmac_sha512(secret, secretlen, data, sizeof data, hash))
return false;
memcpy(out, hash, outlen);
out += outlen;
outlen = 0;
}
}
return true;
}

View file

@ -79,6 +79,13 @@ size_t cipher_keylength(const cipher_t *cipher) {
return cipher->cipher->key_len + cipher->cipher->iv_len;
}
size_t cipher_blocksize(const cipher_t *cipher) {
if(!cipher || !cipher->cipher)
return 1;
return cipher->cipher->block_size;
}
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
bool result;

View file

@ -42,6 +42,7 @@ bool sigalrm = false;
extern char **g_argv;
extern bool use_logfile;
extern bool use_syslog;
/* Some functions the less gifted operating systems might lack... */
@ -61,12 +62,9 @@ static bool install_service(void) {
return false;
}
if(!strchr(program_name, '\\')) {
GetCurrentDirectory(sizeof command - 1, command + 1);
strncat(command, "\\", sizeof command - strlen(command));
}
strncat(command, program_name, sizeof command - strlen(command));
HMODULE module = GetModuleHandle(NULL);
GetModuleFileName(module, command + 1, sizeof command - 1);
command[sizeof command - 1] = 0;
strncat(command, "\"", sizeof command - strlen(command));
@ -189,6 +187,8 @@ bool init_service(void) {
Detach from current terminal
*/
bool detach(void) {
logmode_t logmode;
#ifndef HAVE_MINGW
signal(SIGPIPE, SIG_IGN);
signal(SIGUSR1, SIG_IGN);
@ -200,7 +200,7 @@ bool detach(void) {
if(do_detach) {
#ifndef HAVE_MINGW
if(daemon(0, 0)) {
if(daemon(1, 0)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno));
return false;
}
@ -210,12 +210,17 @@ bool detach(void) {
#endif
}
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
if(use_logfile)
logmode = LOGMODE_FILE;
else if(use_syslog || do_detach)
logmode = LOGMODE_SYSLOG;
else
logmode = LOGMODE_STDERR;
openlogger(identname, logmode);
logger(DEBUG_ALWAYS, LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
VERSION, BUILD_DATE, BUILD_TIME, debug_level);
BUILD_VERSION, BUILD_DATE, BUILD_TIME, debug_level);
return true;
}

View file

@ -41,6 +41,9 @@ static bool (*request_handlers[])(connection_t *, const char *) = {
add_subnet_h, del_subnet_h,
add_edge_h, del_edge_h,
key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h,
NULL, NULL, /* Not "real" requests (yet) */
sptps_tcppacket_h,
udp_info_h, mtu_info_h,
};
/* Request names */
@ -51,6 +54,7 @@ static char (*request_name[]) = {
"PING", "PONG",
"ADD_SUBNET", "DEL_SUBNET",
"ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
"REQ_PUBKEY", "ANS_PUBKEY", "SPTPS_PACKET", "UDP_INFO", "MTU_INFO",
};
static splay_tree_t *past_request_tree;
@ -132,7 +136,8 @@ bool receive_request(connection_t *c, const char *request) {
if(!request_handlers[reqno](c, request)) {
/* Something went wrong. Probably scriptkiddies. Terminate. */
logger(DEBUG_ALWAYS, LOG_ERR, "Error while processing %s from %s (%s)", request_name[reqno], c->name, c->hostname);
if(reqno != TERMREQ)
logger(DEBUG_ALWAYS, LOG_ERR, "Error while processing %s from %s (%s)", request_name[reqno], c->name, c->hostname);
return false;
}
} else {

View file

@ -26,7 +26,7 @@
/* Protocol version. Different major versions are incompatible. */
#define PROT_MAJOR 17
#define PROT_MINOR 4 /* Should not exceed 255! */
#define PROT_MINOR 7 /* Should not exceed 255! */
/* Silly Windows */
@ -48,7 +48,8 @@ typedef enum request_t {
/* Tinc 1.1 requests */
CONTROL,
REQ_PUBKEY, ANS_PUBKEY,
REQ_SPTPS,
SPTPS_PACKET,
UDP_INFO, MTU_INFO,
LAST /* Guardian for the highest request number */
} request_t;
@ -107,6 +108,9 @@ extern void send_key_changed(void);
extern bool send_req_key(struct node_t *);
extern bool send_ans_key(struct node_t *);
extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *);
extern bool send_sptps_tcppacket(struct connection_t *, const char*, int);
extern bool send_udp_info(struct node_t *, struct node_t *);
extern bool send_mtu_info(struct node_t *, struct node_t *, int);
/* Request handlers */
@ -128,6 +132,9 @@ extern bool key_changed_h(struct connection_t *, const char *);
extern bool req_key_h(struct connection_t *, const char *);
extern bool ans_key_h(struct connection_t *, const char *);
extern bool tcppacket_h(struct connection_t *, const char *);
extern bool sptps_tcppacket_h(struct connection_t *, const char *);
extern bool control_h(struct connection_t *, const char *);
extern bool udp_info_h(struct connection_t *, const char *);
extern bool mtu_info_h(struct connection_t *, const char *);
#endif /* __TINC_PROTOCOL_H__ */

View file

@ -45,6 +45,8 @@
#include "utils.h"
#include "xalloc.h"
#include "ed25519/sha512.h"
ecdsa_t *invitation_key = NULL;
static bool send_proxyrequest(connection_t *c) {
@ -115,7 +117,7 @@ static bool send_proxyrequest(connection_t *c) {
i += 2;
c->tcplen += 22;
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
return false;
}
if(i > len)
@ -211,17 +213,13 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat
return false;
// Recover the filename from the cookie and the key
digest_t *digest = digest_open_by_name("sha256", 18);
if(!digest)
abort();
char *fingerprint = ecdsa_get_base64_public_key(invitation_key);
char hashbuf[18 + strlen(fingerprint)];
char cookie[25];
char cookie[64];
memcpy(hashbuf, data, 18);
memcpy(hashbuf + 18, fingerprint, sizeof hashbuf - 18);
digest_create(digest, hashbuf, sizeof hashbuf, cookie);
sha512(hashbuf, sizeof hashbuf, cookie);
b64encode_urlsafe(cookie, cookie, 18);
digest_close(digest);
free(fingerprint);
char filename[PATH_MAX], usedname[PATH_MAX];
@ -388,7 +386,7 @@ bool id_h(connection_t *c, const char *request) {
/* Forbid version rollback for nodes whose Ed25519 key we know */
if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
if(ecdsa_active(c->ecdsa) && c->protocol_minor < 1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Peer %s (%s) tries to roll back protocol version to %d.%d",
c->name, c->hostname, c->protocol_major, c->protocol_minor);
return false;
@ -412,6 +410,9 @@ bool id_h(connection_t *c, const char *request) {
}
bool send_metakey(connection_t *c) {
#ifdef DISABLE_LEGACY
return false;
#else
if(!myself->connection->rsa) {
logger(DEBUG_CONNECTIONS, LOG_ERR, "Peer %s (%s) uses legacy protocol which we don't support", c->name, c->hostname);
return false;
@ -480,9 +481,13 @@ bool send_metakey(connection_t *c) {
c->status.encryptout = true;
return result;
#endif
}
bool metakey_h(connection_t *c, const char *request) {
#ifdef DISABLE_LEGACY
return false;
#else
if(!myself->connection->rsa)
return false;
@ -545,9 +550,13 @@ bool metakey_h(connection_t *c, const char *request) {
c->allow_request = CHALLENGE;
return send_challenge(c);
#endif
}
bool send_challenge(connection_t *c) {
#ifdef DISABLE_LEGACY
return false;
#else
const size_t len = rsa_size(c->rsa);
char buffer[len * 2 + 1];
@ -565,9 +574,13 @@ bool send_challenge(connection_t *c) {
/* Send the challenge */
return send_request(c, "%d %s", CHALLENGE, buffer);
#endif
}
bool challenge_h(connection_t *c, const char *request) {
#ifdef DISABLE_LEGACY
return false;
#else
if(!myself->connection->rsa)
return false;
@ -606,9 +619,13 @@ bool challenge_h(connection_t *c, const char *request) {
c->allow_request = CHAL_REPLY;
return send_request(c, "%d %s", CHAL_REPLY, buffer);
#endif
}
bool chal_reply_h(connection_t *c, const char *request) {
#ifdef DISABLE_LEGACY
return false;
#else
char hishash[MAX_STRING_SIZE];
if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) {
@ -645,9 +662,13 @@ bool chal_reply_h(connection_t *c, const char *request) {
c->allow_request = ACK;
return send_ack(c);
#endif
}
static bool send_upgrade(connection_t *c) {
#ifdef DISABLE_LEGACY
return false;
#else
/* Special case when protocol_minor is 1: the other end is Ed25519 capable,
* but doesn't know our key yet. So send it now. */
@ -659,6 +680,7 @@ static bool send_upgrade(connection_t *c) {
bool result = send_request(c, "%d %s", ACK, pubkey);
free(pubkey);
return result;
#endif
}
bool send_ack(connection_t *c) {
@ -758,6 +780,8 @@ static bool upgrade_h(connection_t *c, const char *request) {
logger(DEBUG_ALWAYS, LOG_INFO, "Got Ed25519 public key from %s (%s), upgrading!", c->name, c->hostname);
append_config_file(c->name, "Ed25519PublicKey", pubkey);
c->allow_request = TERMREQ;
if(c->outgoing)
c->outgoing->timeout = 0;
return send_termreq(c);
}

View file

@ -37,19 +37,26 @@
bool send_add_edge(connection_t *c, const edge_t *e) {
bool x;
char *address, *port;
char *local_address, *local_port;
sockaddr2str(&e->address, &address, &port);
sockaddr2str(&e->local_address, &local_address, &local_port);
x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, rand(),
e->from->name, e->to->name, address, port,
e->options, e->weight, local_address, local_port);
if(e->local_address.sa.sa_family) {
char *local_address, *local_port;
sockaddr2str(&e->local_address, &local_address, &local_port);
x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, rand(),
e->from->name, e->to->name, address, port,
e->options, e->weight, local_address, local_port);
free(local_address);
free(local_port);
} else {
x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(),
e->from->name, e->to->name, address, port,
e->options, e->weight);
}
free(address);
free(port);
free(local_address);
free(local_port);
return x;
}
@ -61,9 +68,9 @@ bool add_edge_h(connection_t *c, const char *request) {
char to_name[MAX_STRING_SIZE];
char to_address[MAX_STRING_SIZE];
char to_port[MAX_STRING_SIZE];
char address_local[MAX_STRING_SIZE] = "unknown";
char port_local[MAX_STRING_SIZE] = "unknown";
sockaddr_t address, local_address;
char address_local[MAX_STRING_SIZE];
char port_local[MAX_STRING_SIZE];
sockaddr_t address, local_address = {{0}};
uint32_t options;
int weight;
@ -117,27 +124,71 @@ bool add_edge_h(connection_t *c, const char *request) {
/* Convert addresses */
address = str2sockaddr(to_address, to_port);
local_address = str2sockaddr(address_local, port_local);
if(parameter_count >= 8)
local_address = str2sockaddr(address_local, port_local);
/* Check if edge already exists */
e = lookup_edge(from, to);
if(e) {
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address) || sockaddrcmp(&e->local_address, &local_address)) {
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
if(from == myself) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
"ADD_EDGE", c->name, c->hostname);
send_add_edge(c, e);
sockaddrfree(&local_address);
return true;
} else {
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
"ADD_EDGE", c->name, c->hostname);
edge_del(e);
graph();
e->options = options;
if(sockaddrcmp(&e->address, &address)) {
sockaddrfree(&e->address);
e->address = address;
}
if(e->weight != weight) {
splay_node_t *node = splay_unlink(edge_weight_tree, e);
e->weight = weight;
splay_insert_node(edge_weight_tree, node);
}
goto done;
}
} else
} else if(sockaddrcmp(&e->local_address, &local_address)) {
if(from == myself) {
if(e->local_address.sa.sa_family && local_address.sa.sa_family) {
// Someone has the wrong local address for ourself. Correct then.
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
"ADD_EDGE", c->name, c->hostname);
send_add_edge(c, e);
sockaddrfree(&local_address);
return true;
}
// Otherwise, just ignore it.
sockaddrfree(&local_address);
return true;
} else if(local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN) {
// We learned a new local address for this edge.
// local_address.sa.sa_family will be 0 if we got it from older tinc versions
// local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions
// but for edge which does not have local_address
sockaddrfree(&e->local_address);
e->local_address = local_address;
// Tell others about it.
if(!tunnelserver)
forward_request(c, request);
return true;
} else {
sockaddrfree(&local_address);
return true;
}
} else {
sockaddrfree(&local_address);
return true;
}
} else if(from == myself) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist",
"ADD_EDGE", c->name, c->hostname);
@ -147,6 +198,7 @@ bool add_edge_h(connection_t *c, const char *request) {
e->to = to;
send_del_edge(c, e);
free_edge(e);
sockaddrfree(&local_address);
return true;
}
@ -159,6 +211,7 @@ bool add_edge_h(connection_t *c, const char *request) {
e->weight = weight;
edge_add(e);
done:
/* Tell the rest about the new edge */
if(!tunnelserver)

View file

@ -36,6 +36,7 @@
static bool mykeyused = false;
void send_key_changed(void) {
#ifndef DISABLE_LEGACY
send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
@ -43,6 +44,7 @@ void send_key_changed(void) {
for list_each(connection_t, c, connection_list)
if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps)
send_ans_key(c->node);
#endif
/* Force key exchange for connections using SPTPS */
@ -87,9 +89,13 @@ bool key_changed_h(connection_t *c, const char *request) {
return true;
}
static bool send_sptps_data_myself(void *handle, uint8_t type, const void *data, size_t len) {
return send_sptps_data(handle, myself, type, data, len);
}
static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
node_t *to = handle;
to->sptps.send_data = send_sptps_data;
to->sptps.send_data = send_sptps_data_myself;
char buf[len * 4 / 3 + 5];
b64encode(data, buf, len);
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
@ -103,9 +109,6 @@ bool send_req_key(node_t *to) {
return true;
}
if(to->sptps.label)
logger(DEBUG_ALWAYS, LOG_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name);
char label[25 + strlen(myself->name) + strlen(to->name)];
snprintf(label, sizeof label, "tinc UDP key expansion %s %s", myself->name, to->name);
sptps_stop(&to->sptps);
@ -121,7 +124,52 @@ bool send_req_key(node_t *to) {
/* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, node_t *to, int reqno) {
/* If this is a SPTPS packet, see if sending UDP info helps.
Note that we only do this if we're the destination or the static relay;
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
if((reqno == REQ_KEY || reqno == SPTPS_PACKET) && to->via == myself)
send_udp_info(myself, from);
if(reqno == SPTPS_PACKET) {
/* This is a SPTPS data packet. */
char buf[MAX_STRING_SIZE];
int len;
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s) to %s (%s): %s", "SPTPS_PACKET", from->name, from->hostname, to->name, to->hostname, "invalid SPTPS data");
return true;
}
if(to != myself) {
/* We don't just forward the request, because we want to use UDP if it's available. */
send_sptps_data(to, from, 0, buf, len);
try_tx(to, true);
} else {
/* The packet is for us */
if(!sptps_receive_data(&from->sptps, buf, len)) {
/* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
so let's restart SPTPS in case that helps. But don't do that too often
to prevent storms. */
if(from->last_req_key < now.tv_sec - 10) {
logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname);
send_req_key(from);
}
return true;
}
send_mtu_info(myself, from, MTU);
}
return true;
}
/* Requests that are not SPTPS data packets are forwarded as-is. */
if (to != myself)
return send_request(to->nexthop->connection, "%s", request);
/* The request is for us */
switch(reqno) {
case REQ_PUBKEY: {
if(!node_read_ecdsa_public_key(from)) {
@ -176,24 +224,9 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
from->status.validkey = false;
from->status.waitingforkey = true;
from->last_req_key = now.tv_sec;
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
sptps_receive_data(&from->sptps, buf, len);
return true;
}
case REQ_SPTPS: {
if(!from->status.validkey) {
logger(DEBUG_PROTOCOL, LOG_ERR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
return true;
}
char buf[MAX_STRING_SIZE];
int len;
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
return true;
}
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data_myself, receive_sptps_record);
sptps_receive_data(&from->sptps, buf, len);
send_mtu_info(myself, from, MTU);
return true;
}
@ -241,7 +274,7 @@ bool req_key_h(connection_t *c, const char *request) {
if(to == myself) { /* Yes */
/* Is this an extended REQ_KEY message? */
if(experimental && reqno)
return req_key_ext_h(c, request, from, reqno);
return req_key_ext_h(c, request, from, to, reqno);
/* No, just send our key back */
send_ans_key(from);
@ -255,7 +288,10 @@ bool req_key_h(connection_t *c, const char *request) {
return true;
}
/* TODO: forwarding SPTPS packets in this way is inefficient because we send them over TCP without checking for UDP connectivity */
/* Is this an extended REQ_KEY message? */
if(experimental && reqno)
return req_key_ext_h(c, request, from, to, reqno);
send_request(to->nexthop->connection, "%s", request);
}
@ -266,6 +302,9 @@ bool send_ans_key(node_t *to) {
if(to->status.sptps)
abort();
#ifdef DISABLE_LEGACY
return false;
#else
size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
char key[keylen * 2 + 1];
@ -300,12 +339,15 @@ bool send_ans_key(node_t *to) {
to->received = 0;
if(replaywin) memset(to->late, 0, replaywin);
to->status.validkey_in = true;
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
myself->name, to->name, key,
cipher_get_nid(to->incipher),
digest_get_nid(to->indigest),
(int)digest_length(to->indigest),
to->incompression);
#endif
}
bool ans_key_h(connection_t *c, const char *request) {
@ -358,7 +400,7 @@ bool ans_key_h(connection_t *c, const char *request) {
return true;
}
if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) {
char *address, *port;
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
sockaddr2str(&from->address, &address, &port);
@ -371,10 +413,12 @@ bool ans_key_h(connection_t *c, const char *request) {
return send_request(to->nexthop->connection, "%s", request);
}
#ifndef DISABLE_LEGACY
/* Don't use key material until every check has passed. */
cipher_close(from->outcipher);
digest_close(from->outdigest);
from->status.validkey = false;
#endif
if (!from->status.sptps) from->status.validkey = false;
if(compression < 0 || compression > 11) {
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
@ -388,9 +432,18 @@ bool ans_key_h(connection_t *c, const char *request) {
if(from->status.sptps) {
char buf[strlen(key)];
int len = b64decode(key, buf, strlen(key));
if(!len || !sptps_receive_data(&from->sptps, buf, len))
logger(DEBUG_ALWAYS, LOG_ERR, "Error processing SPTPS data from %s (%s)", from->name, from->hostname);
if(!len || !sptps_receive_data(&from->sptps, buf, len)) {
/* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
so let's restart SPTPS in case that helps. But don't do that too often
to prevent storms.
Note that simply relying on handshake timeout is not enough, because
that doesn't apply to key regeneration. */
if(from->last_req_key < now.tv_sec - 10) {
logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode handshake TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname);
send_req_key(from);
}
return true;
}
if(from->status.validkey) {
if(*address && *port) {
@ -398,16 +451,17 @@ bool ans_key_h(connection_t *c, const char *request) {
sockaddr_t sa = str2sockaddr(address, port);
update_node_udp(from, &sa);
}
/* Don't send probes if we can't send UDP packets directly to that node.
TODO: the indirect (via) condition can change at any time as edges are added and removed, so this should probably be moved to graph.c. */
if((from->via == myself || from->via == from) && from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
send_mtu_probe(from);
}
send_mtu_info(myself, from, MTU);
return true;
}
#ifdef DISABLE_LEGACY
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses legacy protocol!", from->name, from->hostname);
return false;
#else
/* Check and lookup cipher and digest algorithms */
if(cipher) {
@ -458,8 +512,6 @@ bool ans_key_h(connection_t *c, const char *request) {
update_node_udp(from, &sa);
}
if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
send_mtu_probe(from);
return true;
#endif
}

View file

@ -28,8 +28,15 @@
#include "netutl.h"
#include "protocol.h"
#include "utils.h"
#include "xalloc.h"
#ifndef MIN
#define MIN(x, y) (((x)<(y))?(x):(y))
#endif
int maxoutbufsize = 0;
int mtu_info_interval = 5;
int udp_info_interval = 5;
/* Status and error notification routines */
@ -149,3 +156,229 @@ bool tcppacket_h(connection_t *c, const char *request) {
return true;
}
bool send_sptps_tcppacket(connection_t *c, const char* packet, int len) {
/* If there already is a lot of data in the outbuf buffer, discard this packet.
We use a very simple Random Early Drop algorithm. */
if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
return true;
if(!send_request(c, "%d %d", SPTPS_PACKET, len))
return false;
send_meta_raw(c, packet, len);
return true;
}
bool sptps_tcppacket_h(connection_t *c, const char* request) {
short int len;
if(sscanf(request, "%*d %hd", &len) != 1) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "SPTPS_PACKET", c->name,
c->hostname);
return false;
}
/* Set sptpslen to len, this will tell receive_meta() that a SPTPS packet is coming. */
c->sptpslen = len;
return true;
}
/* Transmitting UDP information */
bool send_udp_info(node_t *from, node_t *to) {
/* If there's a static relay in the path, there's no point in sending the message
farther than the static relay. */
to = (to->via == myself) ? to->nexthop : to->via;
/* Skip cases where sending UDP info messages doesn't make sense.
This is done here in order to avoid repeating the same logic in multiple callsites. */
if(to == myself)
return true;
if(!to->status.reachable)
return true;
if(from == myself) {
if(to->connection)
return true;
struct timeval elapsed;
timersub(&now, &to->udp_info_sent, &elapsed);
if(elapsed.tv_sec < udp_info_interval)
return true;
}
if((myself->options | from->options | to->options) & OPTION_TCPONLY)
return true;
if((to->nexthop->options >> 24) < 5)
return true;
char *from_address, *from_port;
/* If we're the originator, the address we use is irrelevant
because the first intermediate node will ignore it.
We use our local address as it somewhat makes sense
and it's simpler than introducing an encoding for "null" addresses anyway. */
sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port);
bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port);
free(from_address);
free(from_port);
if(from == myself)
to->udp_info_sent = now;
return x;
}
bool udp_info_h(connection_t *c, const char* request) {
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
char from_address[MAX_STRING_SIZE];
char from_port[MAX_STRING_SIZE];
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname);
return false;
}
if(!check_id(from_name) || !check_id(to_name)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name");
return false;
}
node_t *from = lookup_node(from_name);
if(!from) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, from_name);
return true;
}
if(from != from->via) {
/* Not supposed to happen, as it means the message wandered past a static relay */
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname);
return true;
}
/* If we have a direct edge to "from", we are in a better position
to guess its address than it is itself. */
if(!from->connection && !from->status.udp_confirmed) {
sockaddr_t from_addr = str2sockaddr(from_address, from_port);
if(sockaddrcmp(&from_addr, &from->address))
update_node_udp(from, &from_addr);
}
node_t *to = lookup_node(to_name);
if(!to) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, to_name);
return true;
}
/* Send our own data (which could be what we just received) up the chain. */
return send_udp_info(from, to);
}
/* Transmitting MTU information */
bool send_mtu_info(node_t *from, node_t *to, int mtu) {
/* Skip cases where sending MTU info messages doesn't make sense.
This is done here in order to avoid repeating the same logic in multiple callsites. */
if(to == myself)
return true;
if(!to->status.reachable)
return true;
if(from == myself) {
if(to->connection)
return true;
struct timeval elapsed;
timersub(&now, &to->mtu_info_sent, &elapsed);
if(elapsed.tv_sec < mtu_info_interval)
return true;
}
if((to->nexthop->options >> 24) < 6)
return true;
/* We will send the passed-in MTU value, unless we believe ours is better. */
node_t *via = (from->via == myself) ? from->nexthop : from->via;
if(from->minmtu == from->maxmtu && from->via == myself) {
/* We have a direct measurement. Override the value entirely.
Note that we only do that if we are sitting as a static relay in the path;
otherwise, we can't guarantee packets will flow through us, and increasing
MTU could therefore end up being too optimistic. */
mtu = from->minmtu;
} else if(via->minmtu == via->maxmtu) {
/* Static relay. Ensure packets will make it through the entire relay path. */
mtu = MIN(mtu, via->minmtu);
} else if(via->nexthop->minmtu == via->nexthop->maxmtu) {
/* Dynamic relay. Ensure packets will make it through the entire relay path. */
mtu = MIN(mtu, via->nexthop->minmtu);
}
if(from == myself)
to->mtu_info_sent = now;
/* If none of the conditions above match in the steady state, it means we're using TCP,
so the MTU is irrelevant. That said, it is still important to honor the MTU that was passed in,
because other parts of the relay path might be able to use UDP, which means they care about the MTU. */
return send_request(to->nexthop->connection, "%d %s %s %d", MTU_INFO, from->name, to->name, mtu);
}
bool mtu_info_h(connection_t *c, const char* request) {
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
int mtu;
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &mtu) != 3) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "MTU_INFO", c->name, c->hostname);
return false;
}
if(mtu < 512) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid MTU");
return false;
}
mtu = MIN(mtu, MTU);
if(!check_id(from_name) || !check_id(to_name)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid name");
return false;
}
node_t *from = lookup_node(from_name);
if(!from) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, from_name);
return true;
}
/* If we don't know the current MTU for that node, use the one we received.
Even if we're about to make our own measurements, the value we got from downstream nodes should be pretty close
so it's a good idea to use it in the mean time. */
if(from->mtu != mtu && from->minmtu != from->maxmtu) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Using provisional MTU %d for node %s (%s)", mtu, from->name, from->hostname);
from->mtu = mtu;
}
node_t *to = lookup_node(to_name);
if(!to) {
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, to_name);
return true;
}
/* Continue passing the MTU value (or a better one if we have it) up the chain. */
return send_mtu_info(from, to, mtu);
}

View file

@ -105,6 +105,260 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
return true;
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
/* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip = {0};
struct icmp icmp = {0};
struct in_addr ip_src;
struct in_addr ip_dst;
uint32_t oldlen;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
ip_src = ip.ip_src;
ip_dst = ip.ip_dst;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = ip.ip_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
ip_dst = addr.sin_addr;
}
}
close(sockfd);
}
}
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
ip.ip_v = 4;
ip.ip_hl = ip_size / 4;
ip.ip_tos = 0;
ip.ip_len = htons(ip_size + icmp_size + oldlen);
ip.ip_id = 0;
ip.ip_off = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_sum = 0;
ip.ip_src = ip_dst;
ip.ip_dst = ip_src;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
/* Fill in ICMP header */
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip, ip_size);
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet);
}
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
uint16_t checksum;
struct {
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
uint32_t length;
uint32_t next;
} pseudo;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
pseudo.ip6_src = ip6.ip6_dst;
pseudo.ip6_dst = ip6.ip6_src;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) {
int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = ip6.ip6_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
pseudo.ip6_src = addr.sin6_addr;
}
}
close(sockfd);
}
}
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
ip6.ip6_flow = htonl(0x60000000UL);
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_hlim = 255;
ip6.ip6_src = pseudo.ip6_src;
ip6.ip6_dst = pseudo.ip6_dst;
/* Fill in ICMP header */
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
/* Create pseudo header */
pseudo.length = htonl(icmp6_size + pseudo.length);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
send_packet(source, packet);
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
switch (type) {
case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size))
return false;
if(DATA(packet)[ethlen + 8] <= 1) {
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
DATA(packet)[ethlen + 8]--;
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
DATA(packet)[ethlen + 10] = checksum >> 8;
DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size))
return false;
if(DATA(packet)[ethlen + 7] <= 1) {
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
DATA(packet)[ethlen + 7]--;
return true;
default:
return true;
}
}
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
return;
@ -164,7 +418,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
/* Found it */
uint16_t oldmss = DATA(packet)[start + 22 + i] << 8 | DATA(packet)[start + 23 + i];
uint16_t newmss = mtu - start - 20;
uint16_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17];
uint32_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17];
if(oldmss <= newmss)
break;
@ -175,22 +429,17 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
DATA(packet)[start + 22 + i] = newmss >> 8;
DATA(packet)[start + 23 + i] = newmss & 0xff;
csum ^= 0xffff;
csum -= oldmss;
csum += oldmss ^ 0xffff;
csum += newmss;
csum = (csum & 0xffff) + (csum >> 16);
csum += csum >> 16;
csum ^= 0xffff;
DATA(packet)[start + 16] = csum >> 8;
DATA(packet)[start + 17] = csum & 0xff;
DATA(packet)[start + 17] = csum;
break;
}
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
static void age_subnets(void *data) {
bool left = false;
@ -248,77 +497,12 @@ static void learn_mac(mac_t *address) {
}
}
/* RFC 792 */
static void route_broadcast(node_t *source, vpn_packet_t *packet) {
if(decrement_ttl && source != myself)
if(!do_decrement_ttl(source, packet))
return;
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip = {0};
struct icmp icmp = {0};
struct in_addr ip_src;
struct in_addr ip_dst;
uint32_t oldlen;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
ip_src = ip.ip_src;
ip_dst = ip.ip_dst;
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
ip.ip_v = 4;
ip.ip_hl = ip_size / 4;
ip.ip_tos = 0;
ip.ip_len = htons(ip_size + icmp_size + oldlen);
ip.ip_id = 0;
ip.ip_off = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_sum = 0;
ip.ip_src = ip_dst;
ip.ip_dst = ip_src;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
/* Fill in ICMP header */
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip, ip_size);
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet);
broadcast_packet(source, packet);
}
/* RFC 791 */
@ -396,7 +580,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
}
if (!subnet->owner) {
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -411,6 +595,10 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
if(priorityinheritance)
packet->priority = DATA(packet)[15];
@ -441,86 +629,6 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
send_packet(subnet->owner, packet);
}
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
uint16_t checksum;
struct {
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
uint32_t length;
uint32_t next;
} pseudo;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
pseudo.ip6_src = ip6.ip6_dst;
pseudo.ip6_dst = ip6.ip6_src;
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
ip6.ip6_flow = htonl(0x60000000UL);
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_hlim = 255;
ip6.ip6_src = pseudo.ip6_src;
ip6.ip6_dst = pseudo.ip6_dst;
/* Fill in ICMP header */
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
/* Create pseudo header */
pseudo.length = htonl(icmp6_size + pseudo.length);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
send_packet(source, packet);
}
static void route_neighborsol(node_t *source, vpn_packet_t *packet);
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
@ -556,7 +664,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
}
if (!subnet->owner) {
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -571,6 +679,10 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via == source) {
@ -687,6 +799,10 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
if(subnet->owner == myself)
return; /* silently ignore */
if(decrement_ttl)
if(!do_decrement_ttl(source, packet))
return;
/* Create neighbor advertation reply */
memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
@ -782,15 +898,17 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
if(subnet->owner == myself)
return; /* silently ignore */
memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
if(decrement_ttl)
if(!do_decrement_ttl(source, packet))
return;
memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */
memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */
memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */
memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */
memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* set source hard/proto addr */
arp.arp_sha[ETH_ALEN - 1] ^= 0xFF; /* for consistency with route_packet() */
arp.arp_op = htons(ARPOP_REPLY);
/* Copy structs on stack back to packet */
@ -818,7 +936,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet || !subnet->owner) {
broadcast_packet(source, packet);
route_broadcast(source, packet);
return;
}
@ -830,6 +948,10 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
return;
if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet))
return;
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
@ -888,58 +1010,6 @@ static void send_pcap(vpn_packet_t *packet) {
}
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
switch (type) {
case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size))
return false;
if(DATA(packet)[ethlen + 8] < 1) {
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
DATA(packet)[ethlen + 8]--;
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
DATA(packet)[ethlen + 10] = checksum >> 8;
DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size))
return false;
if(DATA(packet)[ethlen + 7] < 1) {
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
DATA(packet)[ethlen + 7]--;
return true;
default:
return true;
}
}
void route(node_t *source, vpn_packet_t *packet) {
if(pcap)
send_pcap(packet);
@ -952,10 +1022,6 @@ void route(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size))
return;
if(decrement_ttl && source != myself)
if(!do_decrement_ttl(source, packet))
return;
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
switch (routing_mode) {
@ -984,7 +1050,7 @@ void route(node_t *source, vpn_packet_t *packet) {
break;
case RMODE_HUB:
broadcast_packet(source, packet);
route_broadcast(source, packet);
break;
}
}

View file

@ -1,7 +1,7 @@
/*
script.c -- call an external script
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
2000-2015 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,21 +26,59 @@
#include "script.h"
#include "xalloc.h"
#ifdef HAVE_PUTENV
static void unputenv(const char *p) {
const char *e = strchr(p, '=');
if(!e)
return;
int len = e - p;
#ifndef HAVE_UNSETENV
#ifdef HAVE_MINGW
// Windows requires putenv("FOO=") to unset %FOO%
len++;
#endif
#endif
char var[len + 1];
strncpy(var, p, len);
var[len] = 0;
#ifdef HAVE_UNSETENV
unsetenv(var);
#else
// We must keep what we putenv() around in memory.
// To do this without memory leaks, keep things in a list and reuse if possible.
static list_t list = {};
for list_each(char, data, &list) {
if(!strcmp(data, var)) {
putenv(data);
return;
}
}
char *data = xstrdup(var);
list_insert_tail(&list, data);
putenv(data);
#endif
}
#else
static void putenv(const char *p) {}
static void unputenv(const char *p) {}
#endif
bool execute_script(const char *name, char **envp) {
#ifdef HAVE_SYSTEM
char *scriptname;
char scriptname[PATH_MAX];
char *command;
xasprintf(&scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension);
snprintf(scriptname, sizeof scriptname, "%s" SLASH "%s%s", confbase, name, scriptextension);
/* First check if there is a script */
#ifdef HAVE_MINGW
if(!*scriptextension) {
const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD";
char fullname[strlen(scriptname) + strlen(pathext)];
char *ext = fullname + strlen(scriptname);
strcpy(fullname, scriptname);
size_t pathlen = strlen(pathext);
size_t scriptlen = strlen(scriptname);
char fullname[scriptlen + pathlen + 1];
char *ext = fullname + scriptlen;
strncpy(fullname, scriptname, sizeof fullname);
const char *p = pathext;
bool found = false;
@ -51,32 +89,26 @@ bool execute_script(const char *name, char **envp) {
ext[q - p] = 0;
q++;
} else {
strcpy(ext, p);
strncpy(ext, p, pathlen + 1);
}
if((found = !access(fullname, F_OK)))
break;
p = q;
}
if(!found) {
free(scriptname);
if(!found)
return true;
}
} else
#endif
if(access(scriptname, F_OK)) {
free(scriptname);
if(access(scriptname, F_OK))
return true;
}
logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name);
#ifdef HAVE_PUTENV
/* Set environment */
for(int i = 0; envp[i]; i++)
putenv(envp[i]);
#endif
if(scriptinterpreter)
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
@ -86,19 +118,11 @@ bool execute_script(const char *name, char **envp) {
int status = system(command);
free(command);
free(scriptname);
/* Unset environment */
for(int i = 0; envp[i]; i++) {
char *e = strchr(envp[i], '=');
if(e) {
char p[e - envp[i] + 1];
strncpy(p, envp[i], e - envp[i]);
p[e - envp[i]] = '\0';
putenv(p);
}
}
for(int i = 0; envp[i]; i++)
unputenv(envp[i]);
if(status != -1) {
#ifdef WEXITSTATUS
@ -121,6 +145,6 @@ bool execute_script(const char *name, char **envp) {
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
return false;
}
#endif
return true;
}

View file

@ -106,6 +106,12 @@ extern splay_node_t *splay_search_closest_greater_node(splay_tree_t *, const voi
extern void splay_foreach(const splay_tree_t *, splay_action_t);
extern void splay_foreach_node(const splay_tree_t *, splay_action_t);
/*
Iterates over a tree.
CAUTION: while this construct supports deleting the current item,
it does *not* support deleting *other* nodes while iterating on the tree.
*/
#define splay_each(type, item, tree) (type *item = (type *)1; item; item = NULL) for(splay_node_t *node = (tree)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
#endif

View file

@ -1,6 +1,6 @@
/*
sptps.c -- Simple Peer-to-Peer Security
Copyright (C) 2011-2014 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2011-2015 Guus Sliepen <guus@tinc-vpn.org>,
2010 Brandon L. Black <blblack@gmail.com>
This program is free software; you can redistribute it and/or modify
@ -204,7 +204,7 @@ static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
// Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
char seed[s->labellen + 64 + 13];
strcpy(seed, "key expansion");
memcpy(seed, "key expansion", 13);
if(s->initiator) {
memcpy(seed + 13, s->mykex + 1, 32);
memcpy(seed + 45, s->hiskex + 1, 32);
@ -384,10 +384,11 @@ static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) {
if (update_state)
s->farfuture++;
if(farfuture)
return error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture);
return update_state ? error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture) : false;
// Unless we have seen lots of them, in which case we consider the others lost.
warning(s, "Lost %d packets\n", seqno - s->inseqno);
if(update_state)
warning(s, "Lost %d packets\n", seqno - s->inseqno);
if (update_state) {
// Mark all packets in the replay window as being late.
memset(s->late, 255, s->replaywin);
@ -395,7 +396,7 @@ static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) {
} else if (seqno < s->inseqno) {
// If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it.
if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8)))
return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno);
return update_state ? error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno) : false;
} else if (update_state) {
// We missed some packets. Mark them in the bitmap as being late.
for(int i = s->inseqno; i < seqno; i++)
@ -447,6 +448,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
uint32_t seqno;
memcpy(&seqno, data, 4);
seqno = ntohl(seqno);
data += 4; len -= 4;
if(!s->instate) {
if(seqno != s->inseqno)
@ -454,39 +456,40 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
s->inseqno = seqno + 1;
uint8_t type = data[4];
uint8_t type = *(data++); len--;
if(type != SPTPS_HANDSHAKE)
return error(s, EIO, "Application record received before handshake finished");
return receive_handshake(s, data + 5, len - 5);
return receive_handshake(s, data, len);
}
// Decrypt
char buffer[len];
size_t outlen;
if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen))
if(!chacha_poly1305_decrypt(s->incipher, seqno, data, len, buffer, &outlen))
return error(s, EIO, "Failed to decrypt and verify packet");
if(!sptps_check_seqno(s, seqno, true))
return false;
// Append a NULL byte for safety.
buffer[len - 20] = 0;
buffer[outlen] = 0;
uint8_t type = buffer[0];
data = buffer;
len = outlen;
uint8_t type = *(data++); len--;
if(type < SPTPS_HANDSHAKE) {
if(!s->instate)
return error(s, EIO, "Application record received before handshake finished");
if(!s->receive_record(s->handle, type, buffer + 1, len - 21))
abort();
if(!s->receive_record(s->handle, type, data, len))
return false;
} else if(type == SPTPS_HANDSHAKE) {
if(!receive_handshake(s, buffer + 1, len - 21))
abort();
if(!receive_handshake(s, data, len))
return false;
} else {
return error(s, EIO, "Invalid record type %d", type);
}
@ -495,90 +498,92 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
}
// Receive incoming data. Check if it contains a complete record, if so, handle it.
bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) {
size_t total_read = 0;
if(!s->state)
return error(s, EIO, "Invalid session state zero");
if(s->datagram)
return sptps_receive_data_datagram(s, data, len);
return sptps_receive_data_datagram(s, data, len) ? len : false;
while(len) {
// First read the 2 length bytes.
if(s->buflen < 2) {
size_t toread = 2 - s->buflen;
if(toread > len)
toread = len;
memcpy(s->inbuf + s->buflen, data, toread);
s->buflen += toread;
len -= toread;
data += toread;
// Exit early if we don't have the full length.
if(s->buflen < 2)
return true;
// Get the length bytes
memcpy(&s->reclen, s->inbuf, 2);
s->reclen = ntohs(s->reclen);
// If we have the length bytes, ensure our buffer can hold the whole request.
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
if(!s->inbuf)
return error(s, errno, strerror(errno));
// Exit early if we have no more data to process.
if(!len)
return true;
}
// Read up to the end of the record.
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
// First read the 2 length bytes.
if(s->buflen < 2) {
size_t toread = 2 - s->buflen;
if(toread > len)
toread = len;
memcpy(s->inbuf + s->buflen, data, toread);
total_read += toread;
s->buflen += toread;
len -= toread;
data += toread;
// If we don't have a whole record, exit.
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
return true;
// Exit early if we don't have the full length.
if(s->buflen < 2)
return total_read;
// Update sequence number.
// Get the length bytes
uint32_t seqno = s->inseqno++;
memcpy(&s->reclen, s->inbuf, 2);
s->reclen = ntohs(s->reclen);
// Check HMAC and decrypt.
if(s->instate) {
if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
return error(s, EINVAL, "Failed to decrypt and verify record");
}
// If we have the length bytes, ensure our buffer can hold the whole request.
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
if(!s->inbuf)
return error(s, errno, strerror(errno));
// Append a NULL byte for safety.
s->inbuf[s->reclen + 3UL] = 0;
uint8_t type = s->inbuf[2];
if(type < SPTPS_HANDSHAKE) {
if(!s->instate)
return error(s, EIO, "Application record received before handshake finished");
if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
return false;
} else if(type == SPTPS_HANDSHAKE) {
if(!receive_handshake(s, s->inbuf + 3, s->reclen))
return false;
} else {
return error(s, EIO, "Invalid record type %d", type);
}
s->buflen = 0;
// Exit early if we have no more data to process.
if(!len)
return total_read;
}
return true;
// Read up to the end of the record.
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
if(toread > len)
toread = len;
memcpy(s->inbuf + s->buflen, data, toread);
total_read += toread;
s->buflen += toread;
len -= toread;
data += toread;
// If we don't have a whole record, exit.
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
return total_read;
// Update sequence number.
uint32_t seqno = s->inseqno++;
// Check HMAC and decrypt.
if(s->instate) {
if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
return error(s, EINVAL, "Failed to decrypt and verify record");
}
// Append a NULL byte for safety.
s->inbuf[s->reclen + 3UL] = 0;
uint8_t type = s->inbuf[2];
if(type < SPTPS_HANDSHAKE) {
if(!s->instate)
return error(s, EIO, "Application record received before handshake finished");
if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
return false;
} else if(type == SPTPS_HANDSHAKE) {
if(!receive_handshake(s, s->inbuf + 3, s->reclen))
return false;
} else {
return error(s, EIO, "Invalid record type %d", type);
}
s->buflen = 0;
return total_read;
}
// Start a SPTPS session.

View file

@ -88,7 +88,7 @@ extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap
extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record);
extern bool sptps_stop(sptps_t *s);
extern bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len);
extern bool sptps_receive_data(sptps_t *s, const void *data, size_t len);
extern size_t sptps_receive_data(sptps_t *s, const void *data, size_t len);
extern bool sptps_force_kex(sptps_t *s);
extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len);

View file

@ -88,7 +88,10 @@ int main(int argc, char *argv[]) {
FILE *fp = fopen(argv[1], "w");
if(fp) {
ecdsa_write_pem_private_key(key, fp);
if(!ecdsa_write_pem_private_key(key, fp)) {
fprintf(stderr, "Could not write ECDSA private key\n");
return 1;
}
fclose(fp);
} else {
fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[1], strerror(errno));
@ -97,7 +100,8 @@ int main(int argc, char *argv[]) {
fp = fopen(argv[2], "w");
if(fp) {
ecdsa_write_pem_public_key(key, fp);
if(!ecdsa_write_pem_public_key(key, fp))
fprintf(stderr, "Could not write ECDSA public key\n");
fclose(fp);
} else {
fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[2], strerror(errno));

View file

@ -33,6 +33,7 @@ bool send_request(void *c, const char *msg, ...) { return false; }
struct list_t *connection_list = NULL;
bool send_meta(void *c, const char *msg , int len) { return false; }
char *logfilename = NULL;
bool do_detach = false;
struct timeval now;
static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
@ -46,11 +47,16 @@ static bool receive_record(void *handle, uint8_t type, const void *data, uint16_
}
static void receive_data(sptps_t *sptps) {
char buf[4096];
char buf[4096], *bufp = buf;
int fd = *(int *)sptps->handle;
size_t len = recv(fd, buf, sizeof buf, 0);
if(!sptps_receive_data(sptps, buf, len))
abort();
while(len) {
size_t done = sptps_receive_data(sptps, bufp, len);
if(!done)
abort();
bufp += done;
len -= done;
}
}
struct timespec start;
@ -101,19 +107,26 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Ed25519 sign for %lg seconds: ", duration);
for(clock_start(); clock_countto(duration);)
ecdsa_sign(key1, buf1, 256, buf2);
fprintf(stderr, "%22.2lf op/s\n", rate);
if(!ecdsa_sign(key1, buf1, 256, buf2))
return 1;
fprintf(stderr, "%20.2lf op/s\n", rate);
fprintf(stderr, "Ed25519 verify for %lg seconds: ", duration);
for(clock_start(); clock_countto(duration);)
ecdsa_verify(key1, buf1, 256, buf2);
fprintf(stderr, "%20.2lf op/s\n", rate);
if(!ecdsa_verify(key1, buf1, 256, buf2)) {
fprintf(stderr, "Signature verification failed\n");
return 1;
}
fprintf(stderr, "%18.2lf op/s\n", rate);
ecdh1 = ecdh_generate_public(buf1);
fprintf(stderr, "ECDH for %lg seconds: ", duration);
for(clock_start(); clock_countto(duration);) {
ecdh2 = ecdh_generate_public(buf2);
ecdh_compute_shared(ecdh2, buf1, buf3);
if(!ecdh2)
return 1;
if(!ecdh_compute_shared(ecdh2, buf1, buf3))
return 1;
}
fprintf(stderr, "%28.2lf op/s\n", rate);
ecdh_free(ecdh1);

View file

@ -35,8 +35,10 @@ bool send_request(void *c, const char *msg, ...) { return false; }
struct list_t *connection_list = NULL;
bool send_meta(void *c, const char *msg , int len) { return false; }
char *logfilename = NULL;
bool do_detach = false;
struct timeval now;
static bool special;
static bool verbose;
static bool readonly;
static bool writeonly;
@ -69,6 +71,7 @@ static struct option const long_options[] = {
{"writeonly", no_argument, NULL, 'w'},
{"packet-loss", required_argument, NULL, 'L'},
{"replay-window", required_argument, NULL, 'W'},
{"special", no_argument, NULL, 's'},
{"verbose", required_argument, NULL, 'v'},
{"help", no_argument, NULL, 1},
{NULL, 0, NULL, 0}
@ -88,6 +91,7 @@ static void usage() {
" -w, --writeonly Only send data from stdin to the socket.\n"
" -L, --packet-loss RATE Fake packet loss of RATE percent.\n"
" -R, --replay-window N Set replay window to N bytes.\n"
" -s, --special Enable special handling of lines starting with #, ^ and $.\n"
" -v, --verbose Display debug messages.\n"
"\n");
fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
@ -106,7 +110,7 @@ int main(int argc, char *argv[]) {
ecdsa_t *mykey = NULL, *hiskey = NULL;
bool quit = false;
while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) {
while((r = getopt_long(argc, argv, "dqrstwL:W:v", long_options, &option_index)) != EOF) {
switch (r) {
case 0: /* long option */
break;
@ -149,6 +153,10 @@ int main(int argc, char *argv[]) {
verbose = true;
break;
case 's': /* special character handling */
special = true;
break;
case '?': /* wrong options */
usage();
return 1;
@ -271,11 +279,19 @@ int main(int argc, char *argv[]) {
crypto_init();
FILE *fp = fopen(argv[1], "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
return 1;
}
if(!(mykey = ecdsa_read_pem_private_key(fp)))
return 1;
fclose(fp);
fp = fopen(argv[2], "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
return 1;
}
if(!(hiskey = ecdsa_read_pem_public_key(fp)))
return 1;
fclose(fp);
@ -315,11 +331,11 @@ int main(int argc, char *argv[]) {
readonly = true;
continue;
}
if(buf[0] == '#')
if(special && buf[0] == '#')
s.outseqno = atoi(buf + 1);
if(buf[0] == '^')
if(special && buf[0] == '^')
sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0);
else if(buf[0] == '$') {
else if(special && buf[0] == '$') {
sptps_force_kex(&s);
if(len > 1)
sptps_send_record(&s, 0, buf, len);
@ -348,8 +364,19 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Dropped.\n");
continue;
}
if(!sptps_receive_data(&s, buf, len) && !datagram)
return 1;
char *bufp = buf;
while(len) {
size_t done = sptps_receive_data(&s, bufp, len);
if(!done) {
if(!datagram)
return 1;
} else {
break;
}
bufp += done;
len -= done;
}
}
}

View file

@ -40,9 +40,9 @@ splay_tree_t *subnet_tree;
/* Subnet lookup cache */
hash_t *ipv4_cache;
hash_t *ipv6_cache;
hash_t *mac_cache;
static hash_t *ipv4_cache;
static hash_t *ipv6_cache;
static hash_t *mac_cache;
void subnet_cache_flush(void) {
hash_clear(ipv4_cache);

View file

@ -22,6 +22,7 @@
#define __TINC_SUBNET_H__
#include "net.h"
#include "node.h"
typedef enum subnet_type_t {
SUBNET_MAC = 0,
@ -44,8 +45,6 @@ typedef struct subnet_ipv6_t {
int prefixlength;
} subnet_ipv6_t;
#include "node.h"
typedef struct subnet_t {
struct node_t *owner; /* the owner of this subnet */

View file

@ -401,11 +401,8 @@ bool net2str(char *netstr, int len, const subnet_t *subnet) {
len -= result;
}
if (subnet->weight != DEFAULT_WEIGHT) {
if (subnet->weight != DEFAULT_WEIGHT)
snprintf(netstr, len, "#%d", subnet->weight);
netstr += result;
len -= result;
}
return true;
}

View file

@ -1,7 +1,7 @@
/*
system.h -- system headers
Copyright (C) 1998-2005 Ivo Timmermans
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,12 +25,6 @@
#include "have.h"
#ifndef HAVE_STDBOOL_H
typedef int bool;
#define true 1
#define false 0
#endif
#ifndef HAVE_STRSIGNAL
# define strsignal(p) ""
#endif
@ -39,8 +33,4 @@ typedef int bool;
#include "dropin.h"
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
#endif /* __TINC_SYSTEM_H__ */

View file

@ -1,6 +1,6 @@
/*
tincctl.c -- Controlling a running tincd
Copyright (C) 2007-2014 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,6 +31,7 @@
#include "control_common.h"
#include "crypto.h"
#include "ecdsagen.h"
#include "fsck.h"
#include "info.h"
#include "invitation.h"
#include "names.h"
@ -66,7 +67,7 @@ char line[4096];
static int code;
static int req;
static int result;
static bool force = false;
bool force = false;
bool tty = true;
bool confbasegiven = false;
bool netnamegiven = false;
@ -87,8 +88,8 @@ static struct option const long_options[] = {
static void version(void) {
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n"
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
"See the AUTHORS file for a complete list.\n\n"
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to redistribute it under certain conditions;\n"
@ -105,6 +106,7 @@ static void usage(bool status) {
" -c, --config=DIR Read configuration options from DIR.\n"
" -n, --net=NETNAME Connect to net NETNAME.\n"
" --pidfile=FILENAME Read control cookie from FILENAME.\n"
" --force Force some commands to work despite warnings.\n"
" --help Display this help and exit.\n"
" --version Output version information and exit.\n"
"\n"
@ -119,8 +121,12 @@ static void usage(bool status) {
" restart [tincd options] Restart tincd.\n"
" reload Partially reload configuration of running tincd.\n"
" pid Show PID of currently running tincd.\n"
#ifdef DISABLE_LEGACY
" generate-keys Generate a new Ed25519 public/private keypair.\n"
#else
" generate-keys [bits] Generate new RSA and Ed25519 public/private keypairs.\n"
" generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n"
#endif
" generate-ed25519-keys Generate a new Ed25519 public/private keypair.\n"
" dump Dump a list of one of the following things:\n"
" [reachable] nodes - all known nodes in the VPN\n"
@ -128,6 +134,7 @@ static void usage(bool status) {
" subnets - all known subnets in the VPN\n"
" connections - all meta connections with ourself\n"
" [di]graph - graph of the VPN in dotty format\n"
" invitations - outstanding invitations\n"
" info NODE|SUBNET|ADDRESS Give information about a particular NODE, SUBNET or ADDRESS.\n"
" purge Purge unreachable nodes\n"
" debug N Set debug level\n"
@ -140,12 +147,15 @@ static void usage(bool status) {
" log [level] Dump log output [up to the specified level]\n"
" export Export host configuration of local node to standard output\n"
" export-all Export all host configuration files to standard output\n"
" import [--force] Import host configuration file(s) from standard input\n"
" exchange [--force] Same as export followed by import\n"
" exchange-all [--force] Same as export-all followed by import\n"
" import Import host configuration file(s) from standard input\n"
" exchange Same as export followed by import\n"
" exchange-all Same as export-all followed by import\n"
" invite NODE [...] Generate an invitation for NODE\n"
" join INVITATION Join a VPN using an INVITIATION\n"
" join INVITATION Join a VPN using an INVITATION\n"
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
" fsck Check the configuration files for problems.\n"
" sign [FILE] Generate a signed version of a file.\n"
" verify NODE [FILE] Verify that a file was signed by the given NODE.\n"
"\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
@ -225,6 +235,12 @@ FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
perms &= ~mask;
umask(~perms);
FILE *f = fopen(filename, mode);
if(!f) {
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
#ifdef HAVE_FCHMOD
if((perms & 0444) && f)
fchmod(fileno(f), perms);
@ -314,7 +330,7 @@ static void disable_old_keys(const char *filename, const char *what) {
static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
FILE *r;
char *directory;
char directory[PATH_MAX] = ".";
char buf[PATH_MAX];
char buf2[PATH_MAX];
@ -342,7 +358,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
if(filename[0] != '/') {
#endif
/* The directory is a relative path or a filename. */
directory = get_current_dir_name();
getcwd(directory, sizeof directory);
snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename);
filename = buf2;
}
@ -368,7 +384,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
static bool ed25519_keygen(bool ask) {
ecdsa_t *key;
FILE *f;
char *pubname, *privname;
char fname[PATH_MAX];
fprintf(stderr, "Generating Ed25519 keypair:\n");
@ -378,29 +394,25 @@ static bool ed25519_keygen(bool ask) {
} else
fprintf(stderr, "Done.\n");
xasprintf(&privname, "%s" SLASH "ed25519_key.priv", confbase);
f = ask_and_open(privname, "private Ed25519 key", "a", ask, 0600);
free(privname);
snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
f = ask_and_open(fname, "private Ed25519 key", "a", ask, 0600);
if(!f)
return false;
goto error;
if(!ecdsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Error writing private key!\n");
ecdsa_free(key);
fclose(f);
return false;
goto error;
}
fclose(f);
if(name)
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
else
xasprintf(&pubname, "%s" SLASH "ed25519_key.pub", confbase);
snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.pub", confbase);
f = ask_and_open(pubname, "public Ed25519 key", "a", ask, 0666);
free(pubname);
f = ask_and_open(fname, "public Ed25519 key", "a", ask, 0666);
if(!f)
return false;
@ -413,8 +425,15 @@ static bool ed25519_keygen(bool ask) {
ecdsa_free(key);
return true;
error:
if(f)
fclose(f);
ecdsa_free(key);
return false;
}
#ifndef DISABLE_LEGACY
/*
Generate a public/private RSA keypair, and ask for a file to store
them in.
@ -422,7 +441,7 @@ static bool ed25519_keygen(bool ask) {
static bool rsa_keygen(int bits, bool ask) {
rsa_t *key;
FILE *f;
char *pubname, *privname;
char fname[PATH_MAX];
// Make sure the key size is a multiple of 8 bits.
bits &= ~0x7;
@ -441,45 +460,46 @@ static bool rsa_keygen(int bits, bool ask) {
} else
fprintf(stderr, "Done.\n");
xasprintf(&privname, "%s" SLASH "rsa_key.priv", confbase);
f = ask_and_open(privname, "private RSA key", "a", ask, 0600);
free(privname);
snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.priv", confbase);
f = ask_and_open(fname, "private RSA key", "a", ask, 0600);
if(!f)
return false;
goto error;
if(!rsa_write_pem_private_key(key, f)) {
fprintf(stderr, "Error writing private key!\n");
fclose(f);
rsa_free(key);
return false;
goto error;
}
fclose(f);
if(name)
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
else
xasprintf(&pubname, "%s" SLASH "rsa_key.pub", confbase);
snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.pub", confbase);
f = ask_and_open(pubname, "public RSA key", "a", ask, 0666);
free(pubname);
f = ask_and_open(fname, "public RSA key", "a", ask, 0666);
if(!f)
return false;
goto error;
if(!rsa_write_pem_public_key(key, f)) {
fprintf(stderr, "Error writing public key!\n");
fclose(f);
rsa_free(key);
return false;
goto error;
}
fclose(f);
rsa_free(key);
return true;
error:
if(f)
fclose(f);
rsa_free(key);
return false;
}
#endif
char buffer[4096];
size_t blen = 0;
@ -842,6 +862,13 @@ static int cmd_start(int argc, char *argv[]) {
}
return status;
#else
int pfd[2] = {-1, -1};
if(socketpair(AF_UNIX, SOCK_STREAM, 0, pfd)) {
fprintf(stderr, "Could not create umbilical socket: %s\n", strerror(errno));
free(nargv);
return 1;
}
pid_t pid = fork();
if(pid == -1) {
fprintf(stderr, "Could not fork: %s\n", strerror(errno));
@ -849,8 +876,15 @@ static int cmd_start(int argc, char *argv[]) {
return 1;
}
if(!pid)
if(!pid) {
close(pfd[0]);
char buf[100] = "";
snprintf(buf, sizeof buf, "%d", pfd[1]);
setenv("TINC_UMBILICAL", buf, true);
exit(execvp(c, nargv));
} else {
close(pfd[1]);
}
free(nargv);
@ -858,12 +892,33 @@ static int cmd_start(int argc, char *argv[]) {
#ifdef SIGINT
signal(SIGINT, SIG_IGN);
#endif
// Pass all log messages from the umbilical to stderr.
// A nul-byte right before closure means tincd started succesfully.
bool failure = true;
char buf[1024];
ssize_t len;
while((len = read(pfd[0], buf, sizeof buf)) > 0) {
failure = buf[len - 1];
if(!failure)
len--;
write(2, buf, len);
}
if(len)
failure = true;
close(pfd[0]);
// Make sure the child process is really gone.
result = waitpid(pid, &status, 0);
#ifdef SIGINT
signal(SIGINT, SIG_DFL);
#endif
if(result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
if(failure || result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
fprintf(stderr, "Error starting %s\n", c);
return 1;
}
@ -934,6 +989,65 @@ static int cmd_reload(int argc, char *argv[]) {
}
static int dump_invitations(void) {
char dname[PATH_MAX];
snprintf(dname, sizeof dname, "%s" SLASH "invitations", confbase);
DIR *dir = opendir(dname);
if(!dir) {
if(errno == ENOENT) {
fprintf(stderr, "No outstanding invitations.\n");
return 0;
}
fprintf(stderr, "Cannot not read directory %s: %s\n", dname, strerror(errno));
return 1;
}
struct dirent *ent;
bool found = false;
while((ent = readdir(dir))) {
char buf[MAX_STRING_SIZE];
if(b64decode(ent->d_name, buf, 24) != 18)
continue;
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ent->d_name);
FILE *f = fopen(fname, "r");
if(!f) {
fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno));
fclose(f);
continue;
}
buf[0] = 0;
if(!fgets(buf, sizeof buf, f)) {
fprintf(stderr, "Invalid invitation file %s", fname);
fclose(f);
continue;
}
fclose(f);
char *eol = buf + strlen(buf);
while(strchr("\t \r\n", *--eol))
*eol = 0;
if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) {
fprintf(stderr, "Invalid invitation file %s", fname);
continue;
}
found = true;
printf("%s %s\n", ent->d_name, buf + 7);
}
closedir(dir);
if(!found)
fprintf(stderr, "No outstanding invitations.\n");
return 0;
}
static int cmd_dump(int argc, char *argv[]) {
bool only_reachable = false;
@ -954,6 +1068,9 @@ static int cmd_dump(int argc, char *argv[]) {
return 1;
}
if(!strcasecmp(argv[1], "invitations"))
return dump_invitations();
if(!connect_tincd(true))
return 1;
@ -1316,6 +1433,29 @@ char *get_my_name(bool verbose) {
return NULL;
}
ecdsa_t *get_pubkey(FILE *f) {
char buf[4096];
char *value;
while(fgets(buf, sizeof buf, f)) {
int len = strcspn(buf, "\t =");
value = buf + len;
value += strspn(value, "\t ");
if(*value == '=') {
value++;
value += strspn(value, "\t ");
}
if(!rstrip(value))
continue;
buf[len] = 0;
if(strcasecmp(buf, "Ed25519PublicKey"))
continue;
if(*value)
return ecdsa_set_base64_public_key(value);
}
return NULL;
}
const var_t variables[] = {
/* Server configuration */
{"AddressFamily", VAR_SERVER},
@ -1358,8 +1498,17 @@ const var_t variables[] = {
{"ScriptsInterpreter", VAR_SERVER},
{"StrictSubnets", VAR_SERVER},
{"TunnelServer", VAR_SERVER},
{"UDPDiscovery", VAR_SERVER},
{"UDPDiscoveryKeepaliveInterval", VAR_SERVER},
{"UDPDiscoveryInterval", VAR_SERVER},
{"UDPDiscoveryTimeout", VAR_SERVER},
{"MTUInfoInterval", VAR_SERVER},
{"UDPInfoInterval", VAR_SERVER},
{"UDPRcvBuf", VAR_SERVER},
{"UDPSndBuf", VAR_SERVER},
{"UPnP", VAR_SERVER},
{"UPnPDiscoverWait", VAR_SERVER},
{"UPnPRefreshPeriod", VAR_SERVER},
{"VDEGroup", VAR_SERVER},
{"VDEPort", VAR_SERVER},
/* Host configuration */
@ -1519,11 +1668,11 @@ static int cmd_config(int argc, char *argv[]) {
}
// Open the right configuration file.
char *filename;
char filename[PATH_MAX];
if(node)
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, node);
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, node);
else
filename = tinc_conf;
snprintf(filename, sizeof filename, "%s", tinc_conf);
FILE *f = fopen(filename, "r");
if(!f) {
@ -1531,11 +1680,11 @@ static int cmd_config(int argc, char *argv[]) {
return 1;
}
char *tmpfile = NULL;
char tmpfile[PATH_MAX];
FILE *tf = NULL;
if(action >= -1) {
xasprintf(&tmpfile, "%s.config.tmp", filename);
snprintf(tmpfile, sizeof tmpfile, "%s.config.tmp", filename);
tf = fopen(tmpfile, "w");
if(!tf) {
fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
@ -1598,6 +1747,11 @@ static int cmd_config(int argc, char *argv[]) {
}
set = true;
continue;
// Add
} else if(action > 0) {
// Check if we've already seen this variable with the same value
if(!strcasecmp(bvalue, value))
found = true;
}
}
@ -1630,7 +1784,7 @@ static int cmd_config(int argc, char *argv[]) {
}
// Add new variable if necessary.
if(action > 0 || (action == 0 && !set)) {
if((action > 0 && !found)|| (action == 0 && !set)) {
if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
return 1;
@ -1679,7 +1833,7 @@ static int cmd_config(int argc, char *argv[]) {
}
static bool try_bind(int port) {
struct addrinfo *ai = NULL;
struct addrinfo *ai = NULL, *aip;
struct addrinfo hint = {
.ai_flags = AI_PASSIVE,
.ai_family = AF_UNSPEC,
@ -1687,24 +1841,30 @@ static bool try_bind(int port) {
.ai_protocol = IPPROTO_TCP,
};
bool success = true;
char portstr[16];
snprintf(portstr, sizeof portstr, "%d", port);
if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
return false;
while(ai) {
for(aip = ai; aip; aip = aip->ai_next) {
int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
if(!fd)
return false;
if(!fd) {
success = false;
break;
}
int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
closesocket(fd);
if(result)
return false;
ai = ai->ai_next;
if(result) {
success = false;
break;
}
}
return true;
freeaddrinfo(ai);
return success;
}
int check_port(char *name) {
@ -1716,11 +1876,11 @@ int check_port(char *name) {
for(int i = 0; i < 100; i++) {
int port = 0x1000 + (rand() & 0x7fff);
if(try_bind(port)) {
char *filename;
xasprintf(&filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
FILE *f = fopen(filename, "a");
free(filename);
if(!f) {
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
fprintf(stderr, "Please change tinc's Port manually.\n");
return 0;
}
@ -1800,14 +1960,19 @@ static int cmd_init(int argc, char *argv[]) {
fprintf(f, "Name = %s\n", name);
fclose(f);
if(!rsa_keygen(2048, false) || !ed25519_keygen(false))
#ifndef DISABLE_LEGACY
if(!rsa_keygen(2048, false))
return 1;
#endif
if(!ed25519_keygen(false))
return 1;
check_port(name);
#ifndef HAVE_MINGW
char *filename;
xasprintf(&filename, "%s" SLASH "tinc-up", confbase);
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up", confbase);
if(access(filename, F_OK)) {
FILE *f = fopenmask(filename, "w", 0777);
if(!f) {
@ -1824,7 +1989,11 @@ static int cmd_init(int argc, char *argv[]) {
}
static int cmd_generate_keys(int argc, char *argv[]) {
#ifdef DISABLE_LEGACY
if(argc > 1) {
#else
if(argc > 2) {
#endif
fprintf(stderr, "Too many arguments!\n");
return 1;
}
@ -1832,9 +2001,18 @@ static int cmd_generate_keys(int argc, char *argv[]) {
if(!name)
name = get_my_name(false);
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true));
#ifndef DISABLE_LEGACY
if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true))
return 1;
#endif
if(!ed25519_keygen(true))
return 1;
return 0;
}
#ifndef DISABLE_LEGACY
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
if(argc > 2) {
fprintf(stderr, "Too many arguments!\n");
@ -1846,6 +2024,7 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) {
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
}
#endif
static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
if(argc > 1) {
@ -1903,12 +2082,12 @@ static int cmd_edit(int argc, char *argv[]) {
return 1;
}
char *filename = NULL;
char filename[PATH_MAX] = "";
if(strncmp(argv[1], "hosts" SLASH, 6)) {
for(int i = 0; conffiles[i]; i++) {
if(!strcmp(argv[1], conffiles[i])) {
xasprintf(&filename, "%s" SLASH "%s", confbase, argv[1]);
snprintf(filename, sizeof filename, "%s" SLASH "%s", confbase, argv[1]);
break;
}
}
@ -1916,8 +2095,8 @@ static int cmd_edit(int argc, char *argv[]) {
argv[1] += 6;
}
if(!filename) {
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, argv[1]);
if(!*filename) {
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, argv[1]);
char *dash = strchr(argv[1], '-');
if(dash) {
*dash++ = 0;
@ -1935,6 +2114,7 @@ static int cmd_edit(int argc, char *argv[]) {
xasprintf(&command, "edit \"%s\"", filename);
#endif
int result = system(command);
free(command);
if(result)
return result;
@ -1946,8 +2126,8 @@ static int cmd_edit(int argc, char *argv[]) {
}
static int export(const char *name, FILE *out) {
char *filename;
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name);
char filename[PATH_MAX];
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
FILE *in = fopen(filename, "r");
if(!in) {
fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
@ -2034,7 +2214,7 @@ static int cmd_import(int argc, char *argv[]) {
char buf[4096];
char name[4096];
char *filename = NULL;
char filename[PATH_MAX] = "";
int count = 0;
bool firstline = true;
@ -2050,8 +2230,7 @@ static int cmd_import(int argc, char *argv[]) {
if(out)
fclose(out);
free(filename);
xasprintf(&filename, "%s" SLASH "%s", hosts_dir, name);
snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
if(!force && !access(filename, F_OK)) {
fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
@ -2105,27 +2284,29 @@ static int cmd_exchange_all(int argc, char *argv[]) {
}
static int switch_network(char *name) {
if(strcmp(name, ".")) {
if(!check_netname(name, false)) {
fprintf(stderr, "Invalid character in netname!\n");
return 1;
}
if(!check_netname(name, true))
fprintf(stderr, "Warning: unsafe character in netname!\n");
}
if(fd >= 0) {
close(fd);
fd = -1;
}
free(confbase);
confbase = NULL;
free(pidfilename);
pidfilename = NULL;
free(logfilename);
logfilename = NULL;
free(unixsocketname);
unixsocketname = NULL;
free_names();
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
make_names(false);
free(tinc_conf);
free(hosts_dir);
free(prompt);
free(netname);
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
make_names();
xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
xasprintf(&prompt, "%s> ", identname);
@ -2158,11 +2339,10 @@ static int cmd_network(int argc, char *argv[]) {
continue;
}
char *fname;
xasprintf(&fname, "%s/%s/tinc.conf", confdir, ent->d_name);
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s/%s/tinc.conf", confdir, ent->d_name);
if(!access(fname, R_OK))
printf("%s\n", ent->d_name);
free(fname);
}
closedir(dir);
@ -2170,6 +2350,240 @@ static int cmd_network(int argc, char *argv[]) {
return 0;
}
static int cmd_fsck(int argc, char *argv[]) {
if(argc > 1) {
fprintf(stderr, "Too many arguments!\n");
return 1;
}
return fsck(orig_argv[0]);
}
static void *readfile(FILE *in, size_t *len) {
size_t count = 0;
size_t alloced = 4096;
char *buf = xmalloc(alloced);
while(!feof(in)) {
size_t read = fread(buf + count, 1, alloced - count, in);
if(!read)
break;
count += read;
if(count >= alloced) {
alloced *= 2;
buf = xrealloc(buf, alloced);
}
}
if(len)
*len = count;
return buf;
}
static int cmd_sign(int argc, char *argv[]) {
if(argc > 2) {
fprintf(stderr, "Too many arguments!\n");
return 1;
}
if(!name) {
name = get_my_name(true);
if(!name)
return 1;
}
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
FILE *fp = fopen(fname, "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
return 1;
}
ecdsa_t *key = ecdsa_read_pem_private_key(fp);
if(!key) {
fprintf(stderr, "Could not read private key from %s\n", fname);
fclose(fp);
return 1;
}
fclose(fp);
FILE *in;
if(argc == 2) {
in = fopen(argv[1], "rb");
if(!in) {
fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
ecdsa_free(key);
return 1;
}
} else {
in = stdin;
}
size_t len;
char *data = readfile(in, &len);
if(in != stdin)
fclose(in);
if(!data) {
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
ecdsa_free(key);
return 1;
}
// Ensure we sign our name and current time as well
long t = time(NULL);
char *trailer;
xasprintf(&trailer, " %s %ld", name, t);
int trailer_len = strlen(trailer);
data = xrealloc(data, len + trailer_len);
memcpy(data + len, trailer, trailer_len);
free(trailer);
char sig[87];
if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
fprintf(stderr, "Error generating signature\n");
free(data);
ecdsa_free(key);
return 1;
}
b64encode(sig, sig, 64);
ecdsa_free(key);
fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
fwrite(data, len, 1, stdout);
free(data);
return 0;
}
static int cmd_verify(int argc, char *argv[]) {
if(argc < 2) {
fprintf(stderr, "Not enough arguments!\n");
return 1;
}
if(argc > 3) {
fprintf(stderr, "Too many arguments!\n");
return 1;
}
char *node = argv[1];
if(!strcmp(node, ".")) {
if(!name) {
name = get_my_name(true);
if(!name)
return 1;
}
node = name;
} else if(!strcmp(node, "*")) {
node = NULL;
} else {
if(!check_id(node)) {
fprintf(stderr, "Invalid node name\n");
return 1;
}
}
FILE *in;
if(argc == 3) {
in = fopen(argv[2], "rb");
if(!in) {
fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
return 1;
}
} else {
in = stdin;
}
size_t len;
char *data = readfile(in, &len);
if(in != stdin)
fclose(in);
if(!data) {
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
return 1;
}
char *newline = memchr(data, '\n', len);
if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
fprintf(stderr, "Invalid input\n");
return 1;
}
*newline++ = '\0';
size_t skip = newline - data;
char signer[MAX_STRING_SIZE] = "";
char sig[MAX_STRING_SIZE] = "";
long t = 0;
if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
fprintf(stderr, "Invalid input\n");
return 1;
}
if(node && strcmp(node, signer)) {
fprintf(stderr, "Signature is not made by %s\n", node);
return 1;
}
if(!node)
node = signer;
char *trailer;
xasprintf(&trailer, " %s %ld", signer, t);
int trailer_len = strlen(trailer);
data = xrealloc(data, len + trailer_len);
memcpy(data + len, trailer, trailer_len);
free(trailer);
newline = data + skip;
char fname[PATH_MAX];
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node);
FILE *fp = fopen(fname, "r");
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
free(data);
return 1;
}
ecdsa_t *key = get_pubkey(fp);
if(!key) {
rewind(fp);
key = ecdsa_read_pem_public_key(fp);
}
if(!key) {
fprintf(stderr, "Could not read public key from %s\n", fname);
fclose(fp);
free(data);
return 1;
}
fclose(fp);
if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
fprintf(stderr, "Invalid signature\n");
free(data);
ecdsa_free(key);
return 1;
}
ecdsa_free(key);
fwrite(newline, len - (newline - data), 1, stdout);
free(data);
return 0;
}
static const struct {
const char *command;
int (*function)(int argc, char *argv[]);
@ -2180,6 +2594,7 @@ static const struct {
{"restart", cmd_restart},
{"reload", cmd_reload},
{"dump", cmd_dump},
{"list", cmd_dump},
{"purge", cmd_purge},
{"debug", cmd_debug},
{"retry", cmd_retry},
@ -2196,7 +2611,9 @@ static const struct {
{"set", cmd_config},
{"init", cmd_init},
{"generate-keys", cmd_generate_keys},
#ifndef DISABLE_LEGACY
{"generate-rsa-keys", cmd_generate_rsa_keys},
#endif
{"generate-ed25519-keys", cmd_generate_ed25519_keys},
{"help", cmd_help},
{"version", cmd_version},
@ -2210,6 +2627,9 @@ static const struct {
{"invite", cmd_invite},
{"join", cmd_join},
{"network", cmd_network},
{"fsck", cmd_fsck},
{"sign", cmd_sign},
{"verify", cmd_verify},
{NULL, NULL},
};
@ -2444,7 +2864,7 @@ int main(int argc, char *argv[]) {
if(!parse_options(argc, argv))
return 1;
make_names();
make_names(false);
xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);

View file

@ -1,6 +1,6 @@
/*
tincctl.h -- header for tincctl.c.
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,6 +21,7 @@
#define __TINC_TINCCTL_H__
extern bool tty;
extern bool force;
extern char line[4096];
extern int fd;
extern char buffer[4096];
@ -49,6 +50,7 @@ extern bool sendline(int fd, char *format, ...);
extern bool recvline(int fd, char *line, size_t len);
extern int check_port(char *name);
extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
extern ecdsa_t *get_pubkey(FILE *f);
#endif

View file

@ -1,7 +1,7 @@
/*
tincd.c -- the main file for tincd
Copyright (C) 1998-2005 Ivo Timmermans
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2008 Max Rijevski <maksuf@gmail.com>
2009 Michael Tokarev <mjt@tls.msk.ru>
2010 Julien Muchembled <jm@jmuchemb.eu>
@ -43,8 +43,6 @@
#include <time.h>
#endif
#include <getopt.h>
#include "conf.h"
#include "control.h"
#include "crypto.h"
@ -85,6 +83,9 @@ static const char *switchuser = NULL;
/* If nonzero, write log entries to a separate file. */
bool use_logfile = false;
/* If nonzero, use syslog instead of stderr in no-detach mode. */
bool use_syslog = false;
char **g_argv; /* a copy of the cmdline arguments */
static int status = 1;
@ -101,6 +102,7 @@ static struct option const long_options[] = {
{"chroot", no_argument, NULL, 'R'},
{"user", required_argument, NULL, 'U'},
{"logfile", optional_argument, NULL, 4},
{"syslog", no_argument, NULL, 's'},
{"pidfile", required_argument, NULL, 5},
{"option", required_argument, NULL, 'o'},
{NULL, 0, NULL, 0}
@ -125,6 +127,7 @@ static void usage(bool status) {
" -L, --mlock Lock tinc into main memory.\n"
#endif
" --logfile[=FILENAME] Write log entries to a logfile.\n"
" -s --syslog Use syslog instead of stderr with --no-detach.\n"
" --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n"
" --bypass-security Disables meta protocol security, for debugging.\n"
" -o, --option[HOST.]KEY=VALUE Set global/host configuration value.\n"
@ -146,7 +149,7 @@ static bool parse_options(int argc, char **argv) {
cmdline_conf = list_alloc((list_action_t)free_config);
while((r = getopt_long(argc, argv, "c:DLd::n:o:RU:", long_options, &option_index)) != EOF) {
while((r = getopt_long(argc, argv, "c:DLd::n:so:RU:", long_options, &option_index)) != EOF) {
switch (r) {
case 0: /* long option */
break;
@ -181,6 +184,11 @@ static bool parse_options(int argc, char **argv) {
netname = xstrdup(optarg);
break;
case 's': /* syslog */
use_logfile = false;
use_syslog = true;
break;
case 'o': /* option */
cfg = parse_config_line(optarg, NULL, ++lineno);
if (!cfg)
@ -216,6 +224,7 @@ static bool parse_options(int argc, char **argv) {
break;
case 4: /* write log entries to a file */
use_syslog = false;
use_logfile = true;
if(!optarg && optind < argc && *argv[optind] != '-')
optarg = argv[optind++];
@ -252,11 +261,14 @@ static bool parse_options(int argc, char **argv) {
netname = NULL;
}
if(netname && (strpbrk(netname, "\\/") || *netname == '.')) {
if(netname && !check_netname(netname, false)) {
fprintf(stderr, "Invalid character in netname!\n");
return false;
}
if(netname && !check_netname(netname, true))
fprintf(stderr, "Warning: unsafe character in netname!\n");
return true;
}
@ -328,12 +340,13 @@ int main(int argc, char **argv) {
if(!parse_options(argc, argv))
return 1;
make_names();
make_names(true);
chdir(confbase);
if(show_version) {
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n"
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
"See the AUTHORS file for a complete list.\n\n"
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
"and you are welcome to redistribute it under certain conditions;\n"
@ -352,6 +365,18 @@ int main(int argc, char **argv) {
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
return 1;
}
#else
// Check if we got an umbilical fd from the process that started us
char *umbstr = getenv("TINC_UMBILICAL");
if(umbstr) {
umbilical = atoi(umbstr);
if(fcntl(umbilical, F_GETFL) < 0)
umbilical = 0;
#ifdef FD_CLOEXEC
if(umbilical)
fcntl(umbilical, F_SETFD, FD_CLOEXEC);
#endif
}
#endif
openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
@ -455,6 +480,12 @@ int main2(int argc, char **argv) {
logger(DEBUG_ALWAYS, LOG_NOTICE, "Ready");
if(umbilical) { // snip!
write(umbilical, "", 1);
close(umbilical);
umbilical = 0;
}
try_outgoing_connections();
status = main_loop();

164
src/upnp.c Normal file
View file

@ -0,0 +1,164 @@
/*
upnp.c -- UPnP-IGD client
Copyright (C) 2015 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 "upnp.h"
#include <pthread.h>
#include "miniupnpc/miniupnpc.h"
#include "miniupnpc/upnpcommands.h"
#include "miniupnpc/upnperrors.h"
#include "system.h"
#include "logger.h"
#include "names.h"
#include "net.h"
#include "netutl.h"
#include "utils.h"
static bool upnp_tcp;
static bool upnp_udp;
static int upnp_discover_wait = 5;
static int upnp_refresh_period = 60;
// Unfortunately, libminiupnpc devs don't seem to care about API compatibility,
// and there are slight changes to function signatures between library versions.
// Well, at least they publish a "MINIUPNPC_API_VERSION" constant, so we got that going for us, which is nice.
// Differences between API versions are documented in "apiversions.txt" in the libminiupnpc distribution.
#ifndef MINIUPNPC_API_VERSION
#define MINIUPNPC_API_VERSION 0
#endif
static struct UPNPDev *upnp_discover(int delay, int *error) {
#if MINIUPNPC_API_VERSION <= 13
#if MINIUPNPC_API_VERSION < 8
#warning "The version of libminiupnpc you're building against seems to be too old. Expect trouble."
#endif
return upnpDiscover(delay, NULL, NULL, false, false, error);
#elif MINIUPNPC_API_VERSION <= 14
return upnpDiscover(delay, NULL NULL, false, false, 2, error);
#else
#if MINIUPNPC_API_VERSION > 15
#warning "The version of libminiupnpc you're building against seems to be too recent. Expect trouble."
#endif
return upnpDiscover(delay, NULL, NULL, UPNP_LOCAL_PORT_ANY, false, 2, error);
#endif
}
static void upnp_add_mapping(struct UPNPUrls *urls, struct IGDdatas *data, const char *myaddr, int socket, const char *proto) {
// Extract the port from the listening socket.
// Note that we can't simply use listen_socket[].sa because this won't have the port
// if we're running with Port=0 (dynamically assigned port).
sockaddr_t sa;
socklen_t salen = sizeof sa;
if (getsockname(socket, &sa.sa, &salen)) {
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket address: [%d] %s", sockerrno, sockstrerror(sockerrno));
return;
}
char *port;
sockaddr2str(&sa, NULL, &port);
if (!port) {
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket port");
return;
}
// Use a lease twice as long as the refresh period so that the mapping won't expire before we refresh.
char lease_duration[16];
snprintf(lease_duration, sizeof lease_duration, "%d", upnp_refresh_period * 2);
int error = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, port, port, myaddr, identname, proto, NULL, lease_duration);
if (error == 0) {
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Successfully set port mapping (%s:%s %s for %s seconds)", myaddr, port, proto, lease_duration);
} else {
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Failed to set port mapping (%s:%s %s for %s seconds): [%d] %s", myaddr, port, proto, lease_duration, error, strupnperror(error));
}
free(port);
}
static void upnp_refresh() {
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Discovering IGD devices");
int error;
struct UPNPDev *devices = upnp_discover(upnp_discover_wait * 1000, &error);
if (!devices) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] Unable to find IGD devices: [%d] %s", error, strupnperror(error));
freeUPNPDevlist(devices);
return;
}
struct UPNPUrls urls;
struct IGDdatas data;
char myaddr[64];
int result = UPNP_GetValidIGD(devices, &urls, &data, myaddr, sizeof myaddr);
if (result <= 0) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] No IGD found");
freeUPNPDevlist(devices);
return;
}
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] IGD found: [%d] %s (local address: %s, service type: %s)", result, urls.controlURL, myaddr, data.first.servicetype);
for (int i = 0; i < listen_sockets; i++) {
if (upnp_tcp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].tcp.fd, "TCP");
if (upnp_udp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].udp.fd, "UDP");
}
FreeUPNPUrls(&urls);
freeUPNPDevlist(devices);
}
static void *upnp_thread(void *data) {
while (true) {
time_t start = time(NULL);
upnp_refresh();
// Make sure we'll stick to the refresh period no matter how long upnp_refresh() takes.
time_t refresh_time = start + upnp_refresh_period;
time_t now = time(NULL);
if (now < refresh_time) sleep(refresh_time - now);
}
// TODO: we don't have a clean thread shutdown procedure, so we can't remove the mapping.
// this is probably not a concern as long as the UPnP device honors the lease duration,
// but considering how bug-riddled these devices often are, that's a big "if".
return NULL;
}
void upnp_init(bool tcp, bool udp) {
upnp_tcp = tcp;
upnp_udp = udp;
get_config_int(lookup_config(config_tree, "UPnPDiscoverWait"), &upnp_discover_wait);
get_config_int(lookup_config(config_tree, "UPnPRefreshPeriod"), &upnp_refresh_period);
pthread_t thread;
int error = pthread_create(&thread, NULL, upnp_thread, NULL);
if (error) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread: [%d] %s", error, strerror(error));
}
}

View file

@ -1,6 +1,6 @@
/*
ecdsagen.c -- ECDSA key generation and export
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
upnp.h -- UPnP-IGD client
Copyright (C) 2015 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
@ -17,25 +17,11 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "../system.h"
#ifndef __UPNP_H__
#define __UPNP_H__
#include "../ecdsagen.h"
#include "../utils.h"
#include "../xalloc.h"
#include "system.h"
// Generate ECDSA key
extern void upnp_init(bool, bool);
ecdsa_t *ecdsa_generate(void) {
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
return NULL;
}
// Write PEM ECDSA keys
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
return false;
}
#endif

View file

@ -158,7 +158,7 @@ int b64encode_urlsafe(const void *src, char *dst, int length) {
const char *winerror(int err) {
static char buf[1024], *ptr;
ptr = buf + sprintf(buf, "(%d) ", err);
ptr = buf + snprintf(buf, sizeof buf, "(%d) ", err);
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) {
@ -191,6 +191,22 @@ bool check_id(const char *id) {
return true;
}
bool check_netname(const char *netname, bool strict) {
if(!netname || !*netname || *netname == '.')
return false;
for(const char *c = netname; *c; c++) {
if(iscntrl(*c))
return false;
if(*c == '/' || *c == '\\')
return false;
if(strict && strchr(" $%<>:`\"|?*", *c))
return false;
}
return true;
}
/* Windows doesn't define HOST_NAME_MAX. */
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255

View file

@ -51,6 +51,7 @@ extern const char *winerror(int);
extern unsigned int bitfield_to_int(const void *bitfield, size_t size);
extern bool check_id(const char *);
extern bool check_netname(const char *, bool strict);
char *replace_name(const char *name);
#endif /* __TINC_UTILS_H__ */

View file

@ -18,7 +18,14 @@
*/
#include "version.h"
#include "version_git.h"
#include "../config.h"
/* This file is always rebuilt (even if there are no changes) so that the following is updated */
const char* const BUILD_DATE = __DATE__;
const char* const BUILD_TIME = __TIME__;
#ifdef GIT_DESCRIPTION
const char* const BUILD_VERSION = GIT_DESCRIPTION;
#else
const char* const BUILD_VERSION = VERSION;
#endif

View file

@ -22,5 +22,6 @@
extern const char* const BUILD_DATE;
extern const char* const BUILD_TIME;
extern const char* const BUILD_VERSION;
#endif /* __TINC_VERSION_H__ */