Import Upstream version 1.1~pre11
This commit is contained in:
parent
60cff3039b
commit
1813f3157e
128 changed files with 10991 additions and 3132 deletions
|
|
@ -1,9 +1,36 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
|
||||
sbin_PROGRAMS = tincd tinc sptps_test
|
||||
sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
|
||||
|
||||
## Make sure version.c is always rebuilt
|
||||
.PHONY: version.c
|
||||
version.c:
|
||||
|
||||
if LINUX
|
||||
sbin_PROGRAMS += sptps_speed
|
||||
endif
|
||||
|
||||
DEFAULT_INCLUDES =
|
||||
|
||||
ed25519_SOURCES = \
|
||||
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_SOURCES = \
|
||||
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
|
||||
|
||||
tincd_SOURCES = \
|
||||
buffer.c buffer.h \
|
||||
cipher.h \
|
||||
|
|
@ -63,7 +90,10 @@ tincd_SOURCES = \
|
|||
system.h \
|
||||
tincd.c \
|
||||
utils.c utils.h \
|
||||
xalloc.h
|
||||
xalloc.h \
|
||||
version.c version.h \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
tinc_SOURCES = \
|
||||
dropin.c dropin.h \
|
||||
|
|
@ -79,13 +109,31 @@ tinc_SOURCES = \
|
|||
subnet_parse.c subnet.h \
|
||||
tincctl.c tincctl.h \
|
||||
top.c top.h \
|
||||
utils.c utils.h
|
||||
utils.c utils.h \
|
||||
version.c version.h \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_test_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_test.c \
|
||||
utils.c utils.h
|
||||
utils.c utils.h \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_keypair_SOURCES = \
|
||||
sptps_keypair.c \
|
||||
utils.c utils.h \
|
||||
$(ed25519_SOURCES)
|
||||
|
||||
sptps_speed_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_speed.c \
|
||||
utils.c utils.h \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
## Conditionally compile device drivers
|
||||
|
||||
|
|
@ -125,26 +173,35 @@ tincd_SOURCES += \
|
|||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/ecdh.c \
|
||||
openssl/ecdsa.c \
|
||||
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 \
|
||||
openssl/ecdh.c \
|
||||
openssl/ecdsa.c \
|
||||
openssl/ecdsagen.c \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/ecdsagen.c \
|
||||
openssl/prf.c \
|
||||
openssl/rsa.c \
|
||||
openssl/rsagen.c
|
||||
sptps_test_SOURCES += \
|
||||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/ecdh.c \
|
||||
openssl/ecdsa.c \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
openssl/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
ed25519/ecdsagen.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
|
||||
|
||||
|
|
@ -177,8 +234,9 @@ sptps_test_SOURCES += \
|
|||
endif
|
||||
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
sptps_speed_LDADD = -lrt
|
||||
|
||||
LIBS = @LIBS@ @LIBGCRYPT_LIBS@
|
||||
LIBS = @LIBS@
|
||||
|
||||
if TUNEMU
|
||||
LIBS += -lpcap
|
||||
|
|
|
|||
373
src/Makefile.in
373
src/Makefile.in
|
|
@ -1,4 +1,4 @@
|
|||
# Makefile.in generated by automake 1.14 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.14.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
|
||||
|
|
@ -78,44 +78,57 @@ PRE_UNINSTALL = :
|
|||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
|
||||
@LINUX_TRUE@am__append_1 = linux/device.c
|
||||
@BSD_TRUE@am__append_2 = bsd/device.c
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c bsd/tunemu.h
|
||||
@SOLARIS_TRUE@am__append_4 = solaris/device.c
|
||||
@MINGW_TRUE@am__append_5 = mingw/device.c mingw/common.h
|
||||
@CYGWIN_TRUE@am__append_6 = cygwin/device.c
|
||||
@UML_TRUE@am__append_7 = uml_device.c
|
||||
@VDE_TRUE@am__append_8 = vde_device.c
|
||||
@OPENSSL_TRUE@am__append_9 = \
|
||||
@OPENSSL_TRUE@ openssl/cipher.c \
|
||||
@OPENSSL_TRUE@ openssl/crypto.c \
|
||||
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
|
||||
@OPENSSL_TRUE@ openssl/ecdh.c \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.c \
|
||||
@OPENSSL_TRUE@ openssl/prf.c \
|
||||
@OPENSSL_TRUE@ openssl/rsa.c
|
||||
|
||||
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 = \
|
||||
@OPENSSL_TRUE@ openssl/cipher.c \
|
||||
@OPENSSL_TRUE@ openssl/crypto.c \
|
||||
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
|
||||
@OPENSSL_TRUE@ openssl/ecdh.c \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.c \
|
||||
@OPENSSL_TRUE@ openssl/ecdsagen.c \
|
||||
@OPENSSL_TRUE@ ed25519/ecdh.c \
|
||||
@OPENSSL_TRUE@ ed25519/ecdsa.c \
|
||||
@OPENSSL_TRUE@ openssl/prf.c \
|
||||
@OPENSSL_TRUE@ openssl/rsa.c \
|
||||
@OPENSSL_TRUE@ openssl/rsagen.c
|
||||
@OPENSSL_TRUE@ openssl/rsa.c
|
||||
|
||||
@OPENSSL_TRUE@am__append_11 = \
|
||||
@OPENSSL_TRUE@ openssl/cipher.c \
|
||||
@OPENSSL_TRUE@ openssl/crypto.c \
|
||||
@OPENSSL_TRUE@ openssl/digest.c openssl/digest.h \
|
||||
@OPENSSL_TRUE@ openssl/ecdh.c \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.c \
|
||||
@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@ 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
|
||||
|
||||
@GCRYPT_TRUE@am__append_12 = \
|
||||
@OPENSSL_TRUE@am__append_13 = \
|
||||
@OPENSSL_TRUE@ openssl/crypto.c \
|
||||
@OPENSSL_TRUE@ ed25519/ecdsagen.c
|
||||
|
||||
@OPENSSL_TRUE@am__append_14 = \
|
||||
@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 \
|
||||
|
|
@ -124,7 +137,7 @@ sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
|
|||
@GCRYPT_TRUE@ gcrypt/prf.c \
|
||||
@GCRYPT_TRUE@ gcrypt/rsa.c
|
||||
|
||||
@GCRYPT_TRUE@am__append_13 = \
|
||||
@GCRYPT_TRUE@am__append_16 = \
|
||||
@GCRYPT_TRUE@ gcrypt/cipher.c \
|
||||
@GCRYPT_TRUE@ gcrypt/crypto.c \
|
||||
@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \
|
||||
|
|
@ -135,7 +148,7 @@ sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
|
|||
@GCRYPT_TRUE@ gcrypt/rsa.c \
|
||||
@GCRYPT_TRUE@ gcrypt/rsagen.c
|
||||
|
||||
@GCRYPT_TRUE@am__append_14 = \
|
||||
@GCRYPT_TRUE@am__append_17 = \
|
||||
@GCRYPT_TRUE@ gcrypt/cipher.c \
|
||||
@GCRYPT_TRUE@ gcrypt/crypto.c \
|
||||
@GCRYPT_TRUE@ gcrypt/digest.c gcrypt/digest.h \
|
||||
|
|
@ -143,60 +156,120 @@ sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT)
|
|||
@GCRYPT_TRUE@ gcrypt/ecdsa.c \
|
||||
@GCRYPT_TRUE@ gcrypt/prf.c
|
||||
|
||||
@TUNEMU_TRUE@am__append_15 = -lpcap
|
||||
@TUNEMU_TRUE@am__append_18 = -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/curses.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/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
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
@LINUX_TRUE@am__EXEEXT_1 = sptps_speed$(EXEEXT)
|
||||
am__installdirs = "$(DESTDIR)$(sbindir)"
|
||||
PROGRAMS = $(sbin_PROGRAMS)
|
||||
am__sptps_test_SOURCES_DIST = logger.c logger.h sptps.c sptps.h \
|
||||
sptps_test.c utils.c utils.h openssl/cipher.c openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h openssl/ecdh.c \
|
||||
openssl/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
|
||||
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/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
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
@OPENSSL_TRUE@am__objects_1 = openssl/cipher.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/ecdh.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT)
|
||||
@GCRYPT_TRUE@am__objects_2 = gcrypt/cipher.$(OBJEXT) \
|
||||
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)
|
||||
am_sptps_keypair_OBJECTS = sptps_keypair.$(OBJEXT) utils.$(OBJEXT) \
|
||||
$(am__objects_1) $(am__objects_2)
|
||||
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 \
|
||||
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) \
|
||||
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)
|
||||
am_sptps_speed_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \
|
||||
sptps_speed.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
|
||||
$(am__objects_3) $(am__objects_4)
|
||||
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 \
|
||||
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)
|
||||
am_sptps_test_OBJECTS = logger.$(OBJEXT) sptps.$(OBJEXT) \
|
||||
sptps_test.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
|
||||
$(am__objects_2)
|
||||
$(am__objects_3) $(am__objects_5) $(am__objects_6)
|
||||
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 openssl/cipher.c openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h openssl/ecdh.c \
|
||||
openssl/ecdsa.c openssl/ecdsagen.c openssl/prf.c openssl/rsa.c \
|
||||
utils.c utils.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 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/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_3 = openssl/cipher.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@am__objects_7 = openssl/cipher.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/ecdh.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/ecdsagen.$(OBJEXT) openssl/prf.$(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/rsa.$(OBJEXT) openssl/rsagen.$(OBJEXT)
|
||||
@GCRYPT_TRUE@am__objects_4 = gcrypt/cipher.$(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) \
|
||||
|
|
@ -205,8 +278,9 @@ am_tinc_OBJECTS = dropin.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
|
|||
info.$(OBJEXT) invitation.$(OBJEXT) list.$(OBJEXT) \
|
||||
names.$(OBJEXT) netutl.$(OBJEXT) script.$(OBJEXT) \
|
||||
sptps.$(OBJEXT) subnet_parse.$(OBJEXT) tincctl.$(OBJEXT) \
|
||||
top.$(OBJEXT) utils.$(OBJEXT) $(am__objects_3) \
|
||||
$(am__objects_4)
|
||||
top.$(OBJEXT) utils.$(OBJEXT) version.$(OBJEXT) \
|
||||
$(am__objects_1) $(am__objects_3) $(am__objects_7) \
|
||||
$(am__objects_8)
|
||||
tinc_OBJECTS = $(am_tinc_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
tinc_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
|
||||
|
|
@ -225,28 +299,37 @@ am__tincd_SOURCES_DIST = buffer.c buffer.h cipher.h conf.c conf.h \
|
|||
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 linux/device.c bsd/device.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 \
|
||||
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 openssl/ecdh.c openssl/ecdsa.c openssl/prf.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_5 = linux/device.$(OBJEXT)
|
||||
@BSD_TRUE@am__objects_6 = bsd/device.$(OBJEXT)
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__objects_7 = bsd/tunemu.$(OBJEXT)
|
||||
@SOLARIS_TRUE@am__objects_8 = solaris/device.$(OBJEXT)
|
||||
@MINGW_TRUE@am__objects_9 = mingw/device.$(OBJEXT)
|
||||
@CYGWIN_TRUE@am__objects_10 = cygwin/device.$(OBJEXT)
|
||||
@UML_TRUE@am__objects_11 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_12 = vde_device.$(OBJEXT)
|
||||
@OPENSSL_TRUE@am__objects_13 = openssl/cipher.$(OBJEXT) \
|
||||
@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) \
|
||||
@OPENSSL_TRUE@ openssl/crypto.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) openssl/ecdh.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/digest.$(OBJEXT) ed25519/ecdh.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ ed25519/ecdsa.$(OBJEXT) openssl/prf.$(OBJEXT) \
|
||||
@OPENSSL_TRUE@ openssl/rsa.$(OBJEXT)
|
||||
@GCRYPT_TRUE@am__objects_14 = gcrypt/cipher.$(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)
|
||||
|
|
@ -265,10 +348,11 @@ am_tincd_OBJECTS = buffer.$(OBJEXT) conf.$(OBJEXT) \
|
|||
raw_socket_device.$(OBJEXT) route.$(OBJEXT) script.$(OBJEXT) \
|
||||
splay_tree.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
|
||||
subnet_parse.$(OBJEXT) tincd.$(OBJEXT) utils.$(OBJEXT) \
|
||||
$(am__objects_5) $(am__objects_6) $(am__objects_7) \
|
||||
$(am__objects_8) $(am__objects_9) $(am__objects_10) \
|
||||
$(am__objects_11) $(am__objects_12) $(am__objects_13) \
|
||||
$(am__objects_14)
|
||||
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) \
|
||||
$(am__objects_15) $(am__objects_16) $(am__objects_17) \
|
||||
$(am__objects_18)
|
||||
tincd_OBJECTS = $(am_tincd_OBJECTS)
|
||||
tincd_LDADD = $(LDADD)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
|
|
@ -298,9 +382,11 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
|||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(sptps_test_SOURCES) $(tinc_SOURCES) $(tincd_SOURCES)
|
||||
DIST_SOURCES = $(am__sptps_test_SOURCES_DIST) $(am__tinc_SOURCES_DIST) \
|
||||
$(am__tincd_SOURCES_DIST)
|
||||
SOURCES = $(sptps_keypair_SOURCES) $(sptps_speed_SOURCES) \
|
||||
$(sptps_test_SOURCES) $(tinc_SOURCES) $(tincd_SOURCES)
|
||||
DIST_SOURCES = $(am__sptps_keypair_SOURCES_DIST) \
|
||||
$(am__sptps_speed_SOURCES_DIST) $(am__sptps_test_SOURCES_DIST) \
|
||||
$(am__tinc_SOURCES_DIST) $(am__tincd_SOURCES_DIST)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
|
|
@ -354,11 +440,8 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
|
||||
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
|
||||
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@ @LIBGCRYPT_LIBS@ $(am__append_15)
|
||||
LIBS = @LIBS@ $(am__append_18)
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
|
|
@ -372,7 +455,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
|||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
READLINE_LIBS = @READLINE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
|
|
@ -429,6 +511,25 @@ top_build_prefix = @top_build_prefix@
|
|||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
DEFAULT_INCLUDES =
|
||||
ed25519_SOURCES = \
|
||||
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_SOURCES = \
|
||||
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
|
||||
|
||||
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 \
|
||||
|
|
@ -444,18 +545,27 @@ tincd_SOURCES = buffer.c buffer.h cipher.h conf.c conf.h connection.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 $(am__append_1) $(am__append_2) \
|
||||
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_12)
|
||||
$(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 \
|
||||
subnet_parse.c subnet.h tincctl.c tincctl.h top.c top.h \
|
||||
utils.c utils.h $(am__append_10) $(am__append_13)
|
||||
utils.c utils.h version.c version.h $(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES) $(am__append_11) $(am__append_16)
|
||||
sptps_test_SOURCES = logger.c logger.h sptps.c sptps.h sptps_test.c \
|
||||
utils.c utils.h $(am__append_11) $(am__append_14)
|
||||
utils.c utils.h $(ed25519_SOURCES) $(chacha_poly1305_SOURCES) \
|
||||
$(am__append_12) $(am__append_17)
|
||||
sptps_keypair_SOURCES = sptps_keypair.c utils.c utils.h \
|
||||
$(ed25519_SOURCES) $(am__append_13)
|
||||
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)
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
sptps_speed_LDADD = -lrt
|
||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
|
||||
all: all-am
|
||||
|
||||
|
|
@ -549,24 +659,69 @@ installcheck-sbinPROGRAMS: $(sbin_PROGRAMS)
|
|||
else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \
|
||||
done; \
|
||||
done; rm -f c$${pid}_.???; exit $$bad
|
||||
ed25519/$(am__dirstamp):
|
||||
@$(MKDIR_P) ed25519
|
||||
@: > ed25519/$(am__dirstamp)
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) ed25519/$(DEPDIR)
|
||||
@: > ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/add_scalar.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/fe.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/ge.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/key_exchange.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/keypair.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/sc.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/sha512.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/sign.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
ed25519/verify.$(OBJEXT): ed25519/$(am__dirstamp) \
|
||||
ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/$(am__dirstamp):
|
||||
@$(MKDIR_P) openssl
|
||||
@: > openssl/$(am__dirstamp)
|
||||
openssl/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) openssl/$(DEPDIR)
|
||||
@: > openssl/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/cipher.$(OBJEXT): openssl/$(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)
|
||||
|
||||
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)
|
||||
chacha-poly1305/$(am__dirstamp):
|
||||
@$(MKDIR_P) chacha-poly1305
|
||||
@: > chacha-poly1305/$(am__dirstamp)
|
||||
chacha-poly1305/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) chacha-poly1305/$(DEPDIR)
|
||||
@: > chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
|
||||
chacha-poly1305/chacha.$(OBJEXT): chacha-poly1305/$(am__dirstamp) \
|
||||
chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
|
||||
chacha-poly1305/chacha-poly1305.$(OBJEXT): \
|
||||
chacha-poly1305/$(am__dirstamp) \
|
||||
chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
|
||||
chacha-poly1305/poly1305.$(OBJEXT): chacha-poly1305/$(am__dirstamp) \
|
||||
chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/digest.$(OBJEXT): openssl/$(am__dirstamp) \
|
||||
openssl/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/ecdh.$(OBJEXT): openssl/$(am__dirstamp) \
|
||||
openssl/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/ecdsa.$(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)
|
||||
|
||||
sptps_speed$(EXEEXT): $(sptps_speed_OBJECTS) $(sptps_speed_DEPENDENCIES) $(EXTRA_sptps_speed_DEPENDENCIES)
|
||||
@rm -f sptps_speed$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(sptps_speed_OBJECTS) $(sptps_speed_LDADD) $(LIBS)
|
||||
gcrypt/$(am__dirstamp):
|
||||
@$(MKDIR_P) gcrypt
|
||||
@: > gcrypt/$(am__dirstamp)
|
||||
|
|
@ -589,7 +744,7 @@ gcrypt/prf.$(OBJEXT): gcrypt/$(am__dirstamp) \
|
|||
sptps_test$(EXEEXT): $(sptps_test_OBJECTS) $(sptps_test_DEPENDENCIES) $(EXTRA_sptps_test_DEPENDENCIES)
|
||||
@rm -f sptps_test$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(sptps_test_OBJECTS) $(sptps_test_LDADD) $(LIBS)
|
||||
openssl/ecdsagen.$(OBJEXT): openssl/$(am__dirstamp) \
|
||||
openssl/cipher.$(OBJEXT): openssl/$(am__dirstamp) \
|
||||
openssl/$(DEPDIR)/$(am__dirstamp)
|
||||
openssl/rsa.$(OBJEXT): openssl/$(am__dirstamp) \
|
||||
openssl/$(DEPDIR)/$(am__dirstamp)
|
||||
|
|
@ -655,7 +810,9 @@ tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIE
|
|||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
-rm -f bsd/*.$(OBJEXT)
|
||||
-rm -f chacha-poly1305/*.$(OBJEXT)
|
||||
-rm -f cygwin/*.$(OBJEXT)
|
||||
-rm -f ed25519/*.$(OBJEXT)
|
||||
-rm -f gcrypt/*.$(OBJEXT)
|
||||
-rm -f linux/*.$(OBJEXT)
|
||||
-rm -f mingw/*.$(OBJEXT)
|
||||
|
|
@ -704,6 +861,8 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splay_tree.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps_keypair.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps_speed.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sptps_test.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet_parse.Po@am__quote@
|
||||
|
|
@ -713,9 +872,25 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/tunemu.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@chacha-poly1305/$(DEPDIR)/chacha-poly1305.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@chacha-poly1305/$(DEPDIR)/chacha.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@chacha-poly1305/$(DEPDIR)/poly1305.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@cygwin/$(DEPDIR)/device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/add_scalar.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/ecdh.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/ecdsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/ecdsagen.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/fe.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/ge.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/key_exchange.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/keypair.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/sc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/sha512.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/sign.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@ed25519/$(DEPDIR)/verify.Po@am__quote@
|
||||
@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@
|
||||
|
|
@ -730,9 +905,6 @@ distclean-compile:
|
|||
@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@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/ecdh.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/ecdsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/ecdsagen.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/prf.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/rsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@openssl/$(DEPDIR)/rsagen.Po@am__quote@
|
||||
|
|
@ -871,8 +1043,12 @@ distclean-generic:
|
|||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-rm -f bsd/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f bsd/$(am__dirstamp)
|
||||
-rm -f chacha-poly1305/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f chacha-poly1305/$(am__dirstamp)
|
||||
-rm -f cygwin/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f cygwin/$(am__dirstamp)
|
||||
-rm -f ed25519/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f ed25519/$(am__dirstamp)
|
||||
-rm -f gcrypt/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f gcrypt/$(am__dirstamp)
|
||||
-rm -f linux/$(DEPDIR)/$(am__dirstamp)
|
||||
|
|
@ -892,7 +1068,7 @@ clean: clean-am
|
|||
clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) cygwin/$(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) openssl/$(DEPDIR) solaris/$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
|
@ -938,7 +1114,7 @@ install-ps-am:
|
|||
installcheck-am: installcheck-sbinPROGRAMS
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR) bsd/$(DEPDIR) cygwin/$(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) openssl/$(DEPDIR) solaris/$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
|
|
@ -973,6 +1149,9 @@ uninstall-am: uninstall-sbinPROGRAMS
|
|||
uninstall-am uninstall-sbinPROGRAMS
|
||||
|
||||
|
||||
.PHONY: version.c
|
||||
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.
|
||||
.NOEXPORT:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#if defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
|
||||
#if defined(HAVE_DARWIN) || defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap0"
|
||||
#else
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tun0"
|
||||
|
|
@ -54,8 +54,6 @@ int device_fd = -1;
|
|||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
#if defined(ENABLE_TUNEMU)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
||||
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD) || defined(HAVE_DRAGONFLY)
|
||||
|
|
@ -65,18 +63,9 @@ static device_type_t device_type = DEVICE_TYPE_TUN;
|
|||
#endif
|
||||
|
||||
static bool setup_device(void) {
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
|
||||
char *type;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
else
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "tun"))
|
||||
/* use default */;
|
||||
|
|
@ -95,10 +84,29 @@ static bool setup_device(void) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER)
|
||||
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER)
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
|
||||
if(!device) {
|
||||
if(device_type == DEVICE_TYPE_TAP)
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
else
|
||||
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);
|
||||
|
||||
switch(device_type) {
|
||||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU: {
|
||||
|
|
@ -199,9 +207,11 @@ static void close_device(void) {
|
|||
default:
|
||||
close(device_fd);
|
||||
}
|
||||
device_fd = -1;
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -212,10 +222,10 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(device_type == DEVICE_TYPE_TUNEMU)
|
||||
inlen = tunemu_read(device_fd, packet->data + 14, MTU - 14);
|
||||
inlen = tunemu_read(device_fd, DATA(packet) + 14, MTU - 14);
|
||||
else
|
||||
#endif
|
||||
inlen = read(device_fd, packet->data + 14, MTU - 14);
|
||||
inlen = read(device_fd, DATA(packet) + 14, MTU - 14);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
|
|
@ -223,29 +233,29 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
switch(packet->data[14] >> 4) {
|
||||
switch(DATA(packet)[14] >> 4) {
|
||||
case 4:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
break;
|
||||
case 6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
break;
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
DATA(packet)[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 14;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
u_int32_t type;
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}};
|
||||
|
||||
if((inlen = readv(device_fd, vector, 2)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
|
|
@ -255,13 +265,13 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
switch (ntohl(type)) {
|
||||
case AF_INET:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -271,13 +281,13 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -290,8 +300,6 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
|
|
@ -304,7 +312,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -313,10 +321,10 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
u_int32_t type;
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, packet->len - 14}};
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}};
|
||||
int af;
|
||||
|
||||
af = (packet->data[12] << 8) + packet->data[13];
|
||||
af = (DATA(packet)[12] << 8) + DATA(packet)[13];
|
||||
|
||||
switch (af) {
|
||||
case 0x0800:
|
||||
|
|
@ -341,7 +349,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -350,7 +358,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
if(tunemu_write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -362,21 +370,12 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
103
src/chacha-poly1305/chacha-poly1305.c
Normal file
103
src/chacha-poly1305/chacha-poly1305.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#include "../system.h"
|
||||
|
||||
#include "../cipher.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#include "chacha.h"
|
||||
#include "chacha-poly1305.h"
|
||||
#include "poly1305.h"
|
||||
|
||||
struct chacha_poly1305_ctx {
|
||||
struct chacha_ctx main_ctx, header_ctx;
|
||||
};
|
||||
|
||||
chacha_poly1305_ctx_t *chacha_poly1305_init(void)
|
||||
{
|
||||
chacha_poly1305_ctx_t *ctx = xzalloc(sizeof *ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void chacha_poly1305_exit(chacha_poly1305_ctx_t *ctx)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key)
|
||||
{
|
||||
chacha_keysetup(&ctx->main_ctx, key, 256);
|
||||
chacha_keysetup(&ctx->header_ctx, key + 32, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void put_u64(void *vp, uint64_t v)
|
||||
{
|
||||
uint8_t *p = (uint8_t *) vp;
|
||||
|
||||
p[0] = (uint8_t) (v >> 56) & 0xff;
|
||||
p[1] = (uint8_t) (v >> 48) & 0xff;
|
||||
p[2] = (uint8_t) (v >> 40) & 0xff;
|
||||
p[3] = (uint8_t) (v >> 32) & 0xff;
|
||||
p[4] = (uint8_t) (v >> 24) & 0xff;
|
||||
p[5] = (uint8_t) (v >> 16) & 0xff;
|
||||
p[6] = (uint8_t) (v >> 8) & 0xff;
|
||||
p[7] = (uint8_t) v & 0xff;
|
||||
}
|
||||
|
||||
bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
|
||||
uint8_t seqbuf[8];
|
||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
||||
uint8_t poly_key[POLY1305_KEYLEN];
|
||||
|
||||
/*
|
||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
||||
* packet sequence number.
|
||||
*/
|
||||
memset(poly_key, 0, sizeof(poly_key));
|
||||
put_u64(seqbuf, seqnr);
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
||||
|
||||
/* Set Chacha's block counter to 1 */
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
||||
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
||||
poly1305_auth(outdata + inlen, outdata, inlen, poly_key);
|
||||
|
||||
if (outlen)
|
||||
*outlen = inlen + POLY1305_TAGLEN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen) {
|
||||
uint8_t seqbuf[8];
|
||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
||||
uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
|
||||
|
||||
/*
|
||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
||||
* packet sequence number.
|
||||
*/
|
||||
memset(poly_key, 0, sizeof(poly_key));
|
||||
put_u64(seqbuf, seqnr);
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
||||
|
||||
/* Set Chacha's block counter to 1 */
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
||||
|
||||
/* Check tag before anything else */
|
||||
inlen -= POLY1305_TAGLEN;
|
||||
const uint8_t *tag = indata + inlen;
|
||||
|
||||
poly1305_auth(expected_tag, indata, inlen, poly_key);
|
||||
if (memcmp(expected_tag, tag, POLY1305_TAGLEN))
|
||||
return false;
|
||||
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
||||
|
||||
if (outlen)
|
||||
*outlen = inlen;
|
||||
|
||||
return true;
|
||||
}
|
||||
15
src/chacha-poly1305/chacha-poly1305.h
Normal file
15
src/chacha-poly1305/chacha-poly1305.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef CHACHA_POLY1305_H
|
||||
#define CHACHA_POLY1305_H
|
||||
|
||||
#define CHACHA_POLY1305_KEYLEN 64
|
||||
|
||||
typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t;
|
||||
|
||||
extern chacha_poly1305_ctx_t *chacha_poly1305_init(void);
|
||||
extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *);
|
||||
extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key);
|
||||
|
||||
extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
extern bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
|
||||
#endif //CHACHA_POLY1305_H
|
||||
215
src/chacha-poly1305/chacha.c
Normal file
215
src/chacha-poly1305/chacha.c
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "chacha.h"
|
||||
|
||||
typedef struct chacha_ctx chacha_ctx;
|
||||
|
||||
#define U8C(v) (v##U)
|
||||
#define U32C(v) (v##U)
|
||||
|
||||
#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
|
||||
#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
|
||||
|
||||
#define ROTL32(v, n) \
|
||||
(U32V((v) << (n)) | ((v) >> (32 - (n))))
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((uint32_t)((p)[0]) ) | \
|
||||
((uint32_t)((p)[1]) << 8) | \
|
||||
((uint32_t)((p)[2]) << 16) | \
|
||||
((uint32_t)((p)[3]) << 24))
|
||||
|
||||
#define U32TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
} while (0)
|
||||
|
||||
#define ROTATE(v,c) (ROTL32(v,c))
|
||||
#define XOR(v,w) ((v) ^ (w))
|
||||
#define PLUS(v,w) (U32V((v) + (w)))
|
||||
#define PLUSONE(v) (PLUS((v),1))
|
||||
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
|
||||
void chacha_keysetup(chacha_ctx *x, const uint8_t *k, uint32_t kbits)
|
||||
{
|
||||
const char *constants;
|
||||
|
||||
x->input[4] = U8TO32_LITTLE(k + 0);
|
||||
x->input[5] = U8TO32_LITTLE(k + 4);
|
||||
x->input[6] = U8TO32_LITTLE(k + 8);
|
||||
x->input[7] = U8TO32_LITTLE(k + 12);
|
||||
if (kbits == 256) { /* recommended */
|
||||
k += 16;
|
||||
constants = sigma;
|
||||
} else { /* kbits == 128 */
|
||||
constants = tau;
|
||||
}
|
||||
x->input[8] = U8TO32_LITTLE(k + 0);
|
||||
x->input[9] = U8TO32_LITTLE(k + 4);
|
||||
x->input[10] = U8TO32_LITTLE(k + 8);
|
||||
x->input[11] = U8TO32_LITTLE(k + 12);
|
||||
x->input[0] = U8TO32_LITTLE(constants + 0);
|
||||
x->input[1] = U8TO32_LITTLE(constants + 4);
|
||||
x->input[2] = U8TO32_LITTLE(constants + 8);
|
||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
||||
}
|
||||
|
||||
void chacha_ivsetup(chacha_ctx *x, const uint8_t *iv, const uint8_t *counter)
|
||||
{
|
||||
x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
|
||||
x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
|
||||
x->input[14] = U8TO32_LITTLE(iv + 0);
|
||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
||||
}
|
||||
|
||||
void
|
||||
chacha_encrypt_bytes(chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes)
|
||||
{
|
||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
uint8_t *ctarget = NULL;
|
||||
uint8_t tmp[64];
|
||||
uint32_t i;
|
||||
|
||||
if (!bytes)
|
||||
return;
|
||||
|
||||
j0 = x->input[0];
|
||||
j1 = x->input[1];
|
||||
j2 = x->input[2];
|
||||
j3 = x->input[3];
|
||||
j4 = x->input[4];
|
||||
j5 = x->input[5];
|
||||
j6 = x->input[6];
|
||||
j7 = x->input[7];
|
||||
j8 = x->input[8];
|
||||
j9 = x->input[9];
|
||||
j10 = x->input[10];
|
||||
j11 = x->input[11];
|
||||
j12 = x->input[12];
|
||||
j13 = x->input[13];
|
||||
j14 = x->input[14];
|
||||
j15 = x->input[15];
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0; i < bytes; ++i)
|
||||
tmp[i] = m[i];
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = 20; i > 0; i -= 2) {
|
||||
QUARTERROUND(x0, x4, x8, x12)
|
||||
QUARTERROUND(x1, x5, x9, x13)
|
||||
QUARTERROUND(x2, x6, x10, x14)
|
||||
QUARTERROUND(x3, x7, x11, x15)
|
||||
QUARTERROUND(x0, x5, x10, x15)
|
||||
QUARTERROUND(x1, x6, x11, x12)
|
||||
QUARTERROUND(x2, x7, x8, x13)
|
||||
QUARTERROUND(x3, x4, x9, x14)
|
||||
}
|
||||
x0 = PLUS(x0, j0);
|
||||
x1 = PLUS(x1, j1);
|
||||
x2 = PLUS(x2, j2);
|
||||
x3 = PLUS(x3, j3);
|
||||
x4 = PLUS(x4, j4);
|
||||
x5 = PLUS(x5, j5);
|
||||
x6 = PLUS(x6, j6);
|
||||
x7 = PLUS(x7, j7);
|
||||
x8 = PLUS(x8, j8);
|
||||
x9 = PLUS(x9, j9);
|
||||
x10 = PLUS(x10, j10);
|
||||
x11 = PLUS(x11, j11);
|
||||
x12 = PLUS(x12, j12);
|
||||
x13 = PLUS(x13, j13);
|
||||
x14 = PLUS(x14, j14);
|
||||
x15 = PLUS(x15, j15);
|
||||
|
||||
x0 = XOR(x0, U8TO32_LITTLE(m + 0));
|
||||
x1 = XOR(x1, U8TO32_LITTLE(m + 4));
|
||||
x2 = XOR(x2, U8TO32_LITTLE(m + 8));
|
||||
x3 = XOR(x3, U8TO32_LITTLE(m + 12));
|
||||
x4 = XOR(x4, U8TO32_LITTLE(m + 16));
|
||||
x5 = XOR(x5, U8TO32_LITTLE(m + 20));
|
||||
x6 = XOR(x6, U8TO32_LITTLE(m + 24));
|
||||
x7 = XOR(x7, U8TO32_LITTLE(m + 28));
|
||||
x8 = XOR(x8, U8TO32_LITTLE(m + 32));
|
||||
x9 = XOR(x9, U8TO32_LITTLE(m + 36));
|
||||
x10 = XOR(x10, U8TO32_LITTLE(m + 40));
|
||||
x11 = XOR(x11, U8TO32_LITTLE(m + 44));
|
||||
x12 = XOR(x12, U8TO32_LITTLE(m + 48));
|
||||
x13 = XOR(x13, U8TO32_LITTLE(m + 52));
|
||||
x14 = XOR(x14, U8TO32_LITTLE(m + 56));
|
||||
x15 = XOR(x15, U8TO32_LITTLE(m + 60));
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
if (!j12) {
|
||||
j13 = PLUSONE(j13);
|
||||
/* stopping at 2^70 bytes per nonce is user's responsibility */
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(c + 0, x0);
|
||||
U32TO8_LITTLE(c + 4, x1);
|
||||
U32TO8_LITTLE(c + 8, x2);
|
||||
U32TO8_LITTLE(c + 12, x3);
|
||||
U32TO8_LITTLE(c + 16, x4);
|
||||
U32TO8_LITTLE(c + 20, x5);
|
||||
U32TO8_LITTLE(c + 24, x6);
|
||||
U32TO8_LITTLE(c + 28, x7);
|
||||
U32TO8_LITTLE(c + 32, x8);
|
||||
U32TO8_LITTLE(c + 36, x9);
|
||||
U32TO8_LITTLE(c + 40, x10);
|
||||
U32TO8_LITTLE(c + 44, x11);
|
||||
U32TO8_LITTLE(c + 48, x12);
|
||||
U32TO8_LITTLE(c + 52, x13);
|
||||
U32TO8_LITTLE(c + 56, x14);
|
||||
U32TO8_LITTLE(c + 60, x15);
|
||||
|
||||
if (bytes <= 64) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0; i < bytes; ++i)
|
||||
ctarget[i] = c[i];
|
||||
}
|
||||
x->input[12] = j12;
|
||||
x->input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
||||
24
src/chacha-poly1305/chacha.h
Normal file
24
src/chacha-poly1305/chacha.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#ifndef CHACHA_H
|
||||
#define CHACHA_H
|
||||
|
||||
struct chacha_ctx {
|
||||
uint32_t input[16];
|
||||
};
|
||||
|
||||
#define CHACHA_MINKEYLEN 16
|
||||
#define CHACHA_NONCELEN 8
|
||||
#define CHACHA_CTRLEN 8
|
||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
||||
#define CHACHA_BLOCKLEN 64
|
||||
|
||||
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits);
|
||||
void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr);
|
||||
void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t * c, uint32_t bytes);
|
||||
|
||||
#endif /* CHACHA_H */
|
||||
197
src/chacha-poly1305/poly1305.c
Normal file
197
src/chacha-poly1305/poly1305.c
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Public Domain poly1305 from Andrew Moon
|
||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "poly1305.h"
|
||||
|
||||
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
|
||||
|
||||
#define U8TO32_LE(p) \
|
||||
(((uint32_t)((p)[0])) | \
|
||||
((uint32_t)((p)[1]) << 8) | \
|
||||
((uint32_t)((p)[2]) << 16) | \
|
||||
((uint32_t)((p)[3]) << 24))
|
||||
|
||||
#define U32TO8_LE(p, v) \
|
||||
do { \
|
||||
(p)[0] = (uint8_t)((v)); \
|
||||
(p)[1] = (uint8_t)((v) >> 8); \
|
||||
(p)[2] = (uint8_t)((v) >> 16); \
|
||||
(p)[3] = (uint8_t)((v) >> 24); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN])
|
||||
{
|
||||
uint32_t t0, t1, t2, t3;
|
||||
uint32_t h0, h1, h2, h3, h4;
|
||||
uint32_t r0, r1, r2, r3, r4;
|
||||
uint32_t s1, s2, s3, s4;
|
||||
uint32_t b, nb;
|
||||
size_t j;
|
||||
uint64_t t[5];
|
||||
uint64_t f0, f1, f2, f3;
|
||||
uint32_t g0, g1, g2, g3, g4;
|
||||
uint64_t c;
|
||||
unsigned char mp[16];
|
||||
|
||||
/* clamp key */
|
||||
t0 = U8TO32_LE(key + 0);
|
||||
t1 = U8TO32_LE(key + 4);
|
||||
t2 = U8TO32_LE(key + 8);
|
||||
t3 = U8TO32_LE(key + 12);
|
||||
|
||||
/* precompute multipliers */
|
||||
r0 = t0 & 0x3ffffff;
|
||||
t0 >>= 26;
|
||||
t0 |= t1 << 6;
|
||||
r1 = t0 & 0x3ffff03;
|
||||
t1 >>= 20;
|
||||
t1 |= t2 << 12;
|
||||
r2 = t1 & 0x3ffc0ff;
|
||||
t2 >>= 14;
|
||||
t2 |= t3 << 18;
|
||||
r3 = t2 & 0x3f03fff;
|
||||
t3 >>= 8;
|
||||
r4 = t3 & 0x00fffff;
|
||||
|
||||
s1 = r1 * 5;
|
||||
s2 = r2 * 5;
|
||||
s3 = r3 * 5;
|
||||
s4 = r4 * 5;
|
||||
|
||||
/* init state */
|
||||
h0 = 0;
|
||||
h1 = 0;
|
||||
h2 = 0;
|
||||
h3 = 0;
|
||||
h4 = 0;
|
||||
|
||||
/* full blocks */
|
||||
if (inlen < 16)
|
||||
goto poly1305_donna_atmost15bytes;
|
||||
|
||||
poly1305_donna_16bytes:
|
||||
m += 16;
|
||||
inlen -= 16;
|
||||
|
||||
t0 = U8TO32_LE(m - 16);
|
||||
t1 = U8TO32_LE(m - 12);
|
||||
t2 = U8TO32_LE(m - 8);
|
||||
t3 = U8TO32_LE(m - 4);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8) | (1 << 24);
|
||||
|
||||
poly1305_donna_mul:
|
||||
t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + mul32x32_64(h3, s2) + mul32x32_64(h4, s1);
|
||||
t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + mul32x32_64(h3, s3) + mul32x32_64(h4, s2);
|
||||
t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + mul32x32_64(h3, s4) + mul32x32_64(h4, s3);
|
||||
t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + mul32x32_64(h3, r0) + mul32x32_64(h4, s4);
|
||||
t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + mul32x32_64(h3, r1) + mul32x32_64(h4, r0);
|
||||
|
||||
h0 = (uint32_t) t[0] & 0x3ffffff;
|
||||
c = (t[0] >> 26);
|
||||
t[1] += c;
|
||||
h1 = (uint32_t) t[1] & 0x3ffffff;
|
||||
b = (uint32_t) (t[1] >> 26);
|
||||
t[2] += b;
|
||||
h2 = (uint32_t) t[2] & 0x3ffffff;
|
||||
b = (uint32_t) (t[2] >> 26);
|
||||
t[3] += b;
|
||||
h3 = (uint32_t) t[3] & 0x3ffffff;
|
||||
b = (uint32_t) (t[3] >> 26);
|
||||
t[4] += b;
|
||||
h4 = (uint32_t) t[4] & 0x3ffffff;
|
||||
b = (uint32_t) (t[4] >> 26);
|
||||
h0 += b * 5;
|
||||
|
||||
if (inlen >= 16)
|
||||
goto poly1305_donna_16bytes;
|
||||
|
||||
/* final bytes */
|
||||
poly1305_donna_atmost15bytes:
|
||||
if (!inlen)
|
||||
goto poly1305_donna_finish;
|
||||
|
||||
for (j = 0; j < inlen; j++)
|
||||
mp[j] = m[j];
|
||||
mp[j++] = 1;
|
||||
for (; j < 16; j++)
|
||||
mp[j] = 0;
|
||||
inlen = 0;
|
||||
|
||||
t0 = U8TO32_LE(mp + 0);
|
||||
t1 = U8TO32_LE(mp + 4);
|
||||
t2 = U8TO32_LE(mp + 8);
|
||||
t3 = U8TO32_LE(mp + 12);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8);
|
||||
|
||||
goto poly1305_donna_mul;
|
||||
|
||||
poly1305_donna_finish:
|
||||
b = h0 >> 26;
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += b;
|
||||
b = h1 >> 26;
|
||||
h1 = h1 & 0x3ffffff;
|
||||
h2 += b;
|
||||
b = h2 >> 26;
|
||||
h2 = h2 & 0x3ffffff;
|
||||
h3 += b;
|
||||
b = h3 >> 26;
|
||||
h3 = h3 & 0x3ffffff;
|
||||
h4 += b;
|
||||
b = h4 >> 26;
|
||||
h4 = h4 & 0x3ffffff;
|
||||
h0 += b * 5;
|
||||
b = h0 >> 26;
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += b;
|
||||
|
||||
g0 = h0 + 5;
|
||||
b = g0 >> 26;
|
||||
g0 &= 0x3ffffff;
|
||||
g1 = h1 + b;
|
||||
b = g1 >> 26;
|
||||
g1 &= 0x3ffffff;
|
||||
g2 = h2 + b;
|
||||
b = g2 >> 26;
|
||||
g2 &= 0x3ffffff;
|
||||
g3 = h3 + b;
|
||||
b = g3 >> 26;
|
||||
g3 &= 0x3ffffff;
|
||||
g4 = h4 + b - (1 << 26);
|
||||
|
||||
b = (g4 >> 31) - 1;
|
||||
nb = ~b;
|
||||
h0 = (h0 & nb) | (g0 & b);
|
||||
h1 = (h1 & nb) | (g1 & b);
|
||||
h2 = (h2 & nb) | (g2 & b);
|
||||
h3 = (h3 & nb) | (g3 & b);
|
||||
h4 = (h4 & nb) | (g4 & b);
|
||||
|
||||
f0 = ((h0) | (h1 << 26)) + (uint64_t) U8TO32_LE(&key[16]);
|
||||
f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t) U8TO32_LE(&key[20]);
|
||||
f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t) U8TO32_LE(&key[24]);
|
||||
f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t) U8TO32_LE(&key[28]);
|
||||
|
||||
U32TO8_LE(&out[0], f0);
|
||||
f1 += (f0 >> 32);
|
||||
U32TO8_LE(&out[4], f1);
|
||||
f2 += (f1 >> 32);
|
||||
U32TO8_LE(&out[8], f2);
|
||||
f3 += (f2 >> 32);
|
||||
U32TO8_LE(&out[12], f3);
|
||||
}
|
||||
16
src/chacha-poly1305/poly1305.h
Normal file
16
src/chacha-poly1305/poly1305.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Public Domain poly1305 from Andrew Moon
|
||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
*/
|
||||
|
||||
#ifndef POLY1305_H
|
||||
#define POLY1305_H
|
||||
|
||||
#define POLY1305_KEYLEN 32
|
||||
#define POLY1305_TAGLEN 16
|
||||
|
||||
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]);
|
||||
|
||||
#endif /* POLY1305_H */
|
||||
|
|
@ -34,11 +34,8 @@ extern size_t cipher_keylength(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__));
|
||||
extern bool cipher_set_counter(cipher_t *, const void *, size_t) __attribute__ ((__warn_unused_result__));
|
||||
extern bool cipher_set_counter_key(cipher_t *, void *) __attribute__ ((__warn_unused_result__));
|
||||
extern bool cipher_encrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__ ((__warn_unused_result__));
|
||||
extern bool cipher_decrypt(cipher_t *, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__ ((__warn_unused_result__));
|
||||
extern bool cipher_counter_xor(cipher_t *, const void *indata, size_t inlen, void *outdata) __attribute__ ((__warn_unused_result__));
|
||||
extern int cipher_get_nid(const cipher_t *);
|
||||
extern bool cipher_active(const cipher_t *);
|
||||
|
||||
|
|
|
|||
30
src/conf.c
30
src/conf.c
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
conf.c -- configuration code
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
1998-2005 Ivo Timmermans
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000 Cris van Pelt
|
||||
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
||||
2000 Cris van Pelt
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2013 Florent Clairambault <florent@clairambault.fr>
|
||||
|
||||
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
|
||||
|
|
@ -376,6 +377,29 @@ bool read_server_config(void) {
|
|||
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);
|
||||
DIR *dir = opendir (dname);
|
||||
// If we can find this dir
|
||||
if (dir) {
|
||||
struct dirent *ep;
|
||||
// We list all the files in it
|
||||
while (x && (ep = readdir (dir))) {
|
||||
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);
|
||||
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));
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
typedef struct connection_status_t {
|
||||
unsigned int pinged:1; /* sent ping */
|
||||
unsigned int active:1; /* 1 if active.. */
|
||||
unsigned int unused_active:1;
|
||||
unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||
unsigned int unused_termreq:1; /* the termination of this connection was requested */
|
||||
unsigned int remove_unused:1; /* Set to 1 if you want this connection removed */
|
||||
|
|
@ -49,7 +49,7 @@ typedef struct connection_status_t {
|
|||
unsigned int log:1; /* 1 if this is a control connection requesting log dump */
|
||||
unsigned int invitation:1; /* 1 if this is an invitation */
|
||||
unsigned int invitation_used:1; /* 1 if the invitation has been consumed */
|
||||
unsigned int unused:19;
|
||||
unsigned int unused:18;
|
||||
} connection_status_t;
|
||||
|
||||
#include "ecdsa.h"
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ bool control_h(connection_t *c, const char *request) {
|
|||
for list_each(connection_t, other, connection_list) {
|
||||
if(strcmp(other->name, name))
|
||||
continue;
|
||||
terminate_connection(other, other->status.active);
|
||||
terminate_connection(other, other->edge);
|
||||
found = true;
|
||||
}
|
||||
|
||||
|
|
@ -178,15 +178,15 @@ bool init_control(void) {
|
|||
#ifndef HAVE_MINGW
|
||||
int unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(unix_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create UNIX socket: %s", sockstrerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create UNIX socket: %s", sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_un sun;
|
||||
sun.sun_family = AF_UNIX;
|
||||
strncpy(sun.sun_path, unixsocketname, sizeof sun.sun_path);
|
||||
struct sockaddr_un sa_un;
|
||||
sa_un.sun_family = AF_UNIX;
|
||||
strncpy(sa_un.sun_path, unixsocketname, sizeof sa_un.sun_path);
|
||||
|
||||
if(connect(unix_fd, (struct sockaddr *)&sun, sizeof sun) >= 0) {
|
||||
if(connect(unix_fd, (struct sockaddr *)&sa_un, sizeof sa_un) >= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UNIX socket %s is still in use!", unixsocketname);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -194,16 +194,16 @@ bool init_control(void) {
|
|||
unlink(unixsocketname);
|
||||
|
||||
umask(mask | 077);
|
||||
int result = bind(unix_fd, (struct sockaddr *)&sun, sizeof sun);
|
||||
int result = bind(unix_fd, (struct sockaddr *)&sa_un, sizeof sa_un);
|
||||
umask(mask);
|
||||
|
||||
if(result < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not bind UNIX socket to %s: %s", unixsocketname, sockstrerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not bind UNIX socket to %s: %s", unixsocketname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(listen(unix_fd, 3) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not listen on UNIX socket %s: %s", unixsocketname, sockstrerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not listen on UNIX socket %s: %s", unixsocketname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-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
|
||||
|
|
@ -40,9 +40,6 @@ char *device = NULL;
|
|||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static pid_t reader_pid;
|
||||
static int sp[2];
|
||||
|
||||
|
|
@ -218,18 +215,19 @@ static bool setup_device(void) {
|
|||
static void close_device(void) {
|
||||
close(sp[0]);
|
||||
close(sp[1]);
|
||||
CloseHandle(device_handle);
|
||||
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
kill(reader_pid, SIGKILL);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
|
||||
if((inlen = read(sp[0], DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -237,8 +235,6 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
packet->len = inlen;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
|
|
@ -251,26 +247,17 @@ 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(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
|
||||
if(!WriteFile (device_handle, DATA(packet), packet->len, &outlen, NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,17 +27,13 @@ extern int device_fd;
|
|||
extern char *device;
|
||||
extern char *iface;
|
||||
|
||||
extern uint64_t device_in_packets;
|
||||
extern uint64_t device_in_bytes;
|
||||
extern uint64_t device_out_packets;
|
||||
extern uint64_t device_out_bytes;
|
||||
|
||||
typedef struct devops_t {
|
||||
bool (*setup)(void);
|
||||
void (*close)(void);
|
||||
bool (*read)(struct vpn_packet_t *);
|
||||
bool (*write)(struct vpn_packet_t *);
|
||||
void (*dump_stats)(void);
|
||||
void (*enable)(void); /* optional */
|
||||
void (*disable)(void); /* optional */
|
||||
} devops_t;
|
||||
|
||||
extern const devops_t os_devops;
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@
|
|||
|
||||
static char *device_info = "dummy device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
device = "dummy";
|
||||
iface = "dummy";
|
||||
|
|
@ -43,20 +40,12 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
device_total_out += packet->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t dummy_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
#ifndef __TINC_ECDH_H__
|
||||
#define __TINC_ECDH_H__
|
||||
|
||||
#define ECDH_SIZE 67
|
||||
#define ECDH_SHARED_SIZE 66
|
||||
#define ECDH_SIZE 32
|
||||
#define ECDH_SHARED_SIZE 32
|
||||
|
||||
#ifndef __TINC_ECDH_INTERNAL__
|
||||
typedef struct ecdh ecdh_t;
|
||||
|
|
|
|||
56
src/ed25519/add_scalar.c
Normal file
56
src/ed25519/add_scalar.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "ed25519.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
/* see http://crypto.stackexchange.com/a/6215/4697 */
|
||||
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
|
||||
const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
|
||||
|
||||
unsigned char n[32];
|
||||
ge_p3 nB;
|
||||
ge_p1p1 A_p1p1;
|
||||
ge_p3 A;
|
||||
ge_p3 public_key_unpacked;
|
||||
ge_cached T;
|
||||
|
||||
int i;
|
||||
|
||||
/* copy the scalar and clear highest bit */
|
||||
for (i = 0; i < 31; ++i) {
|
||||
n[i] = scalar[i];
|
||||
}
|
||||
n[31] = scalar[31] & 127;
|
||||
|
||||
/* private key: a = n + t */
|
||||
if (private_key) {
|
||||
sc_muladd(private_key, SC_1, n, private_key);
|
||||
}
|
||||
|
||||
/* public key: A = nB + T */
|
||||
if (public_key) {
|
||||
/* if we know the private key we don't need a point addition, which is faster */
|
||||
/* using a "timing attack" you could find out wether or not we know the private
|
||||
key, but this information seems rather useless - if this is important pass
|
||||
public_key and private_key seperately in 2 function calls */
|
||||
if (private_key) {
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
} else {
|
||||
/* unpack public key into T */
|
||||
ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
|
||||
fe_neg(public_key_unpacked.X, public_key_unpacked.X); // undo negate
|
||||
fe_neg(public_key_unpacked.T, public_key_unpacked.T); // undo negate
|
||||
ge_p3_to_cached(&T, &public_key_unpacked);
|
||||
|
||||
/* calculate n*B */
|
||||
ge_scalarmult_base(&nB, n);
|
||||
|
||||
/* A = n*B + T */
|
||||
ge_add(&A_p1p1, &nB, &T);
|
||||
ge_p1p1_to_p3(&A, &A_p1p1);
|
||||
}
|
||||
|
||||
/* pack public key */
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
}
|
||||
51
src/ed25519/ecdh.c
Normal file
51
src/ed25519/ecdh.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange 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 "ed25519.h"
|
||||
|
||||
#define __TINC_ECDH_INTERNAL__
|
||||
typedef struct ecdh_t {
|
||||
uint8_t private[64];
|
||||
} ecdh_t;
|
||||
|
||||
#include "../crypto.h"
|
||||
#include "../ecdh.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
ecdh_t *ecdh_generate_public(void *pubkey) {
|
||||
ecdh_t *ecdh = xzalloc(sizeof *ecdh);
|
||||
|
||||
uint8_t seed[32];
|
||||
randomize(seed, sizeof seed);
|
||||
ed25519_create_keypair(pubkey, ecdh->private, seed);
|
||||
|
||||
return ecdh;
|
||||
}
|
||||
|
||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
ed25519_key_exchange(shared, pubkey, ecdh->private);
|
||||
free(ecdh);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ecdh_free(ecdh_t *ecdh) {
|
||||
free(ecdh);
|
||||
}
|
||||
145
src/ed25519/ecdsa.c
Normal file
145
src/ed25519/ecdsa.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
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 "ed25519.h"
|
||||
|
||||
#define __TINC_ECDSA_INTERNAL__
|
||||
typedef struct {
|
||||
uint8_t private[64];
|
||||
uint8_t public[32];
|
||||
} ecdsa_t;
|
||||
|
||||
#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) {
|
||||
int len = strlen(p);
|
||||
|
||||
if(len != 43) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid size %d for public key!", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
|
||||
len = b64decode(p, ecdsa->public, len);
|
||||
if(len != 32) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid format of public key! len = %d", len);
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
||||
char *base64 = xmalloc(44);
|
||||
b64encode(ecdsa->public, base64, sizeof ecdsa->public);
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
// Read PEM ECDSA keys
|
||||
|
||||
static bool read_pem(FILE *fp, const char *type, void *buf, size_t size) {
|
||||
char line[1024];
|
||||
bool data = false;
|
||||
size_t typelen = strlen(type);
|
||||
|
||||
while(fgets(line, sizeof line, fp)) {
|
||||
if(!data) {
|
||||
if(strncmp(line, "-----BEGIN ", 11))
|
||||
continue;
|
||||
if(strncmp(line + 11, type, typelen))
|
||||
continue;
|
||||
data = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(line, "-----END ", 9))
|
||||
break;
|
||||
|
||||
size_t linelen = strcspn(line, "\r\n");
|
||||
size_t len = b64decode(line, line, linelen);
|
||||
if(!len) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(len > size) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(buf, line, len);
|
||||
buf += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
if(size) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
|
||||
if(read_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof ecdsa->public))
|
||||
return ecdsa;
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = xmalloc(sizeof *ecdsa);
|
||||
if(read_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof *ecdsa))
|
||||
return ecdsa;
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
// TODO: standardise output format?
|
||||
|
||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
ed25519_sign(sig, in, len, ecdsa->public, ecdsa->private);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
return ed25519_verify(sig, in, len, ecdsa->public);
|
||||
}
|
||||
|
||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
||||
free(ecdsa);
|
||||
}
|
||||
|
|
@ -19,13 +19,15 @@
|
|||
|
||||
#include "../system.h"
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#include "ed25519.h"
|
||||
|
||||
#define __TINC_ECDSA_INTERNAL__
|
||||
typedef EC_KEY ecdsa_t;
|
||||
typedef struct {
|
||||
uint8_t private[64];
|
||||
uint8_t public[32];
|
||||
} ecdsa_t;
|
||||
|
||||
#include "../crypto.h"
|
||||
#include "../ecdsagen.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
|
@ -33,38 +35,37 @@ typedef EC_KEY ecdsa_t;
|
|||
// Generate ECDSA key
|
||||
|
||||
ecdsa_t *ecdsa_generate(void) {
|
||||
ecdsa_t *ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof *ecdsa);
|
||||
|
||||
if(!ecdsa || !EC_KEY_generate_key(ecdsa)) {
|
||||
fprintf(stderr, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
ecdsa_free(ecdsa);
|
||||
return false;
|
||||
}
|
||||
|
||||
EC_KEY_set_asn1_flag(ecdsa, OPENSSL_EC_NAMED_CURVE);
|
||||
EC_KEY_set_conv_form(ecdsa, POINT_CONVERSION_COMPRESSED);
|
||||
uint8_t seed[32];
|
||||
randomize(seed, sizeof seed);
|
||||
ed25519_create_keypair(ecdsa->public, ecdsa->private, seed);
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
// Write PEM ECDSA keys
|
||||
|
||||
static bool write_pem(FILE *fp, const char *type, void *buf, size_t size) {
|
||||
fprintf(fp, "-----BEGIN %s-----\n", type);
|
||||
|
||||
char base64[65];
|
||||
while(size) {
|
||||
size_t todo = size > 48 ? 48 : size;
|
||||
b64encode(buf, base64, todo);
|
||||
fprintf(fp, "%s\n", base64);
|
||||
buf += todo;
|
||||
size -= todo;
|
||||
}
|
||||
|
||||
fprintf(fp, "-----END %s-----\n", type);
|
||||
return !ferror(fp);
|
||||
}
|
||||
|
||||
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
BIO *out = BIO_new(BIO_s_file());
|
||||
if(!out)
|
||||
return false;
|
||||
BIO_set_fp(out, fp, BIO_NOCLOSE);
|
||||
bool result = PEM_write_bio_EC_PUBKEY(out, ecdsa);
|
||||
BIO_free(out);
|
||||
return result;
|
||||
return write_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof ecdsa->public);
|
||||
}
|
||||
|
||||
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
BIO *out = BIO_new(BIO_s_file());
|
||||
if(!out)
|
||||
return false;
|
||||
BIO_set_fp(out, fp, BIO_NOCLOSE);
|
||||
bool result = PEM_write_bio_ECPrivateKey(out, ecdsa, NULL, NULL, 0, NULL, NULL);
|
||||
BIO_free(out);
|
||||
return result;
|
||||
return write_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof *ecdsa);
|
||||
}
|
||||
38
src/ed25519/ed25519.h
Normal file
38
src/ed25519/ed25519.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(ED25519_BUILD_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllexport)
|
||||
#elif defined(ED25519_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllimport)
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
||||
#endif
|
||||
|
||||
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
||||
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
||||
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);
|
||||
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
|
||||
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1491
src/ed25519/fe.c
Normal file
1491
src/ed25519/fe.c
Normal file
File diff suppressed because it is too large
Load diff
41
src/ed25519/fe.h
Normal file
41
src/ed25519/fe.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef FE_H
|
||||
#define FE_H
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
|
||||
/*
|
||||
fe means field element.
|
||||
Here the field is \Z/(2^255-19).
|
||||
An element t, entries t[0]...t[9], represents the integer
|
||||
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
|
||||
Bounds on each t[i] vary depending on context.
|
||||
*/
|
||||
|
||||
|
||||
typedef int32_t fe[10];
|
||||
|
||||
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
|
||||
void fe_frombytes(fe h, const unsigned char *s);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
|
||||
void fe_copy(fe h, const fe f);
|
||||
int fe_isnegative(const fe f);
|
||||
int fe_isnonzero(const fe f);
|
||||
void fe_cmov(fe f, const fe g, unsigned int b);
|
||||
void fe_cswap(fe f, fe g, unsigned int b);
|
||||
|
||||
void fe_neg(fe h, const fe f);
|
||||
void fe_add(fe h, const fe f, const fe g);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_sq2(fe h, const fe f);
|
||||
void fe_mul(fe h, const fe f, const fe g);
|
||||
void fe_mul121666(fe h, fe f);
|
||||
void fe_pow22523(fe out, const fe z);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
|
||||
#endif
|
||||
70
src/ed25519/fixedint.h
Normal file
70
src/ed25519/fixedint.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Portable header to provide the 32 and 64 bits type.
|
||||
|
||||
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
||||
#include <limits.h>
|
||||
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FIXEDINT_H_INCLUDED
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
/* (u)int32_t */
|
||||
#ifndef uint32_t
|
||||
#if (ULONG_MAX == 0xffffffffUL)
|
||||
typedef unsigned long uint32_t;
|
||||
#elif (UINT_MAX == 0xffffffffUL)
|
||||
typedef unsigned int uint32_t;
|
||||
#elif (USHRT_MAX == 0xffffffffUL)
|
||||
typedef unsigned short uint32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef int32_t
|
||||
#if (LONG_MAX == 0x7fffffffL)
|
||||
typedef signed long int32_t;
|
||||
#elif (INT_MAX == 0x7fffffffL)
|
||||
typedef signed int int32_t;
|
||||
#elif (SHRT_MAX == 0x7fffffffL)
|
||||
typedef signed short int32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* (u)int64_t */
|
||||
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__GNUC__)
|
||||
__extension__ typedef long long int64_t;
|
||||
__extension__ typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##UI64
|
||||
#define INT64_C(v) v ##I64
|
||||
#endif
|
||||
#endif
|
||||
467
src/ed25519/ge.c
Normal file
467
src/ed25519/ge.c
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
#include "ge.h"
|
||||
#include "precomp_data.h"
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YplusX);
|
||||
fe_mul(r->Y, r->Y, q->YminusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
static void slide(signed char *r, const unsigned char *a) {
|
||||
int i;
|
||||
int b;
|
||||
int k;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (r[i]) {
|
||||
for (b = 1; b <= 6 && i + b < 256; ++b) {
|
||||
if (r[i + b]) {
|
||||
if (r[i] + (r[i + b] << b) <= 15) {
|
||||
r[i] += r[i + b] << b;
|
||||
r[i + b] = 0;
|
||||
} else if (r[i] - (r[i + b] << b) >= -15) {
|
||||
r[i] -= r[i + b] << b;
|
||||
|
||||
for (k = i + b; k < 256; ++k) {
|
||||
if (!r[k]) {
|
||||
r[k] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
r[k] = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
r = a * A + b * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
*/
|
||||
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p3 A2;
|
||||
int i;
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_p3_to_cached(&Ai[0], A);
|
||||
ge_p3_dbl(&t, A);
|
||||
ge_p1p1_to_p3(&A2, &t);
|
||||
ge_add(&t, &A2, &Ai[0]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[1], &u);
|
||||
ge_add(&t, &A2, &Ai[1]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[2], &u);
|
||||
ge_add(&t, &A2, &Ai[2]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[3], &u);
|
||||
ge_add(&t, &A2, &Ai[3]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[4], &u);
|
||||
ge_add(&t, &A2, &Ai[4]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[5], &u);
|
||||
ge_add(&t, &A2, &Ai[5]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[6], &u);
|
||||
ge_add(&t, &A2, &Ai[6]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[7], &u);
|
||||
ge_p2_0(r);
|
||||
|
||||
for (i = 255; i >= 0; --i) {
|
||||
if (aslide[i] || bslide[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, r);
|
||||
|
||||
if (aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
||||
} else if (aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
||||
}
|
||||
|
||||
if (bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
||||
} else if (bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
||||
}
|
||||
|
||||
ge_p1p1_to_p2(r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const fe d = {
|
||||
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
||||
};
|
||||
|
||||
static const fe sqrtm1 = {
|
||||
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
||||
};
|
||||
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe v3;
|
||||
fe vxx;
|
||||
fe check;
|
||||
fe_frombytes(h->Y, s);
|
||||
fe_1(h->Z);
|
||||
fe_sq(u, h->Y);
|
||||
fe_mul(v, u, d);
|
||||
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
||||
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(h->X, v3);
|
||||
fe_mul(h->X, h->X, v);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
||||
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
||||
fe_mul(h->X, h->X, v3);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||
fe_sq(vxx, h->X);
|
||||
fe_mul(vxx, vxx, v);
|
||||
fe_sub(check, vxx, u); /* vx^2-u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
fe_add(check, vxx, u); /* vx^2+u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe_mul(h->X, h->X, sqrtm1);
|
||||
}
|
||||
|
||||
if (fe_isnegative(h->X) == (s[31] >> 7)) {
|
||||
fe_neg(h->X, h->X);
|
||||
}
|
||||
|
||||
fe_mul(h->T, h->X, h->Y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yplusx);
|
||||
fe_mul(r->Y, r->Y, q->yminusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yminusx);
|
||||
fe_mul(r->Y, r->Y, q->yplusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
fe_mul(r->T, p->X, p->Y);
|
||||
}
|
||||
|
||||
|
||||
void ge_p2_0(ge_p2 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
||||
fe t0;
|
||||
|
||||
fe_sq(r->X, p->X);
|
||||
fe_sq(r->Z, p->Y);
|
||||
fe_sq2(r->T, p->Z);
|
||||
fe_add(r->Y, p->X, p->Y);
|
||||
fe_sq(t0, r->Y);
|
||||
fe_add(r->Y, r->Z, r->X);
|
||||
fe_sub(r->Z, r->Z, r->X);
|
||||
fe_sub(r->X, t0, r->Y);
|
||||
fe_sub(r->T, r->T, r->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_0(ge_p3 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
fe_0(h->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
||||
ge_p2 q;
|
||||
ge_p3_to_p2(&q, p);
|
||||
ge_p2_dbl(r, &q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
static const fe d2 = {
|
||||
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
||||
};
|
||||
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
||||
fe_add(r->YplusX, p->Y, p->X);
|
||||
fe_sub(r->YminusX, p->Y, p->X);
|
||||
fe_copy(r->Z, p->Z);
|
||||
fe_mul(r->T2d, p->T, d2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
||||
fe_copy(r->X, p->X);
|
||||
fe_copy(r->Y, p->Y);
|
||||
fe_copy(r->Z, p->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char equal(signed char b, signed char c) {
|
||||
unsigned char ub = b;
|
||||
unsigned char uc = c;
|
||||
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
||||
uint64_t y = x; /* 0: yes; 1..255: no */
|
||||
y -= 1; /* large: yes; 0..254: no */
|
||||
y >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) y;
|
||||
}
|
||||
|
||||
static unsigned char negative(signed char b) {
|
||||
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
||||
x >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) x;
|
||||
}
|
||||
|
||||
static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
|
||||
fe_cmov(t->yplusx, u->yplusx, b);
|
||||
fe_cmov(t->yminusx, u->yminusx, b);
|
||||
fe_cmov(t->xy2d, u->xy2d, 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);
|
||||
fe_1(t->yplusx);
|
||||
fe_1(t->yminusx);
|
||||
fe_0(t->xy2d);
|
||||
cmov(t, &base[pos][0], equal(babs, 1));
|
||||
cmov(t, &base[pos][1], equal(babs, 2));
|
||||
cmov(t, &base[pos][2], equal(babs, 3));
|
||||
cmov(t, &base[pos][3], equal(babs, 4));
|
||||
cmov(t, &base[pos][4], equal(babs, 5));
|
||||
cmov(t, &base[pos][5], equal(babs, 6));
|
||||
cmov(t, &base[pos][6], equal(babs, 7));
|
||||
cmov(t, &base[pos][7], equal(babs, 8));
|
||||
fe_copy(minust.yplusx, t->yminusx);
|
||||
fe_copy(minust.yminusx, t->yplusx);
|
||||
fe_neg(minust.xy2d, t->xy2d);
|
||||
cmov(t, &minust, bnegative);
|
||||
}
|
||||
|
||||
/*
|
||||
h = a * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
|
||||
Preconditions:
|
||||
a[31] <= 127
|
||||
*/
|
||||
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
signed char e[64];
|
||||
signed char carry;
|
||||
ge_p1p1 r;
|
||||
ge_p2 s;
|
||||
ge_precomp t;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[2 * i + 0] = (a[i] >> 0) & 15;
|
||||
e[2 * i + 1] = (a[i] >> 4) & 15;
|
||||
}
|
||||
|
||||
/* each e[i] is between 0 and 15 */
|
||||
/* e[63] is between 0 and 7 */
|
||||
carry = 0;
|
||||
|
||||
for (i = 0; i < 63; ++i) {
|
||||
e[i] += carry;
|
||||
carry = e[i] + 8;
|
||||
carry >>= 4;
|
||||
e[i] -= carry << 4;
|
||||
}
|
||||
|
||||
e[63] += carry;
|
||||
/* each e[i] is between -8 and 8 */
|
||||
ge_p3_0(h);
|
||||
|
||||
for (i = 1; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
|
||||
ge_p3_dbl(&r, h);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YminusX);
|
||||
fe_mul(r->Y, r->Y, q->YplusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
74
src/ed25519/ge.h
Normal file
74
src/ed25519/ge.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef GE_H
|
||||
#define GE_H
|
||||
|
||||
#include "fe.h"
|
||||
|
||||
|
||||
/*
|
||||
ge means group element.
|
||||
|
||||
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
where d = -121665/121666.
|
||||
|
||||
Representations:
|
||||
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||
void ge_p2_0(ge_p2 *h);
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
||||
void ge_p3_0(ge_p3 *h);
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
||||
|
||||
#endif
|
||||
79
src/ed25519/key_exchange.c
Normal file
79
src/ed25519/key_exchange.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include "ed25519.h"
|
||||
#include "fe.h"
|
||||
|
||||
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
|
||||
fe x1;
|
||||
fe x2;
|
||||
fe z2;
|
||||
fe x3;
|
||||
fe z3;
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
|
||||
int pos;
|
||||
unsigned int swap;
|
||||
unsigned int b;
|
||||
|
||||
/* copy the private key and make sure it's valid */
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[i] = private_key[i];
|
||||
}
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 63;
|
||||
e[31] |= 64;
|
||||
|
||||
/* unpack the public key and convert edwards to montgomery */
|
||||
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
||||
fe_frombytes(x1, public_key);
|
||||
fe_1(tmp1);
|
||||
fe_add(tmp0, x1, tmp1);
|
||||
fe_sub(tmp1, tmp1, x1);
|
||||
fe_invert(tmp1, tmp1);
|
||||
fe_mul(x1, tmp0, tmp1);
|
||||
|
||||
fe_1(x2);
|
||||
fe_0(z2);
|
||||
fe_copy(x3, x1);
|
||||
fe_1(z3);
|
||||
|
||||
swap = 0;
|
||||
for (pos = 254; pos >= 0; --pos) {
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
b &= 1;
|
||||
swap ^= b;
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
swap = b;
|
||||
|
||||
/* from montgomery.h */
|
||||
fe_sub(tmp0, x3, z3);
|
||||
fe_sub(tmp1, x2, z2);
|
||||
fe_add(x2, x2, z2);
|
||||
fe_add(z2, x3, z3);
|
||||
fe_mul(z3, tmp0, x2);
|
||||
fe_mul(z2, z2, tmp1);
|
||||
fe_sq(tmp0, tmp1);
|
||||
fe_sq(tmp1, x2);
|
||||
fe_add(x3, z3, z2);
|
||||
fe_sub(z2, z3, z2);
|
||||
fe_mul(x2, tmp1, tmp0);
|
||||
fe_sub(tmp1, tmp1, tmp0);
|
||||
fe_sq(z2, z2);
|
||||
fe_mul121666(z3, tmp1);
|
||||
fe_sq(x3, x3);
|
||||
fe_add(tmp0, tmp0, z3);
|
||||
fe_mul(z3, x1, z2);
|
||||
fe_mul(z2, tmp1, tmp0);
|
||||
}
|
||||
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
|
||||
fe_invert(z2, z2);
|
||||
fe_mul(x2, x2, z2);
|
||||
fe_tobytes(shared_secret, x2);
|
||||
}
|
||||
16
src/ed25519/keypair.c
Normal file
16
src/ed25519/keypair.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
|
||||
|
||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
||||
ge_p3 A;
|
||||
|
||||
sha512(seed, 32, private_key);
|
||||
private_key[0] &= 248;
|
||||
private_key[31] &= 63;
|
||||
private_key[31] |= 64;
|
||||
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
1391
src/ed25519/precomp_data.h
Normal file
1391
src/ed25519/precomp_data.h
Normal file
File diff suppressed because it is too large
Load diff
809
src/ed25519/sc.c
Normal file
809
src/ed25519/sc.c
Normal file
|
|
@ -0,0 +1,809 @@
|
|||
#include "fixedint.h"
|
||||
#include "sc.h"
|
||||
|
||||
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;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Input:
|
||||
s[0]+256*s[1]+...+256^63*s[63] = s
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
Overwrites s in place.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
||||
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
||||
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
||||
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
||||
int64_t s16 = 2097151 & load_3(s + 42);
|
||||
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
||||
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
||||
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
||||
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
||||
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
||||
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
||||
int64_t s23 = (load_4(s + 60) >> 3);
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (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[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0 * b0;
|
||||
s1 = c1 + a0 * b1 + a1 * b0;
|
||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||
s21 = a10 * b11 + a11 * b10;
|
||||
s22 = a11 * b11;
|
||||
s23 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1 << 20)) >> 21;
|
||||
s19 += carry18;
|
||||
s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1 << 20)) >> 21;
|
||||
s21 += carry20;
|
||||
s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1 << 20)) >> 21;
|
||||
s23 += carry22;
|
||||
s22 -= carry22 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1 << 20)) >> 21;
|
||||
s18 += carry17;
|
||||
s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1 << 20)) >> 21;
|
||||
s20 += carry19;
|
||||
s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1 << 20)) >> 21;
|
||||
s22 += carry21;
|
||||
s21 -= carry21 << 21;
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (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[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
||||
12
src/ed25519/sc.h
Normal file
12
src/ed25519/sc.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef SC_H
|
||||
#define SC_H
|
||||
|
||||
/*
|
||||
The set of scalars is \Z/l
|
||||
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
|
||||
275
src/ed25519/sha512.c
Normal file
275
src/ed25519/sha512.c
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
||||
*/
|
||||
|
||||
#include "fixedint.h"
|
||||
#include "sha512.h"
|
||||
|
||||
/* the K array */
|
||||
static const uint64_t K[80] = {
|
||||
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
||||
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
||||
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
||||
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
||||
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
||||
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
||||
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
||||
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
||||
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
||||
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
||||
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
||||
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
||||
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
||||
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
||||
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
||||
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
||||
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
||||
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
||||
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(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
||||
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
||||
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
||||
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
||||
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
||||
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
||||
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
||||
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
||||
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
||||
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
||||
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
||||
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
||||
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
||||
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
||||
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
||||
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
||||
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Various logical functions */
|
||||
|
||||
#define ROR64c(x, y) \
|
||||
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
||||
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
#define STORE64H(x, y) \
|
||||
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
||||
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
||||
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
||||
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
||||
|
||||
#define LOAD64H(x, y) \
|
||||
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
||||
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
||||
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
||||
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
||||
|
||||
|
||||
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#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))
|
||||
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
||||
#endif
|
||||
|
||||
/* compress 1024-bits */
|
||||
static int sha512_compress(sha512_context *md, unsigned char *buf)
|
||||
{
|
||||
uint64_t S[8], W[80], t0, t1;
|
||||
int i;
|
||||
|
||||
/* copy state into S */
|
||||
for (i = 0; i < 8; i++) {
|
||||
S[i] = md->state[i];
|
||||
}
|
||||
|
||||
/* copy the state into 1024-bits into W[0..15] */
|
||||
for (i = 0; i < 16; i++) {
|
||||
LOAD64H(W[i], buf + (8*i));
|
||||
}
|
||||
|
||||
/* 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) \
|
||||
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||
t1 = Sigma0(a) + Maj(a, b, c);\
|
||||
d += t0; \
|
||||
h = t0 + t1;
|
||||
|
||||
for (i = 0; i < 80; i += 8) {
|
||||
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
|
||||
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
|
||||
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
|
||||
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
|
||||
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
|
||||
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
|
||||
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
|
||||
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
|
||||
}
|
||||
|
||||
#undef RND
|
||||
|
||||
|
||||
|
||||
/* feedback */
|
||||
for (i = 0; i < 8; i++) {
|
||||
md->state[i] = md->state[i] + S[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the hash state
|
||||
@param md The hash state you wish to initialize
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_init(sha512_context * md) {
|
||||
if (md == NULL) return 1;
|
||||
|
||||
md->curlen = 0;
|
||||
md->length = 0;
|
||||
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
||||
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
||||
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
||||
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
||||
md->state[4] = UINT64_C(0x510e527fade682d1);
|
||||
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
||||
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
||||
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Process a block of memory though the hash
|
||||
@param md The hash state
|
||||
@param in The data to hash
|
||||
@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)
|
||||
{
|
||||
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 {
|
||||
n = MIN(inlen, (128 - md->curlen));
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
md->buf[i + md->curlen] = in[i];
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the hash to get the digest
|
||||
@param md The hash state
|
||||
@param out [out] The destination of the hash (64 bytes)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_final(sha512_context * md, unsigned char *out)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (md == NULL) return 1;
|
||||
if (out == NULL) return 1;
|
||||
|
||||
if (md->curlen >= sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* increase the length of the message */
|
||||
md->length += md->curlen * UINT64_C(8);
|
||||
|
||||
/* append the '1' bit */
|
||||
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
|
||||
* encoding like normal.
|
||||
*/
|
||||
if (md->curlen > 112) {
|
||||
while (md->curlen < 128) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
sha512_compress(md, md->buf);
|
||||
md->curlen = 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* store length */
|
||||
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));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
|
||||
{
|
||||
sha512_context ctx;
|
||||
int ret;
|
||||
if ((ret = sha512_init(&ctx))) return ret;
|
||||
if ((ret = sha512_update(&ctx, message, message_len))) return ret;
|
||||
if ((ret = sha512_final(&ctx, out))) return ret;
|
||||
return 0;
|
||||
}
|
||||
21
src/ed25519/sha512.h
Normal file
21
src/ed25519/sha512.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
/* state */
|
||||
typedef struct sha512_context_ {
|
||||
uint64_t length, state[8];
|
||||
size_t curlen;
|
||||
unsigned char buf[128];
|
||||
} 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);
|
||||
|
||||
#endif
|
||||
31
src/ed25519/sign.c
Normal file
31
src/ed25519/sign.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
sha512_context hash;
|
||||
unsigned char hram[64];
|
||||
unsigned char r[64];
|
||||
ge_p3 R;
|
||||
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, private_key + 32, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, r);
|
||||
|
||||
sc_reduce(r);
|
||||
ge_scalarmult_base(&R, r);
|
||||
ge_p3_tobytes(signature, &R);
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, hram);
|
||||
|
||||
sc_reduce(hram);
|
||||
sc_muladd(signature + 32, hram, private_key, r);
|
||||
}
|
||||
77
src/ed25519/verify.c
Normal file
77
src/ed25519/verify.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
||||
unsigned char r = 0;
|
||||
|
||||
r = x[0] ^ y[0];
|
||||
#define F(i) r |= x[i] ^ y[i]
|
||||
F(1);
|
||||
F(2);
|
||||
F(3);
|
||||
F(4);
|
||||
F(5);
|
||||
F(6);
|
||||
F(7);
|
||||
F(8);
|
||||
F(9);
|
||||
F(10);
|
||||
F(11);
|
||||
F(12);
|
||||
F(13);
|
||||
F(14);
|
||||
F(15);
|
||||
F(16);
|
||||
F(17);
|
||||
F(18);
|
||||
F(19);
|
||||
F(20);
|
||||
F(21);
|
||||
F(22);
|
||||
F(23);
|
||||
F(24);
|
||||
F(25);
|
||||
F(26);
|
||||
F(27);
|
||||
F(28);
|
||||
F(29);
|
||||
F(30);
|
||||
F(31);
|
||||
#undef F
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
||||
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
||||
unsigned char h[64];
|
||||
unsigned char checker[32];
|
||||
sha512_context hash;
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
|
||||
if (signature[63] & 224) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, h);
|
||||
|
||||
sc_reduce(h);
|
||||
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
||||
ge_tobytes(checker, &R);
|
||||
|
||||
if (!consttime_equal(checker, signature)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -110,11 +110,13 @@ bool dump_edges(connection_t *c) {
|
|||
for splay_each(node_t, n, node_tree) {
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
char *address = sockaddr2hostname(&e->address);
|
||||
send_request(c, "%d %d %s %s %s %x %d",
|
||||
char* local_address = sockaddr2hostname(&e->local_address);
|
||||
send_request(c, "%d %d %s %s %s %s %x %d",
|
||||
CONTROL, REQ_DUMP_EDGES,
|
||||
e->from->name, e->to->name, address,
|
||||
e->options, e->weight);
|
||||
local_address, e->options, e->weight);
|
||||
free(address);
|
||||
free(local_address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ typedef struct edge_t {
|
|||
struct node_t *from;
|
||||
struct node_t *to;
|
||||
sockaddr_t address;
|
||||
sockaddr_t local_address;
|
||||
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
|
|
|
|||
173
src/event.c
173
src/event.c
|
|
@ -23,15 +23,26 @@
|
|||
#include "event.h"
|
||||
#include "net.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
struct timeval now;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static fd_set readfds;
|
||||
static fd_set writefds;
|
||||
static volatile bool running;
|
||||
#else
|
||||
static const long READ_EVENTS = FD_READ | FD_ACCEPT | FD_CLOSE;
|
||||
static const long WRITE_EVENTS = FD_WRITE | FD_CONNECT;
|
||||
static DWORD event_count = 0;
|
||||
#endif
|
||||
static bool running;
|
||||
|
||||
static int io_compare(const io_t *a, const io_t *b) {
|
||||
#ifndef HAVE_MINGW
|
||||
return a->fd - b->fd;
|
||||
#else
|
||||
return a->event - b->event;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int timeout_compare(const timeout_t *a, const timeout_t *b) {
|
||||
|
|
@ -60,6 +71,14 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
|
|||
return;
|
||||
|
||||
io->fd = fd;
|
||||
#ifdef HAVE_MINGW
|
||||
if (io->fd != -1) {
|
||||
io->event = WSACreateEvent();
|
||||
if (io->event == WSA_INVALID_EVENT)
|
||||
abort();
|
||||
}
|
||||
event_count++;
|
||||
#endif
|
||||
io->cb = cb;
|
||||
io->data = data;
|
||||
io->node.data = io;
|
||||
|
|
@ -70,9 +89,21 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
|
|||
abort();
|
||||
}
|
||||
|
||||
void io_set(io_t *io, int flags) {
|
||||
io->flags = flags;
|
||||
#ifdef HAVE_MINGW
|
||||
void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) {
|
||||
io->event = event;
|
||||
io_add(io, cb, data, -1, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void io_set(io_t *io, int flags) {
|
||||
if (flags == io->flags)
|
||||
return;
|
||||
io->flags = flags;
|
||||
if (io->fd == -1)
|
||||
return;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
if(flags & IO_READ)
|
||||
FD_SET(io->fd, &readfds);
|
||||
else
|
||||
|
|
@ -82,6 +113,15 @@ void io_set(io_t *io, int flags) {
|
|||
FD_SET(io->fd, &writefds);
|
||||
else
|
||||
FD_CLR(io->fd, &writefds);
|
||||
#else
|
||||
long events = 0;
|
||||
if (flags & IO_WRITE)
|
||||
events |= WRITE_EVENTS;
|
||||
if (flags & IO_READ)
|
||||
events |= READ_EVENTS;
|
||||
if (WSAEventSelect(io->fd, io->event, events) != 0)
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void io_del(io_t *io) {
|
||||
|
|
@ -89,6 +129,11 @@ void io_del(io_t *io) {
|
|||
return;
|
||||
|
||||
io_set(io, 0);
|
||||
#ifdef HAVE_MINGW
|
||||
if (io->fd != -1 && WSACloseEvent(io->event) == FALSE)
|
||||
abort();
|
||||
event_count--;
|
||||
#endif
|
||||
|
||||
splay_unlink_node(&io_tree, &io->node);
|
||||
io->cb = NULL;
|
||||
|
|
@ -182,30 +227,37 @@ void signal_del(signal_t *sig) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct timeval * get_time_remaining(struct timeval *diff) {
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval *tv = NULL;
|
||||
|
||||
while(timeout_tree.head) {
|
||||
timeout_t *timeout = timeout_tree.head->data;
|
||||
timersub(&timeout->tv, &now, diff);
|
||||
|
||||
if(diff->tv_sec < 0) {
|
||||
timeout->cb(timeout->data);
|
||||
if(timercmp(&timeout->tv, &now, <))
|
||||
timeout_del(timeout);
|
||||
} else {
|
||||
tv = diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
bool event_loop(void) {
|
||||
running = true;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
fd_set readable;
|
||||
fd_set writable;
|
||||
|
||||
while(running) {
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval diff, *tv = NULL;
|
||||
|
||||
while(timeout_tree.head) {
|
||||
timeout_t *timeout = timeout_tree.head->data;
|
||||
timersub(&timeout->tv, &now, &diff);
|
||||
|
||||
if(diff.tv_sec < 0) {
|
||||
timeout->cb(timeout->data);
|
||||
if(timercmp(&timeout->tv, &now, <))
|
||||
timeout_del(timeout);
|
||||
} else {
|
||||
tv = &diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval diff;
|
||||
struct timeval *tv = get_time_remaining(&diff);
|
||||
memcpy(&readable, &readfds, sizeof readable);
|
||||
memcpy(&writable, &writefds, sizeof writable);
|
||||
|
||||
|
|
@ -216,16 +268,10 @@ bool event_loop(void) {
|
|||
fds = last->fd + 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
LeaveCriticalSection(&mutex);
|
||||
#endif
|
||||
int n = select(fds, &readable, &writable, NULL, tv);
|
||||
#ifdef HAVE_MINGW
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
if(n < 0) {
|
||||
if(sockwouldblock(errno))
|
||||
if(sockwouldblock(sockerrno))
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
|
|
@ -241,16 +287,77 @@ bool event_loop(void) {
|
|||
io->cb(io->data, IO_READ);
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (running) {
|
||||
struct timeval diff;
|
||||
struct timeval *tv = get_time_remaining(&diff);
|
||||
DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
|
||||
|
||||
if (!event_count) {
|
||||
Sleep(timeout_ms);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
For some reason, Microsoft decided to make the FD_WRITE event edge-triggered instead of level-triggered,
|
||||
which is the opposite of what select() does. In practice, that means that if a FD_WRITE event triggers,
|
||||
it will never trigger again until a send() returns EWOULDBLOCK. Since the semantics of this event loop
|
||||
is that write events are level-triggered (i.e. they continue firing until the socket is full), we need
|
||||
to emulate these semantics by making sure we fire each IO_WRITE that is still writeable.
|
||||
|
||||
Note that technically FD_CLOSE has the same problem, but it's okay because user code does not rely on
|
||||
this event being fired again if ignored.
|
||||
*/
|
||||
io_t* writeable_io = NULL;
|
||||
for splay_each(io_t, io, &io_tree)
|
||||
if (io->flags & IO_WRITE && send(io->fd, NULL, 0, 0) == 0) {
|
||||
writeable_io = io;
|
||||
break;
|
||||
}
|
||||
if (writeable_io) {
|
||||
writeable_io->cb(writeable_io->data, IO_WRITE);
|
||||
continue;
|
||||
}
|
||||
|
||||
WSAEVENT* events = xmalloc(event_count * sizeof(*events));
|
||||
DWORD event_index = 0;
|
||||
for splay_each(io_t, io, &io_tree) {
|
||||
events[event_index] = io->event;
|
||||
event_index++;
|
||||
}
|
||||
|
||||
DWORD result = WSAWaitForMultipleEvents(event_count, events, FALSE, timeout_ms, FALSE);
|
||||
|
||||
WSAEVENT event;
|
||||
if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + event_count)
|
||||
event = events[result - WSA_WAIT_EVENT_0];
|
||||
free(events);
|
||||
if (result == WSA_WAIT_TIMEOUT)
|
||||
continue;
|
||||
if (result < WSA_WAIT_EVENT_0 || result >= WSA_WAIT_EVENT_0 + event_count)
|
||||
return false;
|
||||
|
||||
io_t *io = splay_search(&io_tree, &((io_t){.event = event}));
|
||||
if (!io)
|
||||
abort();
|
||||
|
||||
if (io->fd == -1) {
|
||||
io->cb(io->data, 0);
|
||||
} else {
|
||||
WSANETWORKEVENTS network_events;
|
||||
if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
|
||||
return false;
|
||||
if (network_events.lNetworkEvents & WRITE_EVENTS)
|
||||
io->cb(io->data, IO_WRITE);
|
||||
if (network_events.lNetworkEvents & READ_EVENTS)
|
||||
io->cb(io->data, IO_READ);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void event_flush_output(void) {
|
||||
for splay_each(io_t, io, &io_tree)
|
||||
if(FD_ISSET(io->fd, &writefds))
|
||||
io->cb(io->data, IO_WRITE);
|
||||
}
|
||||
|
||||
void event_exit(void) {
|
||||
running = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ typedef void (*signal_cb_t)(void *data);
|
|||
typedef struct io_t {
|
||||
int fd;
|
||||
int flags;
|
||||
#ifdef HAVE_MINGW
|
||||
WSAEVENT event;
|
||||
#endif
|
||||
io_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
|
|
@ -54,6 +57,9 @@ typedef struct signal_t {
|
|||
extern struct timeval now;
|
||||
|
||||
extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags);
|
||||
#ifdef HAVE_MINGW
|
||||
extern void io_add_event(io_t *io, io_cb_t cb, void* data, WSAEVENT event);
|
||||
#endif
|
||||
extern void io_del(io_t *io);
|
||||
extern void io_set(io_t *io, int flags);
|
||||
|
||||
|
|
@ -65,7 +71,6 @@ extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
|
|||
extern void signal_del(signal_t *sig);
|
||||
|
||||
extern bool event_loop(void);
|
||||
extern void event_flush_output(void);
|
||||
extern void event_exit(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
30
src/graph.c
30
src/graph.c
|
|
@ -176,9 +176,13 @@ static void sssp_bfs(void) {
|
|||
&& (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight))
|
||||
continue;
|
||||
|
||||
// Only update nexthop if it doesn't increase the path length
|
||||
|
||||
if(!e->to->status.visited || (e->to->distance == n->distance + 1 && e->weight >= e->to->prevedge->weight))
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
|
||||
e->to->status.visited = true;
|
||||
e->to->status.indirect = indirect;
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
e->to->prevedge = e;
|
||||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
|
|
@ -200,6 +204,9 @@ static void sssp_bfs(void) {
|
|||
static void check_reachability(void) {
|
||||
/* Check reachability status. */
|
||||
|
||||
int reachable_count = 0;
|
||||
int became_reachable_count = 0;
|
||||
int became_unreachable_count = 0;
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n->status.visited != n->status.reachable) {
|
||||
n->status.reachable = !n->status.reachable;
|
||||
|
|
@ -208,9 +215,13 @@ static void check_reachability(void) {
|
|||
if(n->status.reachable) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
n->name, n->hostname);
|
||||
if (n != myself)
|
||||
became_reachable_count++;
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
n->name, n->hostname);
|
||||
if (n != myself)
|
||||
became_unreachable_count++;
|
||||
}
|
||||
|
||||
if(experimental && OPTION_VERSION(n->options) >= 2)
|
||||
|
|
@ -264,15 +275,18 @@ static void check_reachability(void) {
|
|||
update_node_udp(n, NULL);
|
||||
memset(&n->status, 0, sizeof n->status);
|
||||
n->options = 0;
|
||||
} else if(n->connection) {
|
||||
if(n->status.sptps) {
|
||||
if(n->connection->outgoing)
|
||||
send_req_key(n);
|
||||
} else {
|
||||
send_ans_key(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(n->status.reachable && n != myself)
|
||||
reachable_count++;
|
||||
}
|
||||
|
||||
if (device_standby) {
|
||||
if (reachable_count == 0 && became_unreachable_count > 0)
|
||||
device_disable();
|
||||
else if (reachable_count > 0 && reachable_count == became_reachable_count)
|
||||
device_enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,13 @@ void *hash_search_or_insert(hash_t *hash, const void *key, const void *value) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Deleting */
|
||||
|
||||
void hash_delete(hash_t *hash, const void *key) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
hash->values[i] = NULL;
|
||||
}
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
void hash_clear(hash_t *hash) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ extern hash_t *hash_alloc(size_t n, size_t size) __attribute__ ((__malloc__));
|
|||
extern void hash_free(hash_t *);
|
||||
|
||||
extern void hash_insert(hash_t *, const void *key, const void *value);
|
||||
extern void hash_delete(hash_t *, const void *key);
|
||||
|
||||
extern void *hash_search(const hash_t *, const void *key);
|
||||
extern void *hash_search_or_insert(hash_t *, const void *key, const void *value);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "subnet.h"
|
||||
#include "tincctl.h"
|
||||
#include "info.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
|
|
@ -49,6 +50,7 @@ static int info_node(int fd, const char *item) {
|
|||
char line[4096];
|
||||
|
||||
char node[4096];
|
||||
char id[4096];
|
||||
char from[4096];
|
||||
char to[4096];
|
||||
char subnet[4096];
|
||||
|
|
@ -67,12 +69,12 @@ static int info_node(int fd, const char *item) {
|
|||
long int last_state_change;
|
||||
|
||||
while(recvline(fd, line, sizeof line)) {
|
||||
int n = sscanf(line, "%d %d %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
|
||||
int n = sscanf(line, "%d %d %s %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
|
||||
|
||||
if(n == 2)
|
||||
break;
|
||||
|
||||
if(n != 18) {
|
||||
if(n != 19) {
|
||||
fprintf(stderr, "Unable to parse node dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -94,6 +96,7 @@ static int info_node(int fd, const char *item) {
|
|||
}
|
||||
|
||||
printf("Node: %s\n", item);
|
||||
printf("Node ID: %s\n", id);
|
||||
printf("Address: %s port %s\n", host, port);
|
||||
|
||||
char timestr[32] = "never";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
invitation.c -- Create and accept invitations
|
||||
Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2013-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
|
||||
|
|
@ -142,12 +142,19 @@ char *get_my_hostname() {
|
|||
}
|
||||
}
|
||||
|
||||
if(!tty) {
|
||||
if(!hostname) {
|
||||
fprintf(stderr, "Could not determine the external address or hostname. Please set Address manually.\n");
|
||||
return NULL;
|
||||
}
|
||||
goto save;
|
||||
}
|
||||
|
||||
again:
|
||||
printf("Please enter your host's external address or hostname");
|
||||
fprintf(stderr, "Please enter your host's external address or hostname");
|
||||
if(hostname)
|
||||
printf(" [%s]", hostname);
|
||||
printf(": ");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, " [%s]", hostname);
|
||||
fprintf(stderr, ": ");
|
||||
|
||||
if(!fgets(line, sizeof line, stdin)) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
|
||||
|
|
@ -190,8 +197,10 @@ done:
|
|||
else
|
||||
xasprintf(&hostport, "%s:%s", hostname, port);
|
||||
} else {
|
||||
hostport = hostname;
|
||||
hostname = NULL;
|
||||
if(strchr(hostname, ':'))
|
||||
xasprintf(&hostport, "[%s]", hostname);
|
||||
else
|
||||
hostport = xstrdup(hostname);
|
||||
}
|
||||
|
||||
free(hostname);
|
||||
|
|
@ -241,7 +250,7 @@ int cmd_invite(int argc, char *argv[]) {
|
|||
}
|
||||
free(filename);
|
||||
|
||||
// If a daemon is running, ensure no other nodes now about this name
|
||||
// If a daemon is running, ensure no other nodes know about this name
|
||||
bool found = false;
|
||||
if(connect_tincd(false)) {
|
||||
sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
|
||||
|
|
@ -312,7 +321,7 @@ int cmd_invite(int argc, char *argv[]) {
|
|||
free(filename);
|
||||
|
||||
ecdsa_t *key;
|
||||
xasprintf(&filename, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", confbase);
|
||||
xasprintf(&filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
|
||||
|
||||
// Remove the key if there are no outstanding invitations.
|
||||
if(!count)
|
||||
|
|
@ -404,8 +413,12 @@ int cmd_invite(int argc, char *argv[]) {
|
|||
char buf[1024];
|
||||
while(fgets(buf, sizeof buf, tc)) {
|
||||
if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4]))
|
||||
|| (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9])))
|
||||
|| (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) {
|
||||
fputs(buf, f);
|
||||
// Make sure there is a newline character.
|
||||
if(!strchr(buf, '\n'))
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
fclose(tc);
|
||||
}
|
||||
|
|
@ -567,7 +580,7 @@ make_names:
|
|||
|
||||
if(!access(tinc_conf, F_OK)) {
|
||||
fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
|
||||
if(!tty || confbasegiven)
|
||||
if(confbasegiven)
|
||||
return false;
|
||||
|
||||
// Generate a random netname, ask for a better one later.
|
||||
|
|
@ -600,6 +613,7 @@ make_names:
|
|||
FILE *fh = fopen(filename, "w");
|
||||
if(!fh) {
|
||||
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -709,7 +723,7 @@ make_names:
|
|||
if(!b64key)
|
||||
return false;
|
||||
|
||||
xasprintf(&filename, "%s" SLASH "ecdsa_key.priv", confbase);
|
||||
xasprintf(&filename, "%s" SLASH "ed25519_key.priv", confbase);
|
||||
f = fopenmask(filename, "w", 0600);
|
||||
|
||||
if(!ecdsa_write_pem_private_key(key, f)) {
|
||||
|
|
@ -721,7 +735,7 @@ make_names:
|
|||
|
||||
fclose(f);
|
||||
|
||||
fprintf(fh, "ECDSAPublicKey = %s\n", b64key);
|
||||
fprintf(fh, "Ed25519PublicKey = %s\n", b64key);
|
||||
|
||||
sptps_send_record(&sptps, 1, b64key, strlen(b64key));
|
||||
free(b64key);
|
||||
|
|
@ -743,7 +757,7 @@ make_names:
|
|||
check_port(name);
|
||||
|
||||
ask_netname:
|
||||
if(ask_netname) {
|
||||
if(ask_netname && tty) {
|
||||
fprintf(stderr, "Enter a new netname: ");
|
||||
if(!fgets(line, sizeof line, stdin)) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
|
||||
|
|
@ -767,11 +781,13 @@ ask_netname:
|
|||
make_names();
|
||||
}
|
||||
|
||||
fprintf(stderr, "Configuration stored in: %s\n", confbase);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool invitation_send(void *handle, uint8_t type, const char *data, size_t len) {
|
||||
static bool invitation_send(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
while(len) {
|
||||
int result = send(sock, data, len, 0);
|
||||
if(result == -1 && errno == EINTR)
|
||||
|
|
@ -784,7 +800,7 @@ static bool invitation_send(void *handle, uint8_t type, const char *data, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool invitation_receive(void *handle, uint8_t type, const char *msg, uint16_t len) {
|
||||
static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint16_t len) {
|
||||
switch(type) {
|
||||
case SPTPS_HANDSHAKE:
|
||||
return sptps_send_record(&sptps, 0, cookie, sizeof cookie);
|
||||
|
|
@ -850,10 +866,8 @@ int cmd_join(int argc, char *argv[]) {
|
|||
if(argc > 1) {
|
||||
invitation = argv[1];
|
||||
} else {
|
||||
if(tty) {
|
||||
printf("Enter invitation URL: ");
|
||||
fflush(stdout);
|
||||
}
|
||||
if(tty)
|
||||
fprintf(stderr, "Enter invitation URL: ");
|
||||
errno = EPIPE;
|
||||
if(!fgets(line, sizeof line, stdin)) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
|
||||
|
|
@ -893,7 +907,7 @@ int cmd_join(int argc, char *argv[]) {
|
|||
if(!port || !*port)
|
||||
port = "655";
|
||||
|
||||
if(!b64decode(slash, hash, 18) || !b64decode(slash + 24, cookie, 18))
|
||||
if(!b64decode(slash, hash, 24) || !b64decode(slash + 24, cookie, 24))
|
||||
goto invalid;
|
||||
|
||||
// Generate a throw-away key for the invitation.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Linux ethertap and tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-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
|
||||
|
|
@ -46,11 +46,6 @@ static char *type = NULL;
|
|||
static char ifrname[IFNAMSIZ];
|
||||
static char *device_info;
|
||||
|
||||
uint64_t device_in_packets = 0;
|
||||
uint64_t device_in_bytes = 0;
|
||||
uint64_t device_out_packets = 0;
|
||||
uint64_t device_out_bytes = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
|
|
@ -110,15 +105,25 @@ static bool setup_device(void) {
|
|||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
if(ifr.ifr_flags & IFF_TAP) {
|
||||
struct ifreq ifr_mac = {};
|
||||
if(!ioctl(device_fd, SIOCGIFHWADDR, &ifr_mac))
|
||||
memcpy(mymac.x, ifr_mac.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
else
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get MAC address of %s: %s", device, strerror(errno));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
|
||||
free(type);
|
||||
free(device);
|
||||
free(iface);
|
||||
free(type); type = NULL;
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -126,7 +131,7 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
inlen = read(device_fd, packet->data + 10, MTU - 10);
|
||||
inlen = read(device_fd, DATA(packet) + 10, MTU - 10);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
|
|
@ -134,11 +139,11 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
break;
|
||||
case DEVICE_TYPE_TAP:
|
||||
inlen = read(device_fd, packet->data, MTU);
|
||||
inlen = read(device_fd, DATA(packet), MTU);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
|
|
@ -152,9 +157,6 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
abort();
|
||||
}
|
||||
|
||||
device_in_packets++;
|
||||
device_in_bytes += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
|
|
@ -167,15 +169,15 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
packet->data[10] = packet->data[11] = 0;
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
DATA(packet)[10] = DATA(packet)[11] = 0;
|
||||
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
|
|
@ -185,22 +187,12 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
abort();
|
||||
}
|
||||
|
||||
device_out_packets++;
|
||||
device_out_bytes += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_in_bytes);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_out_bytes);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ enum {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern debug_t debug_level;
|
||||
extern bool logcontrol;
|
||||
extern void openlogger(const char *, logmode_t);
|
||||
|
|
|
|||
11
src/meta.c
11
src/meta.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.c -- handle the meta communication
|
||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t length) {
|
||||
bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) {
|
||||
connection_t *c = handle;
|
||||
|
||||
if(!c) {
|
||||
|
|
@ -76,11 +76,12 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
|
|||
|
||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c != from && c->status.active)
|
||||
if(c != from && c->edge)
|
||||
send_meta(c, buffer, length);
|
||||
}
|
||||
|
||||
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
|
||||
bool receive_meta_sptps(void *handle, uint8_t type, const void *vdata, uint16_t length) {
|
||||
const char *data = vdata;
|
||||
connection_t *c = handle;
|
||||
|
||||
if(!c) {
|
||||
|
|
@ -142,7 +143,7 @@ bool receive_meta(connection_t *c) {
|
|||
inlen = recv(c->socket, inbuf, sizeof inbuf - c->inbuf.len, 0);
|
||||
|
||||
if(inlen <= 0) {
|
||||
if(!inlen || !errno) {
|
||||
if(!inlen || !sockerrno) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.h -- header for meta.c
|
||||
Copyright (C) 2000-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -24,8 +24,8 @@
|
|||
#include "connection.h"
|
||||
|
||||
extern bool send_meta(struct connection_t *, const char *, int);
|
||||
extern bool send_meta_sptps(void *, uint8_t, const char *, size_t);
|
||||
extern bool receive_meta_sptps(void *, uint8_t, const char *, uint16_t);
|
||||
extern 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);
|
||||
extern bool receive_meta(struct connection_t *);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a MinGW environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-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
|
||||
|
|
@ -36,55 +36,52 @@
|
|||
|
||||
int device_fd = -1;
|
||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||
static io_t device_read_io;
|
||||
static OVERLAPPED device_read_overlapped;
|
||||
static vpn_packet_t device_read_packet;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
extern char *myport;
|
||||
|
||||
static DWORD WINAPI tapreader(void *bla) {
|
||||
static void device_issue_read() {
|
||||
device_read_overlapped.Offset = 0;
|
||||
device_read_overlapped.OffsetHigh = 0;
|
||||
|
||||
int status;
|
||||
DWORD len;
|
||||
OVERLAPPED overlapped;
|
||||
vpn_packet_t packet;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader running");
|
||||
|
||||
/* Read from tap device and send to parent */
|
||||
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
for(;;) {
|
||||
overlapped.Offset = 0;
|
||||
overlapped.OffsetHigh = 0;
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
status = ReadFile(device_handle, (void *)packet.data, MTU, &len, &overlapped);
|
||||
|
||||
if(!status) {
|
||||
if(GetLastError() == ERROR_IO_PENDING) {
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
|
||||
continue;
|
||||
} else {
|
||||
for (;;) {
|
||||
DWORD len;
|
||||
status = ReadFile(device_handle, (void *)device_read_packet.data, MTU, &len, &device_read_overlapped);
|
||||
if (!status) {
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&mutex);
|
||||
packet.len = len;
|
||||
packet.priority = 0;
|
||||
route(myself, &packet);
|
||||
event_flush_output();
|
||||
LeaveCriticalSection(&mutex);
|
||||
device_read_packet.len = len;
|
||||
device_read_packet.priority = 0;
|
||||
route(myself, &device_read_packet);
|
||||
}
|
||||
}
|
||||
|
||||
static void device_handle_read(void *data, int flags) {
|
||||
ResetEvent(device_read_overlapped.hEvent);
|
||||
|
||||
DWORD len;
|
||||
if (!GetOverlappedResult(device_handle, &device_read_overlapped, &len, FALSE)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error getting read result from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
device_read_packet.len = len;
|
||||
device_read_packet.priority = 0;
|
||||
route(myself, &device_read_packet);
|
||||
device_issue_read();
|
||||
}
|
||||
|
||||
static bool setup_device(void) {
|
||||
HKEY key, key2;
|
||||
int i;
|
||||
|
|
@ -94,12 +91,10 @@ static bool setup_device(void) {
|
|||
char adaptername[1024];
|
||||
char tapname[1024];
|
||||
DWORD len;
|
||||
unsigned long status;
|
||||
|
||||
bool found = false;
|
||||
|
||||
int err;
|
||||
HANDLE thread;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
|
@ -191,20 +186,6 @@ static bool setup_device(void) {
|
|||
overwrite_mac = 1;
|
||||
}
|
||||
|
||||
/* Start the tap reader */
|
||||
|
||||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||
|
||||
if(!thread) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set media status for newer TAP-Win32 devices */
|
||||
|
||||
status = true;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
|
||||
|
||||
device_info = "Windows tap device";
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
|
@ -212,11 +193,36 @@ static bool setup_device(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
CloseHandle(device_handle);
|
||||
static void enable_device(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Enabling %s", device_info);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
ULONG status = 1;
|
||||
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;
|
||||
device_issue_read();
|
||||
}
|
||||
|
||||
static void disable_device(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info);
|
||||
|
||||
io_del(&device_read_io);
|
||||
CancelIo(device_handle);
|
||||
CloseHandle(device_read_overlapped.hEvent);
|
||||
|
||||
ULONG status = 0;
|
||||
DWORD len;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -230,26 +236,19 @@ 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(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
|
||||
if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, &overlapped)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
.enable = enable_device,
|
||||
.disable = disable_device,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@
|
|||
|
||||
static char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static struct addrinfo *ai = NULL;
|
||||
static mac_t ignore_src = {{0}};
|
||||
|
||||
|
|
@ -132,7 +129,7 @@ static bool setup_device(void) {
|
|||
#endif
|
||||
|
||||
default:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -151,33 +148,33 @@ error:
|
|||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
close(device_fd); device_fd = -1;
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
|
||||
if(ai)
|
||||
freeaddrinfo(ai);
|
||||
if(ai) {
|
||||
freeaddrinfo(ai); ai = NULL;
|
||||
}
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) {
|
||||
if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
device, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) {
|
||||
if(!memcmp(&ignore_src, DATA(packet) + 6, sizeof ignore_src)) {
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
|
|
@ -188,45 +185,20 @@ 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, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
if(sendto(device_fd, 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,
|
||||
strerror(errno));
|
||||
sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
memcpy(&ignore_src, packet->data + 6, sizeof ignore_src);
|
||||
memcpy(&ignore_src, DATA(packet) + 6, sizeof ignore_src);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
static bool not_supported(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Raw socket device not supported on this platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = not_supported,
|
||||
.close = NULL,
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.dump_stats = NULL,
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
24
src/names.c
24
src/names.c
|
|
@ -64,8 +64,6 @@ void make_names(void) {
|
|||
else
|
||||
xasprintf(&confbase, "%s", installdir);
|
||||
}
|
||||
if(!pidfilename)
|
||||
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
|
@ -73,11 +71,26 @@ void make_names(void) {
|
|||
if(!confdir)
|
||||
confdir = xstrdup(CONFDIR SLASH "tinc");
|
||||
|
||||
if(!confbase) {
|
||||
if(netname)
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc" SLASH "%s", netname);
|
||||
else
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc");
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
if(!logfilename)
|
||||
xasprintf(&logfilename, "%s" SLASH "log", confbase);
|
||||
|
||||
if(!pidfilename)
|
||||
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
|
||||
#else
|
||||
if(!logfilename)
|
||||
xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname);
|
||||
|
||||
if(!pidfilename)
|
||||
xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
|
||||
#endif
|
||||
|
||||
if(!unixsocketname) {
|
||||
int len = strlen(pidfilename);
|
||||
|
|
@ -88,13 +101,6 @@ void make_names(void) {
|
|||
else
|
||||
strcpy(unixsocketname + len, ".socket");
|
||||
}
|
||||
|
||||
if(!confbase) {
|
||||
if(netname)
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc" SLASH "%s", netname);
|
||||
else
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc");
|
||||
}
|
||||
}
|
||||
|
||||
void free_names(void) {
|
||||
|
|
|
|||
42
src/net.c
42
src/net.c
|
|
@ -36,6 +36,10 @@
|
|||
#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;
|
||||
|
|
@ -93,8 +97,6 @@ void purge(void) {
|
|||
void terminate_connection(connection_t *c, bool report) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname);
|
||||
|
||||
c->status.active = false;
|
||||
|
||||
if(c->node && c->node->connection == c)
|
||||
c->node->connection = NULL;
|
||||
|
||||
|
|
@ -129,6 +131,12 @@ void terminate_connection(connection_t *c, bool report) {
|
|||
|
||||
if(outgoing)
|
||||
do_outgoing_connection(outgoing);
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
/* Clean up dead proxy processes */
|
||||
|
||||
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -145,7 +153,7 @@ static void timeout_handler(void *data) {
|
|||
continue;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now.tv_sec) {
|
||||
if(c->status.active) {
|
||||
if(c->edge) {
|
||||
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);
|
||||
} else if(c->last_ping_time + pinginterval <= now.tv_sec) {
|
||||
|
|
@ -160,7 +168,7 @@ static void timeout_handler(void *data) {
|
|||
else
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
|
||||
}
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,11 +202,11 @@ static void periodic_handler(void *data) {
|
|||
/* Count number of active connections */
|
||||
int nc = 0;
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->status.active && !c->status.control)
|
||||
if(c->edge)
|
||||
nc++;
|
||||
}
|
||||
|
||||
if(nc < autoconnect) {
|
||||
if(nc < 3) {
|
||||
/* Not enough active connections, try to add one.
|
||||
Choose a random node, if we don't have a connection to it,
|
||||
and we are not already trying to make one, create an
|
||||
|
|
@ -232,7 +240,7 @@ static void periodic_handler(void *data) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
} else if(nc > autoconnect) {
|
||||
} else if(nc > 3) {
|
||||
/* Too many active connections, try to remove one.
|
||||
Choose a random outgoing connection to a node
|
||||
that has at least one other connection.
|
||||
|
|
@ -241,7 +249,7 @@ static void periodic_handler(void *data) {
|
|||
int i = 0;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->status.active || c->status.control)
|
||||
if(!c->edge)
|
||||
continue;
|
||||
|
||||
if(i++ != r)
|
||||
|
|
@ -253,12 +261,12 @@ static void periodic_handler(void *data) {
|
|||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
|
||||
list_delete(outgoing_list, c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nc >= autoconnect) {
|
||||
if(nc >= 3) {
|
||||
/* If we have enough active connections,
|
||||
remove any pending outgoing connections.
|
||||
*/
|
||||
|
|
@ -283,7 +291,7 @@ static void periodic_handler(void *data) {
|
|||
|
||||
void handle_meta_connection_data(connection_t *c) {
|
||||
if (!receive_meta(c)) {
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -303,6 +311,9 @@ 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
|
||||
|
|
@ -334,11 +345,14 @@ int reload_configuration(void) {
|
|||
|
||||
if(strictsubnets) {
|
||||
for splay_each(subnet_t, subnet, subnet_tree)
|
||||
subnet->expires = 1;
|
||||
if (subnet->owner)
|
||||
subnet->expires = 1;
|
||||
|
||||
load_all_subnets();
|
||||
|
||||
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||
if (!subnet->owner)
|
||||
continue;
|
||||
if(subnet->expires == 1) {
|
||||
send_del_subnet(everyone, subnet);
|
||||
if(subnet->owner->status.reachable)
|
||||
|
|
@ -402,7 +416,7 @@ int reload_configuration(void) {
|
|||
struct stat s;
|
||||
if(stat(fname, &s) || s.st_mtime > last_config_check) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Host config file of %s has been changed", c->name);
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
}
|
||||
free(fname);
|
||||
}
|
||||
|
|
@ -452,7 +466,7 @@ int main_loop(void) {
|
|||
#endif
|
||||
|
||||
if(!event_loop()) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
34
src/net.h
34
src/net.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-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
|
||||
|
|
@ -32,8 +32,8 @@
|
|||
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
|
||||
#endif
|
||||
|
||||
/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + padding + HMAC + compressor overhead */
|
||||
#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
|
||||
/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + srcid + dstid + padding + HMAC + compressor overhead */
|
||||
#define MAXSIZE (MTU + 4 + sizeof(node_id_t) + sizeof(node_id_t) + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)
|
||||
|
||||
/* MAXBUFSIZE is the maximum size of a request: enough for a MAXSIZEd packet or a 8192 bits RSA key */
|
||||
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)
|
||||
|
|
@ -52,7 +52,12 @@ typedef struct ipv6_t {
|
|||
uint16_t x[8];
|
||||
} ipv6_t;
|
||||
|
||||
typedef struct node_id_t {
|
||||
uint8_t x[6];
|
||||
} node_id_t;
|
||||
|
||||
typedef short length_t;
|
||||
typedef uint32_t seqno_t;
|
||||
|
||||
#define AF_UNKNOWN 255
|
||||
|
||||
|
|
@ -80,10 +85,16 @@ typedef union sockaddr_t {
|
|||
#define SALEN(s) (s.sa_family==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6))
|
||||
#endif
|
||||
|
||||
#define SEQNO(x) ((x)->data + (x)->offset - 4)
|
||||
#define SRCID(x) ((node_id_t *)((x)->data + (x)->offset - 6))
|
||||
#define DSTID(x) ((node_id_t *)((x)->data + (x)->offset - 12))
|
||||
#define DATA(x) ((x)->data + (x)->offset)
|
||||
#define DEFAULT_PACKET_OFFSET 12
|
||||
|
||||
typedef struct vpn_packet_t {
|
||||
length_t len; /* the actual number of bytes in the `data' field */
|
||||
length_t len; /* The actual number of valid bytes in the `data' field (including seqno or dstid/srcid) */
|
||||
length_t offset; /* Offset in the buffer where the packet data starts (righter after seqno or dstid/srcid) */
|
||||
int priority; /* priority or TOS */
|
||||
uint32_t seqno; /* 32 bits sequence number (network byte order of course) */
|
||||
uint8_t data[MAXSIZE];
|
||||
} vpn_packet_t;
|
||||
|
||||
|
|
@ -103,6 +114,7 @@ typedef struct listen_socket_t {
|
|||
io_t tcp;
|
||||
io_t udp;
|
||||
sockaddr_t sa;
|
||||
bool bindto;
|
||||
} listen_socket_t;
|
||||
|
||||
#include "conf.h"
|
||||
|
|
@ -125,7 +137,6 @@ extern int seconds_till_retry;
|
|||
extern int addressfamily;
|
||||
extern unsigned replaywin;
|
||||
extern bool localdiscovery;
|
||||
extern sockaddr_t localdiscovery_address;
|
||||
|
||||
extern listen_socket_t listen_socket[MAXSOCKETS];
|
||||
extern int listen_sockets;
|
||||
|
|
@ -136,7 +147,8 @@ extern int udp_sndbuf;
|
|||
extern int max_connection_burst;
|
||||
extern bool do_prune;
|
||||
extern char *myport;
|
||||
extern int autoconnect;
|
||||
extern bool device_standby;
|
||||
extern bool autoconnect;
|
||||
extern bool disablebuggypeers;
|
||||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
|
|
@ -171,12 +183,14 @@ 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 char *data, size_t len);
|
||||
extern bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len);
|
||||
extern bool send_sptps_data(void *handle, uint8_t 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 void broadcast_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern char *get_name(void);
|
||||
extern void device_enable(void);
|
||||
extern void device_disable(void);
|
||||
extern bool setup_myself_reloadable(void);
|
||||
extern bool setup_network(void);
|
||||
extern void setup_outgoing_connection(struct outgoing_t *);
|
||||
|
|
@ -199,8 +213,6 @@ extern void load_all_nodes(void);
|
|||
|
||||
#ifndef HAVE_MINGW
|
||||
#define closesocket(s) close(s)
|
||||
#else
|
||||
extern CRITICAL_SECTION mutex;
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_NET_H__ */
|
||||
|
|
|
|||
471
src/net_packet.c
471
src/net_packet.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_packet.c -- Handles in- and outgoing VPN packets
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010 Timothy Redaelli <timothy@redaelli.eu>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
|
@ -54,8 +54,7 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
|
|||
static void send_udppacket(node_t *, vpn_packet_t *);
|
||||
|
||||
unsigned replaywin = 16;
|
||||
bool localdiscovery = false;
|
||||
sockaddr_t localdiscovery_address;
|
||||
bool localdiscovery = true;
|
||||
|
||||
#define MAX_SEQNO 1073741824
|
||||
|
||||
|
|
@ -140,19 +139,19 @@ static void send_mtu_probe_handler(void *data) {
|
|||
len = 64;
|
||||
|
||||
vpn_packet_t packet;
|
||||
memset(packet.data, 0, 14);
|
||||
randomize(packet.data + 14, len - 14);
|
||||
packet.offset = DEFAULT_PACKET_OFFSET;
|
||||
memset(DATA(&packet), 0, 14);
|
||||
randomize(DATA(&packet) + 14, len - 14);
|
||||
packet.len = len;
|
||||
if(i >= 4 && n->mtuprobes <= 10)
|
||||
packet.priority = -1;
|
||||
else
|
||||
packet.priority = 0;
|
||||
packet.priority = 0;
|
||||
n->status.send_locally = i >= 4 && n->mtuprobes <= 10 && n->prevedge;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
|
||||
|
||||
send_udppacket(n, &packet);
|
||||
}
|
||||
|
||||
n->status.send_locally = false;
|
||||
n->probe_counter = 0;
|
||||
gettimeofday(&n->probe_time, NULL);
|
||||
|
||||
|
|
@ -178,24 +177,24 @@ void send_mtu_probe(node_t *n) {
|
|||
}
|
||||
|
||||
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
||||
if(!packet->data[0]) {
|
||||
if(!DATA(packet)[0]) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe request %d from %s (%s)", packet->len, n->name, n->hostname);
|
||||
|
||||
/* It's a probe request, send back a reply */
|
||||
|
||||
/* Type 2 probe replies were introduced in protocol 17.3 */
|
||||
if ((n->options >> 24) == 3) {
|
||||
uint8_t* data = packet->data;
|
||||
if ((n->options >> 24) >= 3) {
|
||||
uint8_t *data = DATA(packet);
|
||||
*data++ = 2;
|
||||
uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2;
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
uint32_t sec = htonl(now.tv_sec); memcpy(data, &sec, 4); data += 4;
|
||||
uint32_t usec = htonl(now.tv_usec); memcpy(data, &usec, 4); data += 4;
|
||||
packet->len = data - packet->data;
|
||||
packet->len -= 10;
|
||||
} else {
|
||||
/* Legacy protocol: n won't understand type 2 probe replies. */
|
||||
packet->data[0] = 1;
|
||||
DATA(packet)[0] = 1;
|
||||
}
|
||||
|
||||
/* Temporarily set udp_confirmed, so that the reply is sent
|
||||
|
|
@ -207,14 +206,14 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
|||
n->status.udp_confirmed = udp_confirmed;
|
||||
} else {
|
||||
length_t probelen = len;
|
||||
if (packet->data[0] == 2) {
|
||||
if (DATA(packet)[0] == 2) {
|
||||
if (len < 3)
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Received invalid (too short) MTU probe reply from %s (%s)", n->name, n->hostname);
|
||||
else {
|
||||
uint16_t probelen16; memcpy(&probelen16, packet->data + 1, 2); probelen = ntohs(probelen16);
|
||||
uint16_t probelen16; memcpy(&probelen16, DATA(packet) + 1, 2); probelen = ntohs(probelen16);
|
||||
}
|
||||
}
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", packet->data[0], probelen, n->name, n->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", DATA(packet)[0], probelen, n->name, n->hostname);
|
||||
|
||||
/* It's a valid reply: now we know bidirectional communication
|
||||
is possible using the address and socket that the reply
|
||||
|
|
@ -256,9 +255,9 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
|||
timersub(&now, &n->probe_time, &diff);
|
||||
|
||||
struct timeval probe_timestamp = now;
|
||||
if (packet->data[0] == 2 && packet->len >= 11) {
|
||||
uint32_t sec; memcpy(&sec, packet->data + 3, 4);
|
||||
uint32_t usec; memcpy(&usec, packet->data + 7, 4);
|
||||
if (DATA(packet)[0] == 2 && packet->len >= 11) {
|
||||
uint32_t sec; memcpy(&sec, DATA(packet) + 3, 4);
|
||||
uint32_t usec; memcpy(&usec, DATA(packet) + 7, 4);
|
||||
probe_timestamp.tv_sec = ntohl(sec);
|
||||
probe_timestamp.tv_usec = ntohl(usec);
|
||||
}
|
||||
|
|
@ -350,20 +349,21 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) {
|
|||
|
||||
static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
|
||||
if(n->status.sptps)
|
||||
return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
|
||||
return sptps_verify_datagram(&n->sptps, DATA(inpkt), inpkt->len);
|
||||
|
||||
if(!digest_active(n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest))
|
||||
if(!digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
|
||||
return false;
|
||||
|
||||
return digest_verify(n->indigest, &inpkt->seqno, inpkt->len - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
|
||||
return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
|
||||
}
|
||||
|
||||
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
||||
static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
||||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
int nextpkt = 0;
|
||||
vpn_packet_t *outpkt = pkt[0];
|
||||
size_t outlen;
|
||||
pkt1.offset = DEFAULT_PACKET_OFFSET;
|
||||
pkt2.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
||||
if(n->status.sptps) {
|
||||
if(!n->sptps.state) {
|
||||
|
|
@ -373,43 +373,51 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
|
||||
return;
|
||||
inpkt->offset += 2 * sizeof(node_id_t);
|
||||
if(!sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t))) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!cipher_active(n->incipher)) {
|
||||
if(!n->status.validkey) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check packet length */
|
||||
|
||||
if(inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest)) {
|
||||
if(inpkt->len < sizeof(seqno_t) + digest_length(n->indigest)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* It's a legacy UDP packet, the data starts after the seqno */
|
||||
|
||||
inpkt->offset += sizeof(seqno_t);
|
||||
|
||||
/* Check the message authentication code */
|
||||
|
||||
if(digest_active(n->indigest)) {
|
||||
inpkt->len -= digest_length(n->indigest);
|
||||
if(!digest_verify(n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
|
||||
if(!digest_verify(n->indigest, SEQNO(inpkt), inpkt->len, SEQNO(inpkt) + inpkt->len)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Decrypt the packet */
|
||||
|
||||
if(cipher_active(n->incipher)) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
vpn_packet_t *outpkt = pkt[nextpkt++];
|
||||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_decrypt(n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
if(!cipher_decrypt(n->incipher, SEQNO(inpkt), inpkt->len, SEQNO(outpkt), &outlen, true)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
outpkt->len = outlen;
|
||||
|
|
@ -418,38 +426,40 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
|
||||
/* Check the sequence number */
|
||||
|
||||
inpkt->len -= sizeof inpkt->seqno;
|
||||
inpkt->seqno = ntohl(inpkt->seqno);
|
||||
seqno_t seqno;
|
||||
memcpy(&seqno, SEQNO(inpkt), sizeof seqno);
|
||||
seqno = ntohl(seqno);
|
||||
inpkt->len -= sizeof seqno;
|
||||
|
||||
if(replaywin) {
|
||||
if(inpkt->seqno != n->received_seqno + 1) {
|
||||
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
|
||||
if(seqno != n->received_seqno + 1) {
|
||||
if(seqno >= n->received_seqno + replaywin * 8) {
|
||||
if(n->farfuture++ < replaywin >> 2) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
|
||||
return;
|
||||
n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
|
||||
return false;
|
||||
}
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
|
||||
seqno - n->received_seqno - 1, n->name, n->hostname);
|
||||
memset(n->late, 0, replaywin);
|
||||
} else if (inpkt->seqno <= n->received_seqno) {
|
||||
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
|
||||
} else if (seqno <= n->received_seqno) {
|
||||
if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
n->name, n->hostname, inpkt->seqno, n->received_seqno);
|
||||
return;
|
||||
n->name, n->hostname, seqno, n->received_seqno);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
for(int i = n->received_seqno + 1; i < inpkt->seqno; i++)
|
||||
for(int i = n->received_seqno + 1; i < seqno; i++)
|
||||
n->late[(i / 8) % replaywin] |= 1 << i % 8;
|
||||
}
|
||||
}
|
||||
|
||||
n->farfuture = 0;
|
||||
n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
|
||||
n->late[(seqno / 8) % replaywin] &= ~(1 << seqno % 8);
|
||||
}
|
||||
|
||||
if(inpkt->seqno > n->received_seqno)
|
||||
n->received_seqno = inpkt->seqno;
|
||||
if(seqno > n->received_seqno)
|
||||
n->received_seqno = seqno;
|
||||
|
||||
n->received++;
|
||||
|
||||
|
|
@ -461,12 +471,12 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
length_t origlen = inpkt->len;
|
||||
|
||||
if(n->incompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
vpn_packet_t *outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
|
||||
if((outpkt->len = uncompress_packet(DATA(outpkt), DATA(inpkt), inpkt->len, n->incompression)) < 0) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
inpkt = outpkt;
|
||||
|
|
@ -476,16 +486,18 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
|
||||
inpkt->priority = 0;
|
||||
|
||||
if(!inpkt->data[12] && !inpkt->data[13])
|
||||
if(!DATA(inpkt)[12] && !DATA(inpkt)[13])
|
||||
mtu_probe_h(n, inpkt, origlen);
|
||||
else
|
||||
receive_packet(n, inpkt);
|
||||
return true;
|
||||
}
|
||||
|
||||
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
||||
vpn_packet_t outpkt;
|
||||
outpkt.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
||||
if(len > sizeof outpkt.data)
|
||||
if(len > sizeof outpkt.data - outpkt.offset)
|
||||
return;
|
||||
|
||||
outpkt.len = len;
|
||||
|
|
@ -493,30 +505,46 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
|||
outpkt.priority = 0;
|
||||
else
|
||||
outpkt.priority = -1;
|
||||
memcpy(outpkt.data, buffer, len);
|
||||
memcpy(DATA(&outpkt), buffer, len);
|
||||
|
||||
receive_packet(c->node, &outpkt);
|
||||
}
|
||||
|
||||
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
||||
if(!n->status.validkey) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
|
||||
if(!n->status.waitingforkey)
|
||||
send_req_key(n);
|
||||
else if(n->last_req_key + 10 < now.tv_sec) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
|
||||
sptps_stop(&n->sptps);
|
||||
n->status.waitingforkey = false;
|
||||
send_req_key(n);
|
||||
}
|
||||
return;
|
||||
static bool try_sptps(node_t *n) {
|
||||
if(n->status.validkey)
|
||||
return true;
|
||||
|
||||
/* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET
|
||||
messages anyway, so there's no need for SPTPS at all. */
|
||||
if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY))
|
||||
return false;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
|
||||
|
||||
if(!n->status.waitingforkey)
|
||||
send_req_key(n);
|
||||
else if(n->last_req_key + 10 < now.tv_sec) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
|
||||
sptps_stop(&n->sptps);
|
||||
n->status.waitingforkey = false;
|
||||
send_req_key(n);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
||||
/* Note: condition order is as intended - even if we have a direct
|
||||
metaconnection, we want to try SPTPS anyway as it's the only way to
|
||||
get UDP going */
|
||||
if(!try_sptps(n) && !n->connection)
|
||||
return;
|
||||
|
||||
uint8_t type = 0;
|
||||
int offset = 0;
|
||||
|
||||
if(!(origpkt->data[12] | origpkt->data[13])) {
|
||||
sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
|
||||
if(!(DATA(origpkt)[12] | DATA(origpkt)[13])) {
|
||||
sptps_send_record(&n->sptps, PKT_PROBE, (char *)DATA(origpkt), origpkt->len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -531,7 +559,8 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
|||
vpn_packet_t outpkt;
|
||||
|
||||
if(n->outcompression) {
|
||||
int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
|
||||
outpkt.offset = 0;
|
||||
int len = compress_packet(DATA(&outpkt) + offset, DATA(origpkt) + offset, origpkt->len - offset, n->outcompression);
|
||||
if(len < 0) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
|
||||
} else if(len < origpkt->len - offset) {
|
||||
|
|
@ -541,10 +570,29 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
|||
}
|
||||
}
|
||||
|
||||
sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
|
||||
/* If we have a direct metaconnection to n, and we can't use UDP, then
|
||||
don't bother with SPTPS and just use a "plaintext" PACKET message.
|
||||
We don't really care about end-to-end security since we're not
|
||||
sending the message through any intermediate nodes. */
|
||||
if(n->connection && origpkt->len > n->minmtu)
|
||||
send_tcppacket(n->connection, origpkt);
|
||||
else
|
||||
sptps_send_record(&n->sptps, type, DATA(origpkt) + offset, origpkt->len - offset);
|
||||
return;
|
||||
}
|
||||
|
||||
static void adapt_socket(const sockaddr_t *sa, int *sock) {
|
||||
/* Make sure we have a suitable socket for the chosen address */
|
||||
if(listen_socket[*sock].sa.sa.sa_family != sa->sa.sa_family) {
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family == sa->sa.sa_family) {
|
||||
*sock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void choose_udp_address(const node_t *n, const sockaddr_t **sa, int *sock) {
|
||||
/* Latest guess */
|
||||
*sa = &n->address;
|
||||
|
|
@ -583,54 +631,30 @@ static void choose_udp_address(const node_t *n, const sockaddr_t **sa, int *sock
|
|||
*sock = rand() % listen_sockets;
|
||||
}
|
||||
|
||||
/* Make sure we have a suitable socket for the chosen address */
|
||||
if(listen_socket[*sock].sa.sa.sa_family != (*sa)->sa.sa_family) {
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family == (*sa)->sa.sa_family) {
|
||||
*sock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
adapt_socket(*sa, sock);
|
||||
}
|
||||
|
||||
static void choose_broadcast_address(const node_t *n, const sockaddr_t **sa, int *sock) {
|
||||
static sockaddr_t broadcast_ipv4 = {
|
||||
.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = -1,
|
||||
}
|
||||
};
|
||||
static void choose_local_address(const node_t *n, const sockaddr_t **sa, int *sock) {
|
||||
*sa = NULL;
|
||||
|
||||
static sockaddr_t broadcast_ipv6 = {
|
||||
.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr.s6_addr[0x0] = 0xff,
|
||||
.sin6_addr.s6_addr[0x1] = 0x02,
|
||||
.sin6_addr.s6_addr[0xf] = 0x01,
|
||||
}
|
||||
};
|
||||
/* Pick one of the edges from this node at random, then use its local address. */
|
||||
|
||||
*sock = rand() % listen_sockets;
|
||||
int i = 0;
|
||||
int j = rand() % n->edge_tree->count;
|
||||
edge_t *candidate = NULL;
|
||||
|
||||
if(listen_socket[*sock].sa.sa.sa_family == AF_INET6) {
|
||||
if(localdiscovery_address.sa.sa_family == AF_INET6) {
|
||||
localdiscovery_address.in6.sin6_port = n->prevedge->address.in.sin_port;
|
||||
*sa = &localdiscovery_address;
|
||||
} else {
|
||||
broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port;
|
||||
broadcast_ipv6.in6.sin6_scope_id = listen_socket[*sock].sa.in6.sin6_scope_id;
|
||||
*sa = &broadcast_ipv6;
|
||||
}
|
||||
} else {
|
||||
if(localdiscovery_address.sa.sa_family == AF_INET) {
|
||||
localdiscovery_address.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
*sa = &localdiscovery_address;
|
||||
} else {
|
||||
broadcast_ipv4.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
*sa = &broadcast_ipv4;
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
if(i++ == j) {
|
||||
candidate = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate && candidate->local_address.sa.sa_family) {
|
||||
*sa = &candidate->local_address;
|
||||
*sock = rand() % listen_sockets;
|
||||
adapt_socket(*sa, sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
||||
|
|
@ -643,8 +667,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
size_t outlen;
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
static int priority = 0;
|
||||
#endif
|
||||
int origpriority = origpkt->priority;
|
||||
#endif
|
||||
|
||||
pkt1.offset = DEFAULT_PACKET_OFFSET;
|
||||
pkt2.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
|
||||
|
|
@ -671,7 +698,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (DATA(inpkt)[12] | DATA(inpkt)[13])) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO,
|
||||
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
|
||||
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
|
||||
|
|
@ -689,7 +716,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
if(n->outcompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
|
||||
if((outpkt->len = compress_packet(DATA(outpkt), DATA(inpkt), inpkt->len, n->outcompression)) < 0) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
|
|
@ -700,8 +727,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Add sequence number */
|
||||
|
||||
inpkt->seqno = htonl(++(n->sent_seqno));
|
||||
inpkt->len += sizeof inpkt->seqno;
|
||||
seqno_t seqno = htonl(++(n->sent_seqno));
|
||||
memcpy(SEQNO(inpkt), &seqno, sizeof seqno);
|
||||
inpkt->len += sizeof seqno;
|
||||
|
||||
/* Encrypt the packet */
|
||||
|
||||
|
|
@ -709,7 +737,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
outpkt = pkt[nextpkt++];
|
||||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_encrypt(n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
if(!cipher_encrypt(n->outcipher, SEQNO(inpkt), inpkt->len, SEQNO(outpkt), &outlen, true)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -721,7 +749,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
/* Add the message authentication code */
|
||||
|
||||
if(digest_active(n->outdigest)) {
|
||||
if(!digest_create(n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len)) {
|
||||
if(!digest_create(n->outdigest, SEQNO(inpkt), inpkt->len, SEQNO(inpkt) + inpkt->len)) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
|
||||
goto end;
|
||||
}
|
||||
|
|
@ -731,14 +759,12 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Send the packet */
|
||||
|
||||
const sockaddr_t *sa;
|
||||
const sockaddr_t *sa = NULL;
|
||||
int sock;
|
||||
|
||||
/* Overloaded use of priority field: -1 means local broadcast */
|
||||
|
||||
if(origpriority == -1 && n->prevedge)
|
||||
choose_broadcast_address(n, &sa, &sock);
|
||||
else
|
||||
if(n->status.send_locally)
|
||||
choose_local_address(n, &sa, &sock);
|
||||
if(!sa)
|
||||
choose_udp_address(n, &sa, &sock);
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
|
|
@ -747,11 +773,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
priority = origpriority;
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
|
||||
if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen)
|
||||
n->maxmtu = origlen - 1;
|
||||
|
|
@ -765,39 +791,67 @@ end:
|
|||
origpkt->len = origlen;
|
||||
}
|
||||
|
||||
bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
|
||||
node_t *to = handle;
|
||||
static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
|
||||
node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop;
|
||||
bool direct = from == myself && to == relay;
|
||||
bool relay_supported = (relay->options >> 24) >= 4;
|
||||
bool tcponly = (myself->options | relay->options) & OPTION_TCPONLY;
|
||||
|
||||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, or this packet is larger than the MTU. */
|
||||
/* We don't really need the relay's key, but we need to establish a UDP tunnel with it and discover its MTU. */
|
||||
if (!direct && relay_supported && !tcponly)
|
||||
try_sptps(relay);
|
||||
|
||||
if(type >= SPTPS_HANDSHAKE || ((myself->options | to->options) & OPTION_TCPONLY) || (type != PKT_PROBE && len > to->minmtu)) {
|
||||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU.
|
||||
TODO: When relaying, the original sender does not know the end-to-end PMTU (it only knows the PMTU of the first hop).
|
||||
This can lead to scenarios where large packets are sent over UDP to relay, but then relay has no choice but fall back to TCP. */
|
||||
|
||||
if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
|
||||
char buf[len * 4 / 3 + 5];
|
||||
b64encode(data, buf, len);
|
||||
/* If no valid key is known yet, send the packets using ANS_KEY requests,
|
||||
to ensure we get to learn the reflexive UDP address. */
|
||||
if(!to->status.validkey) {
|
||||
if(from == myself && !to->status.validkey) {
|
||||
to->incompression = myself->incompression;
|
||||
return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, myself->name, to->name, buf, to->incompression);
|
||||
return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, from->name, to->name, buf, to->incompression);
|
||||
} else {
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_SPTPS, buf);
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, REQ_SPTPS, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, send the packet via UDP */
|
||||
|
||||
const sockaddr_t *sa;
|
||||
int sock;
|
||||
|
||||
choose_udp_address(to, &sa, &sock);
|
||||
|
||||
if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(to->maxmtu >= len)
|
||||
to->maxmtu = len - 1;
|
||||
if(to->mtu >= len)
|
||||
to->mtu = len - 1;
|
||||
size_t overhead = 0;
|
||||
if(relay_supported) overhead += sizeof to->id + sizeof from->id;
|
||||
char buf[len + overhead]; char* buf_ptr = buf;
|
||||
if(relay_supported) {
|
||||
if(direct) {
|
||||
/* Inform the recipient that this packet was sent directly. */
|
||||
node_id_t nullid = {};
|
||||
memcpy(buf_ptr, &nullid, sizeof nullid); buf_ptr += sizeof nullid;
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", to->name, to->hostname, sockstrerror(sockerrno));
|
||||
memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
|
||||
}
|
||||
memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id;
|
||||
|
||||
}
|
||||
/* TODO: if this copy turns out to be a performance concern, change sptps_send_record() to add some "pre-padding" to the buffer and use that instead */
|
||||
memcpy(buf_ptr, data, len); buf_ptr += len;
|
||||
|
||||
const sockaddr_t *sa = NULL;
|
||||
int sock;
|
||||
if(relay->status.send_locally)
|
||||
choose_local_address(relay, &sa, &sock);
|
||||
if(!sa)
|
||||
choose_udp_address(relay, &sa, &sock);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
|
||||
if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
// Compensate for SPTPS overhead
|
||||
len -= SPTPS_DATAGRAM_OVERHEAD;
|
||||
if(relay->maxmtu >= len)
|
||||
relay->maxmtu = len - 1;
|
||||
if(relay->mtu >= len)
|
||||
relay->mtu = len - 1;
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Error sending UDP SPTPS packet to %s (%s): %s", relay->name, relay->hostname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -805,7 +859,11 @@ bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t len) {
|
||||
bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
return send_sptps_data_priv(handle, myself, type, data, len);
|
||||
}
|
||||
|
||||
bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) {
|
||||
node_t *from = handle;
|
||||
|
||||
if(type == SPTPS_HANDSHAKE) {
|
||||
|
|
@ -823,10 +881,11 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t
|
|||
}
|
||||
|
||||
vpn_packet_t inpkt;
|
||||
inpkt.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
||||
if(type == PKT_PROBE) {
|
||||
inpkt.len = len;
|
||||
memcpy(inpkt.data, data, len);
|
||||
memcpy(DATA(&inpkt), data, len);
|
||||
mtu_probe_h(from, &inpkt, len);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -846,7 +905,7 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t
|
|||
|
||||
int offset = (type & PKT_MAC) ? 0 : 14;
|
||||
if(type & PKT_COMPRESSED) {
|
||||
length_t ulen = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
|
||||
length_t ulen = uncompress_packet(DATA(&inpkt) + offset, (const uint8_t *)data, len, from->incompression);
|
||||
if(ulen < 0) {
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -855,25 +914,25 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t
|
|||
if(inpkt.len > MAXSIZE)
|
||||
abort();
|
||||
} else {
|
||||
memcpy(inpkt.data + offset, data, len);
|
||||
memcpy(DATA(&inpkt) + offset, data, len);
|
||||
inpkt.len = len + offset;
|
||||
}
|
||||
|
||||
/* Generate the Ethernet packet type if necessary */
|
||||
if(offset) {
|
||||
switch(inpkt.data[14] >> 4) {
|
||||
switch(DATA(&inpkt)[14] >> 4) {
|
||||
case 4:
|
||||
inpkt.data[12] = 0x08;
|
||||
inpkt.data[13] = 0x00;
|
||||
DATA(&inpkt)[12] = 0x08;
|
||||
DATA(&inpkt)[13] = 0x00;
|
||||
break;
|
||||
case 6:
|
||||
inpkt.data[12] = 0x86;
|
||||
inpkt.data[13] = 0xDD;
|
||||
DATA(&inpkt)[12] = 0x86;
|
||||
DATA(&inpkt)[13] = 0xDD;
|
||||
break;
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s (%s)",
|
||||
inpkt.data[14] >> 4, from->name, from->hostname);
|
||||
DATA(&inpkt)[14] >> 4, from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -890,7 +949,7 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
|
|||
|
||||
if(n == myself) {
|
||||
if(overwrite_mac)
|
||||
memcpy(packet->data, mymac.x, ETH_ALEN);
|
||||
memcpy(DATA(packet), mymac.x, ETH_ALEN);
|
||||
n->out_packets++;
|
||||
n->out_bytes += packet->len;
|
||||
devops.write(packet);
|
||||
|
|
@ -948,7 +1007,7 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
|||
// usually distributes the sending of broadcast packets over all nodes.
|
||||
case BMODE_MST:
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
||||
if(c->edge && c->status.mst && c != from->nexthop->connection)
|
||||
send_packet(c->node, packet);
|
||||
break;
|
||||
|
||||
|
|
@ -1002,12 +1061,14 @@ void handle_incoming_vpn_data(void *data, int flags) {
|
|||
listen_socket_t *ls = data;
|
||||
vpn_packet_t pkt;
|
||||
char *hostname;
|
||||
sockaddr_t from = {{0}};
|
||||
socklen_t fromlen = sizeof from;
|
||||
node_t *n;
|
||||
int len;
|
||||
node_id_t nullid = {};
|
||||
sockaddr_t addr = {};
|
||||
socklen_t addrlen = sizeof addr;
|
||||
node_t *from, *to;
|
||||
bool direct = false;
|
||||
|
||||
len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
|
||||
pkt.offset = 0;
|
||||
int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
|
||||
|
||||
if(len <= 0 || len > MAXSIZE) {
|
||||
if(!sockwouldblock(sockerrno))
|
||||
|
|
@ -1017,32 +1078,76 @@ void handle_incoming_vpn_data(void *data, int flags) {
|
|||
|
||||
pkt.len = len;
|
||||
|
||||
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
|
||||
sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */
|
||||
|
||||
n = lookup_node_udp(&from);
|
||||
// Try to figure out who sent this packet.
|
||||
|
||||
node_t *n = lookup_node_udp(&addr);
|
||||
|
||||
if(!n) {
|
||||
n = try_harder(&from, &pkt);
|
||||
if(n)
|
||||
update_node_udp(n, &from);
|
||||
else if(debug_level >= DEBUG_PROTOCOL) {
|
||||
hostname = sockaddr2hostname(&from);
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
|
||||
free(hostname);
|
||||
return;
|
||||
// It might be from a 1.1 node, which might have a source ID in the packet.
|
||||
pkt.offset = 2 * sizeof(node_id_t);
|
||||
from = lookup_node_id(SRCID(&pkt));
|
||||
if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) {
|
||||
if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)))
|
||||
n = from;
|
||||
else
|
||||
goto skip_harder;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
n->sock = ls - listen_socket;
|
||||
if(!n) {
|
||||
pkt.offset = 0;
|
||||
n = try_harder(&addr, &pkt);
|
||||
}
|
||||
|
||||
receive_udppacket(n, &pkt);
|
||||
skip_harder:
|
||||
if(!n) {
|
||||
if(debug_level >= DEBUG_PROTOCOL) {
|
||||
hostname = sockaddr2hostname(&addr);
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
|
||||
free(hostname);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->status.sptps) {
|
||||
pkt.offset = 2 * sizeof(node_id_t);
|
||||
|
||||
if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid)) {
|
||||
direct = true;
|
||||
from = n;
|
||||
to = myself;
|
||||
} else {
|
||||
from = lookup_node_id(SRCID(&pkt));
|
||||
to = lookup_node_id(DSTID(&pkt));
|
||||
}
|
||||
if(!from || !to) {
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
if(to != myself) {
|
||||
send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
direct = true;
|
||||
from = n;
|
||||
}
|
||||
|
||||
pkt.offset = 0;
|
||||
if(!receive_udppacket(from, &pkt))
|
||||
return;
|
||||
|
||||
n->sock = ls - listen_socket;
|
||||
if(direct && sockaddrcmp(&addr, &n->address))
|
||||
update_node_udp(n, &addr);
|
||||
}
|
||||
|
||||
void handle_device_data(void *data, int flags) {
|
||||
vpn_packet_t packet;
|
||||
|
||||
packet.offset = DEFAULT_PACKET_OFFSET;
|
||||
packet.priority = 0;
|
||||
|
||||
if(devops.read(&packet)) {
|
||||
|
|
|
|||
405
src/net_setup.c
405
src/net_setup.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_setup.c -- Setup.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
|
@ -44,15 +44,17 @@
|
|||
#include "xalloc.h"
|
||||
|
||||
char *myport;
|
||||
static char *myname;
|
||||
static io_t device_io;
|
||||
devops_t devops;
|
||||
bool device_standby = false;
|
||||
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
int autoconnect;
|
||||
bool autoconnect;
|
||||
bool disablebuggypeers;
|
||||
|
||||
char *scriptinterpreter;
|
||||
|
|
@ -71,25 +73,23 @@ bool node_read_ecdsa_public_key(node_t *n) {
|
|||
if(!read_host_config(config_tree, n->name))
|
||||
goto exit;
|
||||
|
||||
/* First, check for simple ECDSAPublicKey statement */
|
||||
/* First, check for simple Ed25519PublicKey statement */
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "ECDSAPublicKey"), &p)) {
|
||||
if(get_config_string(lookup_config(config_tree, "Ed25519PublicKey"), &p)) {
|
||||
n->ecdsa = ecdsa_set_base64_public_key(p);
|
||||
free(p);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Else, check for ECDSAPublicKeyFile statement and read it */
|
||||
/* Else, check for Ed25519PublicKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "ECDSAPublicKeyFile"), &pubname))
|
||||
if(!get_config_string(lookup_config(config_tree, "Ed25519PublicKeyFile"), &pubname))
|
||||
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, n->name);
|
||||
|
||||
fp = fopen(pubname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s", pubname, strerror(errno));
|
||||
if(!fp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n->ecdsa = ecdsa_read_pem_public_key(fp);
|
||||
fclose(fp);
|
||||
|
|
@ -114,23 +114,23 @@ bool read_ecdsa_public_key(connection_t *c) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* First, check for simple ECDSAPublicKey statement */
|
||||
/* First, check for simple Ed25519PublicKey statement */
|
||||
|
||||
if(get_config_string(lookup_config(c->config_tree, "ECDSAPublicKey"), &p)) {
|
||||
if(get_config_string(lookup_config(c->config_tree, "Ed25519PublicKey"), &p)) {
|
||||
c->ecdsa = ecdsa_set_base64_public_key(p);
|
||||
free(p);
|
||||
return c->ecdsa;
|
||||
}
|
||||
|
||||
/* Else, check for ECDSAPublicKeyFile statement and read it */
|
||||
/* Else, check for Ed25519PublicKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(c->config_tree, "ECDSAPublicKeyFile"), &fname))
|
||||
if(!get_config_string(lookup_config(c->config_tree, "Ed25519PublicKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, c->name);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA public key file `%s': %s",
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
|
|
@ -140,7 +140,7 @@ bool read_ecdsa_public_key(connection_t *c) {
|
|||
fclose(fp);
|
||||
|
||||
if(!c->ecdsa)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing ECDSA public key file `%s' failed.", fname);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
|
||||
free(fname);
|
||||
return c->ecdsa;
|
||||
}
|
||||
|
|
@ -189,15 +189,15 @@ static bool read_ecdsa_private_key(void) {
|
|||
|
||||
/* Check for PrivateKeyFile statement and read it */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "ECDSAPrivateKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s" SLASH "ecdsa_key.priv", confbase);
|
||||
if(!get_config_string(lookup_config(config_tree, "Ed25519PrivateKeyFile"), &fname))
|
||||
xasprintf(&fname, "%s" SLASH "ed25519_key.priv", confbase);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading ECDSA private key file `%s': %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 private key file `%s': %s", fname, strerror(errno));
|
||||
if(errno == ENOENT)
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Create an ECDSA keypair with `tinc -n %s generate-ecdsa-keys'.", netname ?: ".");
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Create an Ed25519 keypair with `tinc -n %s generate-ed25519-keys'.", netname ?: ".");
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -206,20 +206,20 @@ static bool read_ecdsa_private_key(void) {
|
|||
struct stat s;
|
||||
|
||||
if(fstat(fileno(fp), &s)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat ECDSA private key file `%s': %s'", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat Ed25519 private key file `%s': %s'", fname, strerror(errno));
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(s.st_mode & ~0100700)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for ECDSA private key file `%s'!", fname);
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for Ed25519 private key file `%s'!", fname);
|
||||
#endif
|
||||
|
||||
myself->connection->ecdsa = ecdsa_read_pem_private_key(fp);
|
||||
fclose(fp);
|
||||
|
||||
if(!myself->connection->ecdsa)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
|
||||
free(fname);
|
||||
return myself->connection->ecdsa;
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ static bool read_invitation_key(void) {
|
|||
invitation_key = NULL;
|
||||
}
|
||||
|
||||
xasprintf(&fname, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", confbase);
|
||||
xasprintf(&fname, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ static bool read_invitation_key(void) {
|
|||
invitation_key = ecdsa_read_pem_private_key(fp);
|
||||
fclose(fp);
|
||||
if(!invitation_key)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading ECDSA private key file `%s' failed: %s", fname, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
|
||||
}
|
||||
|
||||
free(fname);
|
||||
|
|
@ -277,6 +277,8 @@ static bool read_rsa_private_key(void) {
|
|||
if(!fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
|
||||
fname, strerror(errno));
|
||||
if(errno == ENOENT)
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Create an RSA keypair with `tinc -n %s generate-rsa-keys'.", netname ?: ".");
|
||||
free(fname);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -403,40 +405,16 @@ void load_all_nodes(void) {
|
|||
|
||||
char *get_name(void) {
|
||||
char *name = NULL;
|
||||
char *returned_name;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Name"), &name);
|
||||
|
||||
if(!name)
|
||||
return NULL;
|
||||
|
||||
if(*name == '$') {
|
||||
char *envname = getenv(name + 1);
|
||||
if(!envname) {
|
||||
if(strcmp(name + 1, "HOST")) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
|
||||
return false;
|
||||
}
|
||||
char envname[32];
|
||||
if(gethostname(envname, 32)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
envname[31] = 0;
|
||||
}
|
||||
free(name);
|
||||
name = xstrdup(envname);
|
||||
for(char *c = name; *c; c++)
|
||||
if(!isalnum(*c))
|
||||
*c = '_';
|
||||
}
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return name;
|
||||
returned_name = replace_name(name);
|
||||
free(name);
|
||||
return returned_name;
|
||||
}
|
||||
|
||||
bool setup_myself_reloadable(void) {
|
||||
|
|
@ -445,7 +423,6 @@ bool setup_myself_reloadable(void) {
|
|||
char *fmode = NULL;
|
||||
char *bmode = NULL;
|
||||
char *afname = NULL;
|
||||
char *address = NULL;
|
||||
char *space;
|
||||
bool choice;
|
||||
|
||||
|
|
@ -532,16 +509,6 @@ bool setup_myself_reloadable(void) {
|
|||
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
|
||||
get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
|
||||
|
||||
memset(&localdiscovery_address, 0, sizeof localdiscovery_address);
|
||||
if(get_config_string(lookup_config(config_tree, "LocalDiscoveryAddress"), &address)) {
|
||||
struct addrinfo *ai = str2addrinfo(address, myport, SOCK_DGRAM);
|
||||
free(address);
|
||||
if(!ai)
|
||||
return false;
|
||||
memcpy(&localdiscovery_address, ai->ai_addr, ai->ai_addrlen);
|
||||
}
|
||||
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "Mode"), &rmode)) {
|
||||
if(!strcasecmp(rmode, "router"))
|
||||
routing_mode = RMODE_ROUTER;
|
||||
|
|
@ -596,6 +563,20 @@ bool setup_myself_reloadable(void) {
|
|||
free(bmode);
|
||||
}
|
||||
|
||||
const char* const DEFAULT_BROADCAST_SUBNETS[] = { "ff:ff:ff:ff:ff:ff", "255.255.255.255", "224.0.0.0/4", "ff00::/8" };
|
||||
for (size_t i = 0; i < sizeof(DEFAULT_BROADCAST_SUBNETS) / sizeof(*DEFAULT_BROADCAST_SUBNETS); i++) {
|
||||
subnet_t *s = new_subnet();
|
||||
if (!str2net(s, DEFAULT_BROADCAST_SUBNETS[i]))
|
||||
abort();
|
||||
subnet_add(NULL, s);
|
||||
}
|
||||
for (config_t* cfg = lookup_config(config_tree, "BroadcastSubnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s;
|
||||
if (!get_config_subnet(cfg, &s))
|
||||
continue;
|
||||
subnet_add(NULL, s);
|
||||
}
|
||||
|
||||
#if !defined(SOL_IP) || !defined(IP_TOS)
|
||||
if(priorityinheritance)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
|
||||
|
|
@ -631,7 +612,15 @@ bool setup_myself_reloadable(void) {
|
|||
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
|
||||
keylifetime = 3600;
|
||||
|
||||
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
|
||||
config_t *cfg = lookup_config(config_tree, "AutoConnect");
|
||||
if(cfg) {
|
||||
if(!get_config_bool(cfg, &autoconnect)) {
|
||||
// Some backwards compatibility with when this option was an int
|
||||
int val = 0;
|
||||
get_config_int(cfg, &val);
|
||||
autoconnect = val;
|
||||
}
|
||||
}
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "DisableBuggyPeers"), &disablebuggypeers);
|
||||
|
||||
|
|
@ -640,18 +629,133 @@ bool setup_myself_reloadable(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Add listening sockets.
|
||||
*/
|
||||
static bool add_listen_address(char *address, bool bindto) {
|
||||
char *port = myport;
|
||||
|
||||
if(address) {
|
||||
char *space = strchr(address, ' ');
|
||||
if(space) {
|
||||
*space++ = 0;
|
||||
port = space;
|
||||
}
|
||||
|
||||
if(!strcmp(address, "*"))
|
||||
*address = 0;
|
||||
}
|
||||
|
||||
struct addrinfo *ai, hint = {0};
|
||||
hint.ai_family = addressfamily;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
hint.ai_flags = AI_PASSIVE;
|
||||
|
||||
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
||||
free(address);
|
||||
|
||||
if(err || !ai) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||
// Ignore duplicate addresses
|
||||
bool found = false;
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++)
|
||||
if(!memcmp(&listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(found)
|
||||
continue;
|
||||
|
||||
if(listen_sockets >= MAXSOCKETS) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
||||
return false;
|
||||
}
|
||||
|
||||
int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(tcp_fd < 0)
|
||||
continue;
|
||||
|
||||
int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(tcp_fd < 0) {
|
||||
close(tcp_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ);
|
||||
io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ);
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
|
||||
free(hostname);
|
||||
}
|
||||
|
||||
listen_socket[listen_sockets].bindto = bindto;
|
||||
memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
|
||||
listen_sockets++;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
void device_enable(void) {
|
||||
if (devops.enable)
|
||||
devops.enable();
|
||||
|
||||
/* Run tinc-up script to further initialize the tap interface */
|
||||
|
||||
char *envp[5] = {NULL};
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NAME=%s", myname);
|
||||
|
||||
execute_script("tinc-up", envp);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
}
|
||||
|
||||
void device_disable(void) {
|
||||
char *envp[5] = {NULL};
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NAME=%s", myname);
|
||||
|
||||
execute_script("tinc-down", envp);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
|
||||
if (devops.disable)
|
||||
devops.disable();
|
||||
}
|
||||
|
||||
/*
|
||||
Configure node_t myself and set up the local sockets (listen only)
|
||||
*/
|
||||
static bool setup_myself(void) {
|
||||
char *name, *hostname, *cipher, *digest, *type;
|
||||
char *address = NULL;
|
||||
bool port_specified = false;
|
||||
|
||||
if(!(name = get_name())) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
|
||||
return false;
|
||||
}
|
||||
|
||||
myname = xstrdup(name);
|
||||
myself = new_node();
|
||||
myself->connection = new_connection();
|
||||
myself->name = name;
|
||||
|
|
@ -660,9 +764,8 @@ static bool setup_myself(void) {
|
|||
|
||||
if(!get_config_string(lookup_config(config_tree, "Port"), &myport))
|
||||
myport = xstrdup("655");
|
||||
|
||||
xasprintf(&myself->hostname, "MYSELF port %s", myport);
|
||||
myself->connection->hostname = xstrdup(myself->hostname);
|
||||
else
|
||||
port_specified = true;
|
||||
|
||||
myself->connection->options = 0;
|
||||
myself->connection->protocol_major = PROT_MAJOR;
|
||||
|
|
@ -670,13 +773,25 @@ static bool setup_myself(void) {
|
|||
|
||||
myself->options |= PROT_MINOR << 24;
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental);
|
||||
if(!get_config_bool(lookup_config(config_tree, "ExperimentalProtocol"), &experimental)) {
|
||||
experimental = read_ecdsa_private_key();
|
||||
if(!experimental)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Support for SPTPS disabled.");
|
||||
} else {
|
||||
if(experimental && !read_ecdsa_private_key())
|
||||
return false;
|
||||
}
|
||||
|
||||
if(experimental && !read_ecdsa_private_key())
|
||||
return false;
|
||||
if(!read_rsa_private_key()) {
|
||||
if(experimental) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Support for legacy protocol disabled.");
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No private keys available, cannot start tinc!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!read_rsa_private_key())
|
||||
return false;
|
||||
/* Ensure myport is numeric */
|
||||
|
||||
if(!atoi(myport)) {
|
||||
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
|
||||
|
|
@ -744,7 +859,9 @@ static bool setup_myself(void) {
|
|||
if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
|
||||
cipher = xstrdup("blowfish");
|
||||
|
||||
if(!(myself->incipher = cipher_open_by_name(cipher))) {
|
||||
if(!strcasecmp(cipher, "none")) {
|
||||
myself->incipher = NULL;
|
||||
} else if(!(myself->incipher = cipher_open_by_name(cipher))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized cipher type!");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -766,7 +883,9 @@ static bool setup_myself(void) {
|
|||
if(!get_config_string(lookup_config(config_tree, "Digest"), &digest))
|
||||
digest = xstrdup("sha1");
|
||||
|
||||
if(!(myself->indigest = digest_open_by_name(digest, maclength))) {
|
||||
if(!strcasecmp(digest, "none")) {
|
||||
myself->indigest = NULL;
|
||||
} else if(!(myself->indigest = digest_open_by_name(digest, maclength))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unrecognized digest type!");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -822,6 +941,8 @@ static bool setup_myself(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "DeviceStandby"), &device_standby);
|
||||
|
||||
if(!devops.setup())
|
||||
return false;
|
||||
|
||||
|
|
@ -847,7 +968,7 @@ static bool setup_myself(void) {
|
|||
for(int i = 0; i < listen_sockets; i++) {
|
||||
salen = sizeof sa;
|
||||
if(getsockname(i + 3, &sa.sa, &salen) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -872,73 +993,25 @@ static bool setup_myself(void) {
|
|||
}
|
||||
} else {
|
||||
listen_sockets = 0;
|
||||
config_t *cfg = lookup_config(config_tree, "BindToAddress");
|
||||
int cfgs = 0;
|
||||
|
||||
do {
|
||||
for(config_t *cfg = lookup_config(config_tree, "BindToAddress"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
cfgs++;
|
||||
get_config_string(cfg, &address);
|
||||
if(cfg)
|
||||
cfg = lookup_config_next(config_tree, cfg);
|
||||
|
||||
char *port = myport;
|
||||
|
||||
if(address) {
|
||||
char *space = strchr(address, ' ');
|
||||
if(space) {
|
||||
*space++ = 0;
|
||||
port = space;
|
||||
}
|
||||
|
||||
if(!strcmp(address, "*"))
|
||||
*address = 0;
|
||||
}
|
||||
|
||||
struct addrinfo *ai, hint = {0};
|
||||
hint.ai_family = addressfamily;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
hint.ai_flags = AI_PASSIVE;
|
||||
|
||||
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
||||
free(address);
|
||||
|
||||
if(err || !ai) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
|
||||
if(!add_listen_address(address, true))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||
if(listen_sockets >= MAXSOCKETS) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
||||
return false;
|
||||
}
|
||||
for(config_t *cfg = lookup_config(config_tree, "ListenAddress"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
cfgs++;
|
||||
get_config_string(cfg, &address);
|
||||
if(!add_listen_address(address, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(tcp_fd < 0)
|
||||
continue;
|
||||
|
||||
int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(tcp_fd < 0) {
|
||||
close(tcp_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ);
|
||||
io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ);
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on %s", hostname);
|
||||
free(hostname);
|
||||
}
|
||||
|
||||
memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
|
||||
listen_sockets++;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
} while(cfg);
|
||||
if(!cfgs)
|
||||
if(!add_listen_address(address, NULL))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!listen_sockets) {
|
||||
|
|
@ -946,6 +1019,24 @@ static bool setup_myself(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* If no Port option was specified, set myport to the port used by the first listening socket. */
|
||||
|
||||
if(!port_specified || atoi(myport) == 0) {
|
||||
sockaddr_t sa;
|
||||
socklen_t salen = sizeof sa;
|
||||
if(!getsockname(listen_socket[0].udp.fd, &sa.sa, &salen)) {
|
||||
free(myport);
|
||||
sockaddr2str(&sa, NULL, &myport);
|
||||
if(!myport)
|
||||
myport = xstrdup("655");
|
||||
}
|
||||
}
|
||||
|
||||
xasprintf(&myself->hostname, "MYSELF port %s", myport);
|
||||
myself->connection->hostname = xstrdup(myself->hostname);
|
||||
|
||||
/* Done. */
|
||||
|
||||
last_config_check = now.tv_sec;
|
||||
|
||||
return true;
|
||||
|
|
@ -982,18 +1073,8 @@ bool setup_network(void) {
|
|||
if(!init_control())
|
||||
return false;
|
||||
|
||||
/* Run tinc-up script to further initialize the tap interface */
|
||||
|
||||
char *envp[5] = {NULL};
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NAME=%s", myself->name);
|
||||
|
||||
execute_script("tinc-up", envp);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
if (!device_standby)
|
||||
device_enable();
|
||||
|
||||
/* Run subnet-up scripts for our own subnets */
|
||||
|
||||
|
|
@ -1016,7 +1097,8 @@ void close_network_connections(void) {
|
|||
terminate_connection(c, false);
|
||||
}
|
||||
|
||||
list_delete_list(outgoing_list);
|
||||
if(outgoing_list)
|
||||
list_delete_list(outgoing_list);
|
||||
|
||||
if(myself && myself->connection) {
|
||||
subnet_update(myself, NULL, false);
|
||||
|
|
@ -1031,28 +1113,27 @@ void close_network_connections(void) {
|
|||
close(listen_socket[i].udp.fd);
|
||||
}
|
||||
|
||||
char *envp[5] = {NULL};
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NAME=%s", myself->name);
|
||||
|
||||
exit_requests();
|
||||
exit_edges();
|
||||
exit_subnets();
|
||||
exit_nodes();
|
||||
exit_connections();
|
||||
|
||||
execute_script("tinc-down", envp);
|
||||
if (!device_standby)
|
||||
device_disable();
|
||||
|
||||
if(myport) free(myport);
|
||||
free(myport);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
free(envp[i]);
|
||||
|
||||
devops.close();
|
||||
if (device_fd >= 0)
|
||||
io_del(&device_io);
|
||||
if (devops.close)
|
||||
devops.close();
|
||||
|
||||
exit_control();
|
||||
|
||||
free(myname);
|
||||
free(scriptextension);
|
||||
free(scriptinterpreter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
110
src/net_socket.c
110
src/net_socket.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_socket.c -- Handle various kinds of sockets.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2009 Florian Forster <octo@verplant.org>
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ static bool bind_to_interface(int sd) {
|
|||
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
|
||||
if(status) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
strerror(errno));
|
||||
sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
|
||||
|
|
@ -116,7 +116,7 @@ static bool bind_to_interface(int sd) {
|
|||
static bool bind_to_address(connection_t *c) {
|
||||
int s = -1;
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
for(int i = 0; i < listen_sockets && listen_socket[i].bindto; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family != c->address.sa.sa_family)
|
||||
continue;
|
||||
if(s >= 0)
|
||||
|
|
@ -134,7 +134,7 @@ static bool bind_to_address(connection_t *c) {
|
|||
sa.in6.sin6_port = 0;
|
||||
|
||||
if(bind(c->socket, &sa.sa, SALEN(sa.sa))) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Can't bind outgoing socket: %s", strerror(errno));
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Can't bind outgoing socket: %s", sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) {
|
||||
closesocket(nfd);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
strerror(sockerrno));
|
||||
sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
|
|
@ -247,10 +247,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof option);
|
||||
|
||||
if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf)))
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, sockstrerror(sockerrno));
|
||||
|
||||
if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf)))
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, sockstrerror(sockerrno));
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if(sa->sa.sa_family == AF_INET6)
|
||||
|
|
@ -271,8 +271,6 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
option = 1;
|
||||
setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option));
|
||||
}
|
||||
#else
|
||||
#warning No way to disable IPv4 fragmentation
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
|
||||
|
|
@ -285,8 +283,6 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
option = 1;
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option));
|
||||
}
|
||||
#else
|
||||
#warning No way to disable IPv6 fragmentation
|
||||
#endif
|
||||
|
||||
if (!bind_to_interface(nfd)) {
|
||||
|
|
@ -334,7 +330,7 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
|
|||
int fd[2];
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s", strerror(errno));
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s", sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -383,16 +379,16 @@ static void handle_meta_write(connection_t *c) {
|
|||
|
||||
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
|
||||
if(outlen <= 0) {
|
||||
if(!errno || errno == EPIPE) {
|
||||
if(!sockerrno || sockerrno == EPIPE) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)", c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Sending %d bytes to %s (%s) would block", c->outbuf.len - c->outbuf.offset, c->name, c->hostname);
|
||||
return;
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, strerror(errno));
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not send %d bytes of data to %s (%s): %s", c->outbuf.len - c->outbuf.offset, c->name, c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -405,19 +401,38 @@ static void handle_meta_io(void *data, int flags) {
|
|||
connection_t *c = data;
|
||||
|
||||
if(c->status.connecting) {
|
||||
c->status.connecting = false;
|
||||
/*
|
||||
The event loop does not protect against spurious events. Verify that we are actually connected
|
||||
by issuing an empty send() call.
|
||||
|
||||
int result;
|
||||
socklen_t len = sizeof result;
|
||||
getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
|
||||
|
||||
if(!result)
|
||||
finish_connecting(c);
|
||||
else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result));
|
||||
terminate_connection(c, false);
|
||||
Note that the behavior of send() on potentially unconnected sockets differ between platforms:
|
||||
+------------+-----------+-------------+-----------+
|
||||
| Event | POSIX | Linux | Windows |
|
||||
+------------+-----------+-------------+-----------+
|
||||
| Spurious | ENOTCONN | EWOULDBLOCK | ENOTCONN |
|
||||
| Failed | ENOTCONN | (cause) | ENOTCONN |
|
||||
| Successful | (success) | (success) | (success) |
|
||||
+------------+-----------+-------------+-----------+
|
||||
*/
|
||||
if (send(c->socket, NULL, 0, 0) != 0) {
|
||||
if (sockwouldblock(sockerrno))
|
||||
return;
|
||||
int socket_error;
|
||||
if (!socknotconn(sockerrno))
|
||||
socket_error = sockerrno;
|
||||
else {
|
||||
socklen_t len = sizeof socket_error;
|
||||
getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&socket_error, &len);
|
||||
}
|
||||
if (socket_error) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(socket_error));
|
||||
terminate_connection(c, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
c->status.connecting = false;
|
||||
finish_connecting(c);
|
||||
}
|
||||
|
||||
if(flags & IO_WRITE)
|
||||
|
|
@ -547,6 +562,39 @@ begin:
|
|||
return true;
|
||||
}
|
||||
|
||||
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
|
||||
static struct addrinfo *get_known_addresses(node_t *n) {
|
||||
struct addrinfo *ai = NULL;
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
if(!e->reverse)
|
||||
continue;
|
||||
|
||||
bool found = false;
|
||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||
if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found)
|
||||
continue;
|
||||
|
||||
struct addrinfo *nai = xzalloc(sizeof *nai);
|
||||
if(ai)
|
||||
ai->ai_next = nai;
|
||||
ai = nai;
|
||||
ai->ai_family = e->reverse->address.sa.sa_family;
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
ai->ai_protocol = IPPROTO_TCP;
|
||||
ai->ai_addrlen = SALEN(e->reverse->address.sa);
|
||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
||||
memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||
timeout_del(&outgoing->ev);
|
||||
|
||||
|
|
@ -564,8 +612,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
|||
outgoing->cfg = lookup_config(outgoing->config_tree, "Address");
|
||||
|
||||
if(!outgoing->cfg) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No address specified for %s", outgoing->name);
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
do_outgoing_connection(outgoing);
|
||||
|
|
@ -594,7 +646,6 @@ void handle_new_meta_connection(void *data, int flags) {
|
|||
// Check if we get many connections from the same host
|
||||
|
||||
static sockaddr_t prev_sa;
|
||||
static time_t prev_time;
|
||||
static int tarpit = -1;
|
||||
|
||||
if(tarpit >= 0) {
|
||||
|
|
@ -621,7 +672,6 @@ void handle_new_meta_connection(void *data, int flags) {
|
|||
}
|
||||
|
||||
memcpy(&prev_sa, &sa, sizeof sa);
|
||||
prev_time = now.tv_sec;
|
||||
|
||||
// Check if we get many connections from different hosts
|
||||
|
||||
|
|
@ -770,7 +820,7 @@ void try_outgoing_connections(void) {
|
|||
if(c->outgoing && c->outgoing->timeout == -1) {
|
||||
c->outgoing = NULL;
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
|
||||
terminate_connection(c, c->status.active);
|
||||
terminate_connection(c, c->edge);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
55
src/node.c
55
src/node.c
|
|
@ -30,8 +30,12 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static digest_t *sha256;
|
||||
|
||||
splay_tree_t *node_tree;
|
||||
static splay_tree_t *node_id_tree;
|
||||
static hash_t *node_udp_cache;
|
||||
static hash_t *node_id_cache;
|
||||
|
||||
node_t *myself;
|
||||
|
||||
|
|
@ -39,14 +43,26 @@ static int node_compare(const node_t *a, const node_t *b) {
|
|||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void exit_nodes(void) {
|
||||
hash_free(node_id_cache);
|
||||
hash_free(node_udp_cache);
|
||||
splay_delete_tree(node_id_tree);
|
||||
splay_delete_tree(node_tree);
|
||||
|
||||
digest_close(sha256);
|
||||
}
|
||||
|
||||
node_t *new_node(void) {
|
||||
|
|
@ -93,16 +109,23 @@ void free_node(node_t *n) {
|
|||
}
|
||||
|
||||
void node_add(node_t *n) {
|
||||
digest_create(sha256, n->name, strlen(n->name), &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);
|
||||
|
||||
for splay_each(subnet_t, s, n->subnet_tree)
|
||||
subnet_del(n, s);
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree)
|
||||
edge_del(e);
|
||||
|
||||
splay_delete(node_id_tree, n);
|
||||
splay_delete(node_tree, n);
|
||||
}
|
||||
|
||||
|
|
@ -114,6 +137,18 @@ node_t *lookup_node(char *name) {
|
|||
return splay_search(node_tree, &n);
|
||||
}
|
||||
|
||||
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 *lookup_node_udp(const sockaddr_t *sa) {
|
||||
return hash_search(node_udp_cache, sa);
|
||||
}
|
||||
|
|
@ -124,7 +159,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
|||
return;
|
||||
}
|
||||
|
||||
hash_insert(node_udp_cache, &n->address, NULL);
|
||||
hash_delete(node_udp_cache, &n->address);
|
||||
|
||||
if(sa) {
|
||||
n->address = *sa;
|
||||
|
|
@ -140,15 +175,27 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
|||
n->hostname = sockaddr2hostname(&n->address);
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
|
||||
}
|
||||
|
||||
/* 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->mtuprobes = 0;
|
||||
n->minmtu = 0;
|
||||
n->maxmtu = MTU;
|
||||
}
|
||||
|
||||
bool dump_nodes(connection_t *c) {
|
||||
for splay_each(node_t, n, node_tree)
|
||||
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
|
||||
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(n->outcipher),
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
|
||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,13 @@ typedef struct node_status_t {
|
|||
unsigned int indirect:1; /* 1 if this node is not directly reachable by us */
|
||||
unsigned int sptps:1; /* 1 if this node supports SPTPS */
|
||||
unsigned int udp_confirmed:1; /* 1 if the address is one that we received UDP traffic on */
|
||||
unsigned int unused:24;
|
||||
unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */
|
||||
unsigned int unused:23;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
char *name; /* name of this node */
|
||||
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 */
|
||||
|
|
@ -110,6 +112,7 @@ extern void free_node(node_t *);
|
|||
extern void node_add(node_t *);
|
||||
extern void node_del(node_t *);
|
||||
extern node_t *lookup_node(char *);
|
||||
extern node_t *lookup_node_id(const node_id_t *);
|
||||
extern node_t *lookup_node_udp(const sockaddr_t *);
|
||||
extern bool dump_nodes(struct connection_t *);
|
||||
extern bool dump_traffic(struct connection_t *);
|
||||
|
|
|
|||
|
|
@ -30,15 +30,8 @@
|
|||
struct cipher {
|
||||
EVP_CIPHER_CTX ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
struct cipher_counter *counter;
|
||||
};
|
||||
|
||||
typedef struct cipher_counter {
|
||||
unsigned char counter[CIPHER_MAX_IV_SIZE];
|
||||
unsigned char block[CIPHER_MAX_IV_SIZE];
|
||||
int n;
|
||||
} cipher_counter_t;
|
||||
|
||||
static cipher_t *cipher_open(const EVP_CIPHER *evp_cipher) {
|
||||
cipher_t *cipher = xzalloc(sizeof *cipher);
|
||||
cipher->cipher = evp_cipher;
|
||||
|
|
@ -76,7 +69,6 @@ void cipher_close(cipher_t *cipher) {
|
|||
return;
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
|
||||
free(cipher->counter);
|
||||
free(cipher);
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +76,7 @@ size_t cipher_keylength(const cipher_t *cipher) {
|
|||
if(!cipher || !cipher->cipher)
|
||||
return 0;
|
||||
|
||||
return cipher->cipher->key_len + cipher->cipher->block_size;
|
||||
return cipher->cipher->key_len + cipher->cipher->iv_len;
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
|
|
@ -117,70 +109,6 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
|
|||
return false;
|
||||
}
|
||||
|
||||
bool cipher_set_counter(cipher_t *cipher, const void *counter, size_t len) {
|
||||
if(len > cipher->cipher->block_size - 4) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter too long");
|
||||
abort();
|
||||
}
|
||||
|
||||
memcpy(cipher->counter->counter + cipher->cipher->block_size - len, counter, len);
|
||||
memset(cipher->counter->counter, 0, 4);
|
||||
cipher->counter->n = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_set_counter_key(cipher_t *cipher, void *key) {
|
||||
int result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, NULL);
|
||||
if(!result) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!cipher->counter)
|
||||
cipher->counter = xzalloc(sizeof *cipher->counter);
|
||||
else
|
||||
cipher->counter->n = 0;
|
||||
|
||||
memcpy(cipher->counter->counter, (unsigned char *)key + cipher->cipher->key_len, cipher->cipher->block_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_counter_xor(cipher_t *cipher, const void *indata, size_t inlen, void *outdata) {
|
||||
if(!cipher->counter) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Counter not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char *in = indata;
|
||||
unsigned char *out = outdata;
|
||||
|
||||
while(inlen--) {
|
||||
// Encrypt the new counter value if we need it
|
||||
if(!cipher->counter->n) {
|
||||
int len;
|
||||
if(!EVP_EncryptUpdate(&cipher->ctx, cipher->counter->block, &len, cipher->counter->counter, cipher->cipher->block_size)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the counter value
|
||||
for(int i = 0; i < cipher->cipher->block_size; i++)
|
||||
if(++cipher->counter->counter[i])
|
||||
break;
|
||||
}
|
||||
|
||||
*out++ = *in++ ^ cipher->counter->block[cipher->counter->n++];
|
||||
|
||||
if(cipher->counter->n >= cipher->cipher->block_size)
|
||||
cipher->counter->n = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
||||
Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
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
|
||||
|
|
@ -25,8 +25,65 @@
|
|||
|
||||
#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) {
|
||||
RAND_load_file("/dev/urandom", 1024);
|
||||
random_init();
|
||||
|
||||
ENGINE_load_builtin_engines();
|
||||
ENGINE_register_all_complete();
|
||||
|
|
@ -42,8 +99,7 @@ void crypto_init(void) {
|
|||
|
||||
void crypto_exit(void) {
|
||||
EVP_cleanup();
|
||||
}
|
||||
|
||||
void randomize(void *out, size_t outlen) {
|
||||
RAND_pseudo_bytes(out, outlen);
|
||||
ERR_free_strings();
|
||||
ENGINE_cleanup();
|
||||
random_exit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange 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 <openssl/err.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#define __TINC_ECDH_INTERNAL__
|
||||
typedef EC_KEY ecdh_t;
|
||||
|
||||
#include "../ecdh.h"
|
||||
#include "../logger.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
ecdh_t *ecdh_generate_public(void *pubkey) {
|
||||
ecdh_t *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!ecdh) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EC_KEY_generate_key(ecdh)) {
|
||||
EC_KEY_free(ecdh);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Generating EC key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EC_POINT *point = EC_KEY_get0_public_key(ecdh);
|
||||
if(!point) {
|
||||
EC_KEY_free(ecdh);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Getting public key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t result = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
EC_KEY_free(ecdh);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting EC_POINT to binary failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ecdh;
|
||||
}
|
||||
|
||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(ecdh));
|
||||
if(!point) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC_POINT_new() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
EC_KEY_free(ecdh);
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = EC_POINT_oct2point(EC_KEY_get0_group(ecdh), point, pubkey, ECDH_SIZE, NULL);
|
||||
if(!result) {
|
||||
EC_POINT_free(point);
|
||||
EC_KEY_free(ecdh);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Converting binary to EC_POINT failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = ECDH_compute_key(shared, ECDH_SIZE, point, ecdh, NULL);
|
||||
EC_POINT_free(point);
|
||||
EC_KEY_free(ecdh);
|
||||
|
||||
if(!result) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Computing Elliptic Curve Diffie-Hellman shared key failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ecdh_free(ecdh_t *ecdh) {
|
||||
if(ecdh)
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
|
|
@ -1,131 +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 <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#define __TINC_ECDSA_INTERNAL__
|
||||
typedef EC_KEY ecdsa_t;
|
||||
|
||||
#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) {
|
||||
ecdsa_t *ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
if(!ecdsa) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "EC_KEY_new_by_curve_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int len = strlen(p);
|
||||
unsigned char pubkey[len / 4 * 3 + 3];
|
||||
const unsigned char *ppubkey = pubkey;
|
||||
len = b64decode(p, (char *)pubkey, len);
|
||||
|
||||
if(!o2i_ECPublicKey(&ecdsa, &ppubkey, len)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "o2i_ECPublicKey failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
EC_KEY_free(ecdsa);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
||||
unsigned char *pubkey = NULL;
|
||||
int len = i2o_ECPublicKey(ecdsa, &pubkey);
|
||||
|
||||
char *base64 = xmalloc(len * 4 / 3 + 5);
|
||||
b64encode((char *)pubkey, base64, len);
|
||||
|
||||
free(pubkey);
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
// Read PEM ECDSA keys
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL);
|
||||
|
||||
if(!ecdsa)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL);
|
||||
|
||||
if(!ecdsa)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read ECDSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
||||
return ECDSA_size(ecdsa);
|
||||
}
|
||||
|
||||
// TODO: standardise output format?
|
||||
|
||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
unsigned int siglen = ECDSA_size(ecdsa);
|
||||
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
memset(sig, 0, siglen);
|
||||
|
||||
if(!ECDSA_sign(0, hash, sizeof hash, sig, &siglen, ecdsa)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_sign() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
unsigned int siglen = ECDSA_size(ecdsa);
|
||||
|
||||
unsigned char hash[SHA512_DIGEST_LENGTH];
|
||||
SHA512(in, len, hash);
|
||||
|
||||
if(!ECDSA_verify(0, hash, sizeof hash, sig, siglen, ecdsa)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "ECDSA_verify() failed: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
||||
if(ecdsa)
|
||||
EC_KEY_free(ecdsa);
|
||||
}
|
||||
|
|
@ -61,8 +61,10 @@ rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) {
|
|||
rsa_t *rsa_read_pem_public_key(FILE *fp) {
|
||||
rsa_t *rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
|
||||
|
||||
if(!rsa)
|
||||
if(!rsa) {
|
||||
rewind(fp);
|
||||
rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if(!rsa)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
#include "version.h"
|
||||
|
||||
/* If zero, don't detach from the terminal. */
|
||||
bool do_detach = true;
|
||||
|
|
@ -108,6 +109,8 @@ static bool install_service(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
io_t stop_io;
|
||||
|
||||
DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
||||
switch(request) {
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
|
|
@ -124,10 +127,11 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
|||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
event_exit();
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwWaitHint = 1000;
|
||||
status.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
if (WSASetEvent(stop_io.event) == FALSE)
|
||||
abort();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +213,7 @@ bool detach(void) {
|
|||
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
|
||||
VERSION, __DATE__, __TIME__, debug_level);
|
||||
VERSION, BUILD_DATE, BUILD_TIME, debug_level);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ extern bool detach(void);
|
|||
extern bool kill_other(int);
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
extern io_t stop_io;
|
||||
extern bool init_service(void);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -55,17 +55,6 @@ static char (*request_name[]) = {
|
|||
|
||||
static splay_tree_t *past_request_tree;
|
||||
|
||||
bool check_id(const char *id) {
|
||||
if(!id || !*id)
|
||||
return false;
|
||||
|
||||
for(; *id; id++)
|
||||
if(!isalnum(*id) && *id != '_')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Generic request routines - takes care of logging and error
|
||||
detection as well */
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
/* Protocol version. Different major versions are incompatible. */
|
||||
|
||||
#define PROT_MAJOR 17
|
||||
#define PROT_MINOR 3 /* Should not exceed 255! */
|
||||
#define PROT_MINOR 4 /* Should not exceed 255! */
|
||||
|
||||
/* Silly Windows */
|
||||
|
||||
|
|
@ -81,7 +81,6 @@ extern ecdsa_t *invitation_key;
|
|||
extern bool send_request(struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
|
||||
extern void forward_request(struct connection_t *, const char *);
|
||||
extern bool receive_request(struct connection_t *, const char *);
|
||||
extern bool check_id(const char *);
|
||||
|
||||
extern void init_requests(void);
|
||||
extern void exit_requests(void);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol_auth.c -- handle the meta-protocol, authentication
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-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
|
||||
|
|
@ -172,7 +172,7 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
|
|||
return false;
|
||||
}
|
||||
|
||||
fprintf(f, "ECDSAPublicKey = %s\n", data);
|
||||
fprintf(f, "Ed25519PublicKey = %s\n", data);
|
||||
fclose(f);
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);
|
||||
|
|
@ -198,7 +198,7 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool receive_invitation_sptps(void *handle, uint8_t type, const char *data, uint16_t len) {
|
||||
static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) {
|
||||
connection_t *c = handle;
|
||||
|
||||
if(type == 128)
|
||||
|
|
@ -380,12 +380,13 @@ bool id_h(connection_t *c, const char *request) {
|
|||
|
||||
if(experimental)
|
||||
read_ecdsa_public_key(c);
|
||||
} else {
|
||||
if(c->protocol_minor && !ecdsa_active(c->ecdsa))
|
||||
c->protocol_minor = 1;
|
||||
/* Ignore failures if no key known yet */
|
||||
}
|
||||
|
||||
/* Forbid version rollback for nodes whose ECDSA key we know */
|
||||
if(c->protocol_minor && !ecdsa_active(c->ecdsa))
|
||||
c->protocol_minor = 1;
|
||||
|
||||
/* Forbid version rollback for nodes whose Ed25519 key we know */
|
||||
|
||||
if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Peer %s (%s) tries to roll back protocol version to %d.%d",
|
||||
|
|
@ -411,6 +412,11 @@ bool id_h(connection_t *c, const char *request) {
|
|||
}
|
||||
|
||||
bool send_metakey(connection_t *c) {
|
||||
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;
|
||||
}
|
||||
|
||||
if(!read_rsa_public_key(c))
|
||||
return false;
|
||||
|
||||
|
|
@ -420,7 +426,7 @@ bool send_metakey(connection_t *c) {
|
|||
if(!(c->outdigest = digest_open_sha1(-1)))
|
||||
return false;
|
||||
|
||||
size_t len = rsa_size(c->rsa);
|
||||
const size_t len = rsa_size(c->rsa);
|
||||
char key[len];
|
||||
char enckey[len];
|
||||
char hexkey[2 * len + 1];
|
||||
|
|
@ -477,9 +483,12 @@ bool send_metakey(connection_t *c) {
|
|||
}
|
||||
|
||||
bool metakey_h(connection_t *c, const char *request) {
|
||||
if(!myself->connection->rsa)
|
||||
return false;
|
||||
|
||||
char hexkey[MAX_STRING_SIZE];
|
||||
int cipher, digest, maclength, compression;
|
||||
size_t len = rsa_size(myself->connection->rsa);
|
||||
const size_t len = rsa_size(myself->connection->rsa);
|
||||
char enckey[len];
|
||||
char key[len];
|
||||
|
||||
|
|
@ -513,14 +522,22 @@ bool metakey_h(connection_t *c, const char *request) {
|
|||
|
||||
/* Check and lookup cipher and digest algorithms */
|
||||
|
||||
if(!(c->incipher = cipher_open_by_nid(cipher)) || !cipher_set_key_from_rsa(c->incipher, key, len, false)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
if(cipher) {
|
||||
if(!(c->incipher = cipher_open_by_nid(cipher)) || !cipher_set_key_from_rsa(c->incipher, key, len, false)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
c->incipher = NULL;
|
||||
}
|
||||
|
||||
if(!(c->indigest = digest_open_by_nid(digest, -1))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
if(digest) {
|
||||
if(!(c->indigest = digest_open_by_nid(digest, -1))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
c->indigest = NULL;
|
||||
}
|
||||
|
||||
c->status.decryptin = true;
|
||||
|
|
@ -531,7 +548,7 @@ bool metakey_h(connection_t *c, const char *request) {
|
|||
}
|
||||
|
||||
bool send_challenge(connection_t *c) {
|
||||
size_t len = rsa_size(c->rsa);
|
||||
const size_t len = rsa_size(c->rsa);
|
||||
char buffer[len * 2 + 1];
|
||||
|
||||
if(!c->hischallenge)
|
||||
|
|
@ -551,8 +568,11 @@ bool send_challenge(connection_t *c) {
|
|||
}
|
||||
|
||||
bool challenge_h(connection_t *c, const char *request) {
|
||||
if(!myself->connection->rsa)
|
||||
return false;
|
||||
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
size_t len = rsa_size(myself->connection->rsa);
|
||||
const size_t len = rsa_size(myself->connection->rsa);
|
||||
size_t digestlen = digest_length(c->indigest);
|
||||
char digest[digestlen];
|
||||
|
||||
|
|
@ -628,7 +648,7 @@ bool chal_reply_h(connection_t *c, const char *request) {
|
|||
}
|
||||
|
||||
static bool send_upgrade(connection_t *c) {
|
||||
/* Special case when protocol_minor is 1: the other end is ECDSA capable,
|
||||
/* Special case when protocol_minor is 1: the other end is Ed25519 capable,
|
||||
* but doesn't know our key yet. So send it now. */
|
||||
|
||||
char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
|
||||
|
|
@ -672,7 +692,8 @@ bool send_ack(connection_t *c) {
|
|||
if(choice)
|
||||
c->options |= OPTION_CLAMP_MSS;
|
||||
|
||||
get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
|
||||
if(!get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight))
|
||||
get_config_int(lookup_config(config_tree, "Weight"), &c->estimated_weight);
|
||||
|
||||
return send_request(c, "%d %s %d %x", ACK, myport, c->estimated_weight, (c->options & 0xffffff) | (experimental ? (PROT_MINOR << 24) : 0));
|
||||
}
|
||||
|
|
@ -716,12 +737,26 @@ static bool upgrade_h(connection_t *c, const char *request) {
|
|||
}
|
||||
|
||||
if(ecdsa_active(c->ecdsa) || read_ecdsa_public_key(c)) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Already have ECDSA public key from %s (%s), not upgrading.", c->name, c->hostname);
|
||||
char *knownkey = ecdsa_get_base64_public_key(c->ecdsa);
|
||||
bool different = strcmp(knownkey, pubkey);
|
||||
free(knownkey);
|
||||
if(different) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Already have an Ed25519 public key from %s (%s) which is different from the one presented now!", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Already have Ed25519 public key from %s (%s), ignoring.", c->name, c->hostname);
|
||||
c->allow_request = TERMREQ;
|
||||
return send_termreq(c);
|
||||
}
|
||||
|
||||
c->ecdsa = ecdsa_set_base64_public_key(pubkey);
|
||||
if(!c->ecdsa) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Got bad Ed25519 public key from %s (%s), not upgrading.", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Got ECDSA public key from %s (%s), upgrading!", c->name, c->hostname);
|
||||
append_config_file(c->name, "ECDSAPublicKey", pubkey);
|
||||
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;
|
||||
return send_termreq(c);
|
||||
}
|
||||
|
|
@ -795,7 +830,6 @@ bool ack_h(connection_t *c, const char *request) {
|
|||
/* Activate this connection */
|
||||
|
||||
c->allow_request = ALL;
|
||||
c->status.active = true;
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection with %s (%s) activated", c->name,
|
||||
c->hostname);
|
||||
|
|
@ -812,6 +846,16 @@ bool ack_h(connection_t *c, const char *request) {
|
|||
sockaddr2str(&c->address, &hisaddress, NULL);
|
||||
c->edge->address = str2sockaddr(hisaddress, hisport);
|
||||
free(hisaddress);
|
||||
sockaddr_t local_sa;
|
||||
socklen_t local_salen = sizeof local_sa;
|
||||
if (getsockname(c->socket, &local_sa.sa, &local_salen) < 0)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get local socket address for connection with %s", c->name);
|
||||
else {
|
||||
char *local_address;
|
||||
sockaddr2str(&local_sa, &local_address, NULL);
|
||||
c->edge->local_address = str2sockaddr(local_address, myport);
|
||||
free(local_address);
|
||||
}
|
||||
c->edge->weight = (weight + c->estimated_weight) / 2;
|
||||
c->edge->connection = c;
|
||||
c->edge->options = c->options;
|
||||
|
|
|
|||
|
|
@ -37,14 +37,19 @@
|
|||
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", ADD_EDGE, rand(),
|
||||
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);
|
||||
e->options, e->weight, local_address, local_port);
|
||||
|
||||
free(address);
|
||||
free(port);
|
||||
free(local_address);
|
||||
free(local_port);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
|
@ -56,12 +61,15 @@ 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];
|
||||
sockaddr_t address;
|
||||
char address_local[MAX_STRING_SIZE] = "unknown";
|
||||
char port_local[MAX_STRING_SIZE] = "unknown";
|
||||
sockaddr_t address, local_address;
|
||||
uint32_t options;
|
||||
int weight;
|
||||
|
||||
if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d",
|
||||
from_name, to_name, to_address, to_port, &options, &weight) != 6) {
|
||||
int parameter_count = sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d "MAX_STRING" "MAX_STRING,
|
||||
from_name, to_name, to_address, to_port, &options, &weight, address_local, port_local);
|
||||
if (parameter_count != 6 && parameter_count != 8) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
|
||||
c->hostname);
|
||||
return false;
|
||||
|
|
@ -109,13 +117,14 @@ 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);
|
||||
|
||||
/* Check if edge already exists */
|
||||
|
||||
e = lookup_edge(from, to);
|
||||
|
||||
if(e) {
|
||||
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
|
||||
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address) || sockaddrcmp(&e->local_address, &local_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);
|
||||
|
|
@ -145,6 +154,7 @@ bool add_edge_h(connection_t *c, const char *request) {
|
|||
e->from = from;
|
||||
e->to = to;
|
||||
e->address = address;
|
||||
e->local_address = local_address;
|
||||
e->options = options;
|
||||
e->weight = weight;
|
||||
edge_add(e);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol_key.c -- handle the meta-protocol, key exchange
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-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
|
||||
|
|
@ -41,7 +41,7 @@ void send_key_changed(void) {
|
|||
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
|
||||
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c->status.active && c->node && c->node->status.reachable && !c->node->status.sptps)
|
||||
if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps)
|
||||
send_ans_key(c->node);
|
||||
|
||||
/* Force key exchange for connections using SPTPS */
|
||||
|
|
@ -87,7 +87,7 @@ bool key_changed_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool send_initial_sptps_data(void *handle, uint8_t type, const char *data, size_t 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;
|
||||
char buf[len * 4 / 3 + 5];
|
||||
|
|
@ -98,7 +98,7 @@ static bool send_initial_sptps_data(void *handle, uint8_t type, const char *data
|
|||
bool send_req_key(node_t *to) {
|
||||
if(to->status.sptps) {
|
||||
if(!node_read_ecdsa_public_key(to)) {
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No ECDSA key known for %s (%s)", to->name, to->hostname);
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", to->name, to->hostname);
|
||||
send_request(to->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, to->name, REQ_PUBKEY);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -124,6 +124,11 @@ bool send_req_key(node_t *to) {
|
|||
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
|
||||
switch(reqno) {
|
||||
case REQ_PUBKEY: {
|
||||
if(!node_read_ecdsa_public_key(from)) {
|
||||
/* Request their key *before* we send our key back. Otherwise the first SPTPS packet from them will get dropped. */
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Preemptively requesting Ed25519 key for %s (%s)", from->name, from->hostname);
|
||||
send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
|
||||
}
|
||||
char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
|
||||
send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey);
|
||||
free(pubkey);
|
||||
|
|
@ -142,14 +147,14 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(DEBUG_PROTOCOL, LOG_INFO, "Learned ECDSA public key from %s (%s)", from->name, from->hostname);
|
||||
append_config_file(from->name, "ECDSAPublicKey", pubkey);
|
||||
logger(DEBUG_PROTOCOL, LOG_INFO, "Learned Ed25519 public key from %s (%s)", from->name, from->hostname);
|
||||
append_config_file(from->name, "Ed25519PublicKey", pubkey);
|
||||
return true;
|
||||
}
|
||||
|
||||
case REQ_KEY: {
|
||||
if(!node_read_ecdsa_public_key(from)) {
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No ECDSA key known for %s (%s)", from->name, from->hostname);
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", from->name, from->hostname);
|
||||
send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -250,6 +255,7 @@ 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 */
|
||||
send_request(to->nexthop->connection, "%s", request);
|
||||
}
|
||||
|
||||
|
|
@ -260,25 +266,32 @@ bool send_ans_key(node_t *to) {
|
|||
if(to->status.sptps)
|
||||
abort();
|
||||
|
||||
size_t keylen = cipher_keylength(myself->incipher);
|
||||
size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
|
||||
char key[keylen * 2 + 1];
|
||||
|
||||
randomize(key, keylen);
|
||||
|
||||
cipher_close(to->incipher);
|
||||
digest_close(to->indigest);
|
||||
|
||||
to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
|
||||
to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
|
||||
if(myself->incipher) {
|
||||
to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
|
||||
if(!to->incipher)
|
||||
abort();
|
||||
if(!cipher_set_key(to->incipher, key, false))
|
||||
abort();
|
||||
}
|
||||
|
||||
if(myself->indigest) {
|
||||
to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
|
||||
if(!to->indigest)
|
||||
abort();
|
||||
if(!digest_set_key(to->indigest, key, keylen))
|
||||
abort();
|
||||
}
|
||||
|
||||
to->incompression = myself->incompression;
|
||||
|
||||
if(!to->incipher || !to->indigest)
|
||||
abort();
|
||||
|
||||
randomize(key, keylen);
|
||||
if(!cipher_set_key(to->incipher, key, false))
|
||||
abort();
|
||||
if(!digest_set_key(to->indigest, key, keylen))
|
||||
abort();
|
||||
|
||||
bin2hex(key, key, keylen);
|
||||
|
||||
// Reset sequence number and late packet window
|
||||
|
|
@ -386,7 +399,9 @@ 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))
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
|
@ -395,14 +410,22 @@ bool ans_key_h(connection_t *c, const char *request) {
|
|||
|
||||
/* Check and lookup cipher and digest algorithms */
|
||||
|
||||
if(!(from->outcipher = cipher_open_by_nid(cipher))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
|
||||
return false;
|
||||
if(cipher) {
|
||||
if(!(from->outcipher = cipher_open_by_nid(cipher))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
from->outcipher = NULL;
|
||||
}
|
||||
|
||||
if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
|
||||
return false;
|
||||
if(digest) {
|
||||
if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
from->outdigest = NULL;
|
||||
}
|
||||
|
||||
if(maclength != digest_length(from->outdigest)) {
|
||||
|
|
@ -414,16 +437,16 @@ bool ans_key_h(connection_t *c, const char *request) {
|
|||
|
||||
keylen = hex2bin(key, key, sizeof key);
|
||||
|
||||
if(keylen != cipher_keylength(from->outcipher)) {
|
||||
if(keylen != (from->outcipher ? cipher_keylength(from->outcipher) : 1)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Update our copy of the origin's packet key */
|
||||
|
||||
if(!cipher_set_key(from->outcipher, key, true))
|
||||
if(from->outcipher && !cipher_set_key(from->outcipher, key, true))
|
||||
return false;
|
||||
if(!digest_set_key(from->outdigest, key, keylen))
|
||||
if(from->outdigest && !digest_set_key(from->outdigest, key, keylen))
|
||||
return false;
|
||||
|
||||
from->status.validkey = true;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) {
|
|||
if(!send_request(c, "%d %hd", PACKET, packet->len))
|
||||
return false;
|
||||
|
||||
return send_meta(c, (char *)packet->data, packet->len);
|
||||
return send_meta(c, (char *)DATA(packet), packet->len);
|
||||
}
|
||||
|
||||
bool tcppacket_h(connection_t *c, const char *request) {
|
||||
|
|
|
|||
|
|
@ -32,12 +32,9 @@
|
|||
#include "route.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET)
|
||||
#if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET) && defined(SIOCGIFINDEX)
|
||||
static char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_ll sa;
|
||||
|
|
@ -86,16 +83,17 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
close(device_fd); device_fd = -1;
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
|
|
@ -103,8 +101,6 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
packet->len = inlen;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
|
|
@ -115,29 +111,20 @@ 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(write(device_fd, packet->data, packet->len) < 0) {
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t raw_socket_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
||||
#else
|
||||
|
|
@ -152,6 +139,5 @@ const devops_t raw_socket_devops = {
|
|||
.close = NULL,
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.dump_stats = NULL,
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
225
src/route.c
225
src/route.c
|
|
@ -115,16 +115,16 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
|
||||
/* Find TCP header */
|
||||
int start = ether_size;
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
start += 4;
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
type = DATA(packet)[16] << 8 | DATA(packet)[17];
|
||||
}
|
||||
|
||||
if(type == ETH_P_IP && packet->data[start + 9] == 6)
|
||||
start += (packet->data[start] & 0xf) * 4;
|
||||
else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6)
|
||||
if(type == ETH_P_IP && DATA(packet)[start + 9] == 6)
|
||||
start += (DATA(packet)[start] & 0xf) * 4;
|
||||
else if(type == ETH_P_IPV6 && DATA(packet)[start + 6] == 6)
|
||||
start += 40;
|
||||
else
|
||||
return;
|
||||
|
|
@ -133,38 +133,38 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
return;
|
||||
|
||||
/* Use data offset field to calculate length of options field */
|
||||
int len = ((packet->data[start + 12] >> 4) - 5) * 4;
|
||||
int len = ((DATA(packet)[start + 12] >> 4) - 5) * 4;
|
||||
|
||||
if(packet->len < start + 20 + len)
|
||||
return;
|
||||
|
||||
/* Search for MSS option header */
|
||||
for(int i = 0; i < len;) {
|
||||
if(packet->data[start + 20 + i] == 0)
|
||||
if(DATA(packet)[start + 20 + i] == 0)
|
||||
break;
|
||||
|
||||
if(packet->data[start + 20 + i] == 1) {
|
||||
if(DATA(packet)[start + 20 + i] == 1) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(i > len - 2 || i > len - packet->data[start + 21 + i])
|
||||
if(i > len - 2 || i > len - DATA(packet)[start + 21 + i])
|
||||
break;
|
||||
|
||||
if(packet->data[start + 20 + i] != 2) {
|
||||
if(packet->data[start + 21 + i] < 2)
|
||||
if(DATA(packet)[start + 20 + i] != 2) {
|
||||
if(DATA(packet)[start + 21 + i] < 2)
|
||||
break;
|
||||
i += packet->data[start + 21 + i];
|
||||
i += DATA(packet)[start + 21 + i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(packet->data[start + 21] != 4)
|
||||
if(DATA(packet)[start + 21] != 4)
|
||||
break;
|
||||
|
||||
/* Found it */
|
||||
uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
|
||||
uint16_t oldmss = DATA(packet)[start + 22 + i] << 8 | DATA(packet)[start + 23 + i];
|
||||
uint16_t newmss = mtu - start - 20;
|
||||
uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
|
||||
uint16_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17];
|
||||
|
||||
if(oldmss <= newmss)
|
||||
break;
|
||||
|
|
@ -172,23 +172,23 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
logger(DEBUG_TRAFFIC, LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
|
||||
|
||||
/* Update the MSS value and the checksum */
|
||||
packet->data[start + 22 + i] = newmss >> 8;
|
||||
packet->data[start + 23 + i] = newmss & 0xff;
|
||||
DATA(packet)[start + 22 + i] = newmss >> 8;
|
||||
DATA(packet)[start + 23 + i] = newmss & 0xff;
|
||||
csum ^= 0xffff;
|
||||
csum -= oldmss;
|
||||
csum += newmss;
|
||||
csum ^= 0xffff;
|
||||
packet->data[start + 16] = csum >> 8;
|
||||
packet->data[start + 17] = csum & 0xff;
|
||||
DATA(packet)[start + 16] = csum >> 8;
|
||||
DATA(packet)[start + 17] = csum & 0xff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_mac_addresses(vpn_packet_t *packet) {
|
||||
mac_t tmp;
|
||||
memcpy(&tmp, &packet->data[0], sizeof tmp);
|
||||
memcpy(&packet->data[0], &packet->data[6], sizeof tmp);
|
||||
memcpy(&packet->data[6], &tmp, sizeof 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) {
|
||||
|
|
@ -203,7 +203,7 @@ static void age_subnets(void *data) {
|
|||
}
|
||||
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c->status.active)
|
||||
if(c->edge)
|
||||
send_del_subnet(c, s);
|
||||
|
||||
subnet_del(myself, s);
|
||||
|
|
@ -223,7 +223,7 @@ static void learn_mac(mac_t *address) {
|
|||
/* If we don't know this MAC address yet, store it */
|
||||
|
||||
if(!subnet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx",
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Learned new MAC address %x:%x:%x:%x:%x:%x",
|
||||
address->x[0], address->x[1], address->x[2], address->x[3],
|
||||
address->x[4], address->x[5]);
|
||||
|
||||
|
|
@ -238,7 +238,7 @@ static void learn_mac(mac_t *address) {
|
|||
/* And tell all other tinc daemons it's our MAC */
|
||||
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c->status.active)
|
||||
if(c->edge)
|
||||
send_add_subnet(c, subnet);
|
||||
|
||||
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
|
||||
|
|
@ -267,7 +267,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
|
||||
/* Copy headers from packet into properly aligned structs on the stack */
|
||||
|
||||
memcpy(&ip, packet->data + ether_size, ip_size);
|
||||
memcpy(&ip, DATA(packet) + ether_size, ip_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
|
|
@ -284,7 +284,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen);
|
||||
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
|
||||
|
||||
/* Fill in IPv4 header */
|
||||
|
||||
|
|
@ -309,12 +309,12 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
icmp.icmp_cksum = 0;
|
||||
|
||||
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
|
||||
icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
|
||||
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(packet->data + ether_size, &ip, ip_size);
|
||||
memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
|
||||
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;
|
||||
|
||||
|
|
@ -330,8 +330,9 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
|
|||
uint8_t *offset;
|
||||
uint16_t ip_off, origf;
|
||||
|
||||
memcpy(&ip, packet->data + ether_size, ip_size);
|
||||
memcpy(&ip, DATA(packet) + ether_size, ip_size);
|
||||
fragment.priority = packet->priority;
|
||||
fragment.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
||||
if(ip.ip_hl != ip_size / 4)
|
||||
return;
|
||||
|
|
@ -345,7 +346,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
|
|||
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname);
|
||||
|
||||
offset = packet->data + ether_size + ip_size;
|
||||
offset = DATA(packet) + ether_size + ip_size;
|
||||
maxlen = (dest->mtu - ether_size - ip_size) & ~0x7;
|
||||
ip_off = ntohs(ip.ip_off);
|
||||
origf = ip_off & ~IP_OFFMASK;
|
||||
|
|
@ -353,7 +354,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
|
|||
|
||||
while(todo) {
|
||||
len = todo > maxlen ? maxlen : todo;
|
||||
memcpy(fragment.data + ether_size + ip_size, offset, len);
|
||||
memcpy(DATA(&fragment) + ether_size + ip_size, offset, len);
|
||||
todo -= len;
|
||||
offset += len;
|
||||
|
||||
|
|
@ -361,8 +362,8 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
|
|||
ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0));
|
||||
ip.ip_sum = 0;
|
||||
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
|
||||
memcpy(fragment.data, packet->data, ether_size);
|
||||
memcpy(fragment.data + ether_size, &ip, ip_size);
|
||||
memcpy(DATA(&fragment), DATA(packet), ether_size);
|
||||
memcpy(DATA(&fragment) + ether_size, &ip, ip_size);
|
||||
fragment.len = ether_size + ip_size + len;
|
||||
|
||||
send_packet(dest, &fragment);
|
||||
|
|
@ -371,12 +372,15 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
|
|||
}
|
||||
}
|
||||
|
||||
static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
||||
static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
||||
if(!checklength(source, packet, ether_size + ip_size))
|
||||
return;
|
||||
|
||||
subnet_t *subnet;
|
||||
node_t *via;
|
||||
ipv4_t dest;
|
||||
|
||||
memcpy(&dest, &packet->data[30], sizeof dest);
|
||||
memcpy(&dest, &DATA(packet)[30], sizeof dest);
|
||||
subnet = lookup_subnet_ipv4(&dest);
|
||||
|
||||
if(!subnet) {
|
||||
|
|
@ -391,6 +395,11 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!subnet->owner) {
|
||||
broadcast_packet(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if(subnet->owner == source) {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
|
||||
return;
|
||||
|
|
@ -403,7 +412,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
|
||||
if(priorityinheritance)
|
||||
packet->priority = packet->data[15];
|
||||
packet->priority = DATA(packet)[15];
|
||||
|
||||
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
|
||||
|
||||
|
|
@ -417,7 +426,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
|
||||
if(via && packet->len > MAX(via->mtu, 590) && via != myself) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
|
||||
if(packet->data[20] & 0x40) {
|
||||
if(DATA(packet)[20] & 0x40) {
|
||||
packet->len = MAX(via->mtu, 590);
|
||||
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
} else {
|
||||
|
|
@ -432,20 +441,6 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
||||
if(!checklength(source, packet, ether_size + ip_size))
|
||||
return;
|
||||
|
||||
if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
|
||||
packet->data[30] == 255 &&
|
||||
packet->data[31] == 255 &&
|
||||
packet->data[32] == 255 &&
|
||||
packet->data[33] == 255)))
|
||||
broadcast_packet(source, packet);
|
||||
else
|
||||
route_ipv4_unicast(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) {
|
||||
|
|
@ -469,7 +464,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
|
||||
/* Copy headers from packet to structs on the stack */
|
||||
|
||||
memcpy(&ip6, packet->data + ether_size, ip6_size);
|
||||
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
|
|
@ -486,7 +481,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(packet->data + ether_size + ip6_size + icmp6_size, packet->data + ether_size, pseudo.length);
|
||||
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
|
||||
|
||||
/* Fill in IPv6 header */
|
||||
|
||||
|
|
@ -512,26 +507,36 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
|
|||
|
||||
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
|
||||
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
|
||||
checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - 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(packet->data + ether_size, &ip6, ip6_size);
|
||||
memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size);
|
||||
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_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
||||
static void route_neighborsol(node_t *source, vpn_packet_t *packet);
|
||||
|
||||
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
||||
if(!checklength(source, packet, ether_size + ip6_size))
|
||||
return;
|
||||
|
||||
if(DATA(packet)[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && DATA(packet)[54] == ND_NEIGHBOR_SOLICIT) {
|
||||
route_neighborsol(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
subnet_t *subnet;
|
||||
node_t *via;
|
||||
ipv6_t dest;
|
||||
|
||||
memcpy(&dest, &packet->data[38], sizeof dest);
|
||||
memcpy(&dest, &DATA(packet)[38], sizeof dest);
|
||||
subnet = lookup_subnet_ipv6(&dest);
|
||||
|
||||
if(!subnet) {
|
||||
|
|
@ -550,6 +555,11 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!subnet->owner) {
|
||||
broadcast_packet(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if(subnet->owner == source) {
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
|
||||
return;
|
||||
|
|
@ -612,15 +622,15 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
|
|||
|
||||
/* Copy headers from packet to structs on the stack */
|
||||
|
||||
memcpy(&ip6, packet->data + ether_size, ip6_size);
|
||||
memcpy(&ns, packet->data + ether_size + ip6_size, ns_size);
|
||||
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
|
||||
memcpy(&ns, DATA(packet) + ether_size + ip6_size, ns_size);
|
||||
if(has_opt)
|
||||
memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size);
|
||||
memcpy(&opt, DATA(packet) + ether_size + ip6_size + ns_size, opt_size);
|
||||
|
||||
/* First, snatch the source address from the neighbor solicitation packet */
|
||||
|
||||
if(overwrite_mac)
|
||||
memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(mymac.x, DATA(packet) + ETH_ALEN, ETH_ALEN);
|
||||
|
||||
/* Check if this is a valid neighbor solicitation request */
|
||||
|
||||
|
|
@ -646,7 +656,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
|
|||
checksum = inet_checksum(&ns, ns_size, checksum);
|
||||
if(has_opt) {
|
||||
checksum = inet_checksum(&opt, opt_size, checksum);
|
||||
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
|
||||
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
|
||||
}
|
||||
|
||||
if(checksum) {
|
||||
|
|
@ -679,14 +689,14 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
|
|||
|
||||
/* Create neighbor advertation reply */
|
||||
|
||||
memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
|
||||
packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
|
||||
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 */
|
||||
|
||||
ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */
|
||||
ip6.ip6_src = ns.nd_ns_target;
|
||||
|
||||
if(has_opt)
|
||||
memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
|
||||
memcpy(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
|
||||
|
||||
ns.nd_ns_cksum = 0;
|
||||
ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
|
||||
|
|
@ -709,36 +719,21 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
|
|||
checksum = inet_checksum(&ns, ns_size, checksum);
|
||||
if(has_opt) {
|
||||
checksum = inet_checksum(&opt, opt_size, checksum);
|
||||
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
|
||||
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
|
||||
}
|
||||
|
||||
ns.nd_ns_hdr.icmp6_cksum = checksum;
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &ip6, ip6_size);
|
||||
memcpy(packet->data + ether_size + ip6_size, &ns, ns_size);
|
||||
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
|
||||
memcpy(DATA(packet) + ether_size + ip6_size, &ns, ns_size);
|
||||
if(has_opt)
|
||||
memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
|
||||
memcpy(DATA(packet) + ether_size + ip6_size + ns_size, &opt, opt_size);
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
||||
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
||||
if(!checklength(source, packet, ether_size + ip6_size))
|
||||
return;
|
||||
|
||||
if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
|
||||
route_neighborsol(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if(broadcast_mode && packet->data[38] == 255)
|
||||
broadcast_packet(source, packet);
|
||||
else
|
||||
route_ipv6_unicast(source, packet);
|
||||
}
|
||||
|
||||
/* RFC 826 */
|
||||
|
||||
static void route_arp(node_t *source, vpn_packet_t *packet) {
|
||||
|
|
@ -757,11 +752,11 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
|
|||
/* First, snatch the source address from the ARP packet */
|
||||
|
||||
if(overwrite_mac)
|
||||
memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(mymac.x, DATA(packet) + ETH_ALEN, ETH_ALEN);
|
||||
|
||||
/* Copy headers from packet to structs on the stack */
|
||||
|
||||
memcpy(&arp, packet->data + ether_size, arp_size);
|
||||
memcpy(&arp, DATA(packet) + ether_size, arp_size);
|
||||
|
||||
/* Check if this is a valid ARP request */
|
||||
|
||||
|
|
@ -787,20 +782,20 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
|
|||
if(subnet->owner == myself)
|
||||
return; /* silently ignore */
|
||||
|
||||
memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
|
||||
packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
|
||||
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 */
|
||||
|
||||
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, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
|
||||
memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
|
||||
arp.arp_op = htons(ARPOP_REPLY);
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &arp, arp_size);
|
||||
memcpy(DATA(packet) + ether_size, &arp, arp_size);
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
|
@ -813,16 +808,16 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
|
||||
if(source == myself) {
|
||||
mac_t src;
|
||||
memcpy(&src, &packet->data[6], sizeof src);
|
||||
memcpy(&src, &DATA(packet)[6], sizeof src);
|
||||
learn_mac(&src);
|
||||
}
|
||||
|
||||
/* Lookup destination address */
|
||||
|
||||
memcpy(&dest, &packet->data[0], sizeof dest);
|
||||
memcpy(&dest, &DATA(packet)[0], sizeof dest);
|
||||
subnet = lookup_subnet_mac(NULL, &dest);
|
||||
|
||||
if(!subnet) {
|
||||
if(!subnet || !subnet->owner) {
|
||||
broadcast_packet(source, packet);
|
||||
return;
|
||||
}
|
||||
|
|
@ -835,10 +830,10 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return;
|
||||
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
|
||||
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
|
||||
packet->priority = packet->data[15];
|
||||
packet->priority = DATA(packet)[15];
|
||||
|
||||
// Handle packets larger than PMTU
|
||||
|
||||
|
|
@ -852,12 +847,12 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
length_t ethlen = 14;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
type = DATA(packet)[16] << 8 | DATA(packet)[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
if(type == ETH_P_IP && packet->len > 576 + ethlen) {
|
||||
if(packet->data[6 + ethlen] & 0x40) {
|
||||
if(DATA(packet)[6 + ethlen] & 0x40) {
|
||||
packet->len = via->mtu;
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
} else {
|
||||
|
|
@ -889,16 +884,16 @@ static void send_pcap(vpn_packet_t *packet) {
|
|||
len = c->outmaclength;
|
||||
|
||||
if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, len))
|
||||
send_meta(c, (char *)packet->data, len);
|
||||
send_meta(c, (char *)DATA(packet), len);
|
||||
}
|
||||
}
|
||||
|
||||
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
type = DATA(packet)[16] << 8 | DATA(packet)[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
|
|
@ -907,22 +902,22 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
|||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 8] < 1) {
|
||||
if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
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 = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
packet->data[ethlen + 8]--;
|
||||
uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
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 = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
|
||||
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
packet->data[ethlen + 10] = checksum >> 8;
|
||||
packet->data[ethlen + 11] = checksum & 0xff;
|
||||
DATA(packet)[ethlen + 10] = checksum >> 8;
|
||||
DATA(packet)[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -930,13 +925,13 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
|||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 7] < 1) {
|
||||
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
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;
|
||||
}
|
||||
|
||||
packet->data[ethlen + 7]--;
|
||||
DATA(packet)[ethlen + 7]--;
|
||||
|
||||
return true;
|
||||
|
||||
|
|
@ -961,7 +956,7 @@ void route(node_t *source, vpn_packet_t *packet) {
|
|||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
|
||||
switch (routing_mode) {
|
||||
case RMODE_ROUTER:
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool execute_script(const char *name, char **envp) {
|
|||
if(q) {
|
||||
memcpy(ext, p, q - p);
|
||||
ext[q - p] = 0;
|
||||
*q++;
|
||||
q++;
|
||||
} else {
|
||||
strcpy(ext, p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
device.c -- Interaction with Solaris tun device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
2001-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
|
||||
|
|
@ -23,171 +24,350 @@
|
|||
|
||||
#include <sys/stropts.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <net/if_tun.h>
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#define DEFAULT_DEVICE "/dev/tun"
|
||||
#ifndef TUNNEWPPA
|
||||
#warning Missing net/if_tun.h, using hardcoded value for TUNNEWPPA
|
||||
#define TUNNEWPPA (('T'<<16) | 0x0001)
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun"
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap"
|
||||
|
||||
static enum {
|
||||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TAP,
|
||||
} device_type = DEVICE_TYPE_TUN;
|
||||
|
||||
int device_fd = -1;
|
||||
static int ip_fd = -1, if_fd = -1;
|
||||
static int ip_fd = -1;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
int ppa;
|
||||
char *ptr;
|
||||
char *type;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
else
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
|
||||
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "tun"))
|
||||
/* use default */;
|
||||
else if(!strcasecmp(type, "tap"))
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER)
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
|
||||
if(device_type == DEVICE_TYPE_TUN)
|
||||
device_info = "Solaris tun device";
|
||||
else
|
||||
device_info = "Solaris tap device";
|
||||
|
||||
/* The following is black magic copied from OpenVPN. */
|
||||
|
||||
if((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", "/dev/ip", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if((device_fd = open(device, O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get unit number. */
|
||||
|
||||
char *ptr = device;
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &ptr);
|
||||
|
||||
while(*ptr && !isdigit(*ptr))
|
||||
ptr++;
|
||||
int ppa = atoi(ptr);
|
||||
|
||||
/* Assign a new PPA and get its unit number. */
|
||||
|
||||
struct strioctl strioc_ppa = {
|
||||
.ic_cmd = TUNNEWPPA,
|
||||
.ic_len = sizeof ppa,
|
||||
.ic_dp = (char *)&ppa,
|
||||
};
|
||||
|
||||
if(!*ptr) { /* no number given, try dynamic */
|
||||
bool found = false;
|
||||
while(!found && ppa < 64) {
|
||||
int new_ppa = ioctl(device_fd, I_STR, &strioc_ppa);
|
||||
if(new_ppa >= 0) {
|
||||
ppa = new_ppa;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
ppa++;
|
||||
}
|
||||
if(!found) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not find free PPA for %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
} else { /* try this particular one */
|
||||
if((ppa = ioctl(device_fd, I_STR, &strioc_ppa)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not assign PPA %d for %s %s!", ppa, device_info, device);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int if_fd;
|
||||
if((if_fd = open(device, O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ioctl(if_fd, I_PUSH, "ip") < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push IP module onto %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
xasprintf(&iface, "%s%d", device_type == DEVICE_TYPE_TUN ? "tun" : "tap", ppa);
|
||||
|
||||
{
|
||||
/* Remove muxes just in case they are left over from a crashed tincd */
|
||||
struct lifreq ifr = {};
|
||||
strncpy(ifr.lifr_name, iface, sizeof ifr.lifr_name);
|
||||
if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
|
||||
int muxid = ifr.lifr_arp_muxid;
|
||||
ioctl(ip_fd, I_PUNLINK, muxid);
|
||||
muxid = ifr.lifr_ip_muxid;
|
||||
ioctl(ip_fd, I_PUNLINK, muxid);
|
||||
}
|
||||
}
|
||||
|
||||
if(device_type == DEVICE_TYPE_TUN) {
|
||||
/* Assign ppa according to the unit number returned by tun device */
|
||||
if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int arp_fd = -1;
|
||||
|
||||
if(device_type == DEVICE_TYPE_TAP) {
|
||||
struct lifreq ifr = {};
|
||||
|
||||
if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set flags on %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
|
||||
ifr.lifr_ppa = ppa;
|
||||
|
||||
/* Assign ppa according to the unit number returned by tun device */
|
||||
if(ioctl(if_fd, SIOCSLIFNAME, &ifr) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device);
|
||||
return false;
|
||||
}
|
||||
if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set flags on %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Push arp module to if_fd */
|
||||
if(ioctl(if_fd, I_PUSH, "arp") < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push ARP module onto %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Pop any modules on the stream */
|
||||
while(true) {
|
||||
if(ioctl(ip_fd, I_POP, NULL) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Push arp module to ip_fd */
|
||||
if(ioctl(ip_fd, I_PUSH, "arp") < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push ARP module onto %s!", "/dev/ip");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Open arp_fd */
|
||||
if((arp_fd = open(device, O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Push arp module to arp_fd */
|
||||
if(ioctl(arp_fd, I_PUSH, "arp") < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push ARP module onto %s %s!", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set ifname to arp */
|
||||
struct strioctl strioc_if = {
|
||||
.ic_cmd = SIOCSLIFNAME,
|
||||
.ic_len = sizeof ifr,
|
||||
.ic_dp = (char *)&ifr,
|
||||
};
|
||||
|
||||
if(ioctl(arp_fd, I_STR, &strioc_if) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set ifname to %s %s", device_info, device);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int ip_muxid, arp_muxid;
|
||||
|
||||
if((ip_muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not link %s %s to IP", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(device_type == DEVICE_TYPE_TAP) {
|
||||
if((arp_muxid = ioctl(ip_fd, I_PLINK, arp_fd)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not link %s %s to ARP", device_info, device);
|
||||
return false;
|
||||
}
|
||||
close(arp_fd);
|
||||
}
|
||||
|
||||
struct lifreq ifr = {};
|
||||
strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
|
||||
ifr.lifr_ip_muxid = ip_muxid;
|
||||
if(device_type == DEVICE_TYPE_TAP) {
|
||||
ifr.lifr_arp_muxid = arp_muxid;
|
||||
}
|
||||
|
||||
if(ioctl(ip_fd, SIOCSLIFMUXID, &ifr) < 0) {
|
||||
if(device_type == DEVICE_TYPE_TAP) {
|
||||
ioctl(ip_fd, I_PUNLINK, arp_muxid);
|
||||
}
|
||||
ioctl(ip_fd, I_PUNLINK, ip_muxid);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not set multiplexor id for %s %s", device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
close(if_fd);
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
ppa = 0;
|
||||
|
||||
ptr = device;
|
||||
while(*ptr && !isdigit((int) *ptr))
|
||||
ptr++;
|
||||
ppa = atoi(ptr);
|
||||
|
||||
if((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open /dev/ip: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(ip_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Assign a new PPA and get its unit number. */
|
||||
if((ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't assign new interface: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if((if_fd = open(device, O_RDWR, 0)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s twice: %s", device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(if_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
if(ioctl(if_fd, I_PUSH, "ip") < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't push IP module: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Assign ppa according to the unit number returned by tun device */
|
||||
if(ioctl(if_fd, IF_UNITSEL, (char *) &ppa) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't set PPA %d: %s", ppa, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ioctl(ip_fd, I_LINK, if_fd) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't link TUN device to IP: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
xasprintf(&iface, "tun%d", ppa);
|
||||
|
||||
device_info = "Solaris tun device";
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(if_fd);
|
||||
close(ip_fd);
|
||||
close(device_fd);
|
||||
if(iface) {
|
||||
struct lifreq ifr = {};
|
||||
strncpy(ifr.lifr_name, iface, sizeof ifr.lifr_name);
|
||||
if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
|
||||
int muxid = ifr.lifr_arp_muxid;
|
||||
ioctl(ip_fd, I_PUNLINK, muxid);
|
||||
muxid = ifr.lifr_ip_muxid;
|
||||
ioctl(ip_fd, I_PUNLINK, muxid);
|
||||
}
|
||||
}
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
close(ip_fd); ip_fd = -1;
|
||||
close(device_fd); device_fd = -1;
|
||||
|
||||
free(device); device = NULL;
|
||||
free(iface); iface = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
|
||||
if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if((inlen = read(device_fd, DATA(packet) + 14, MTU - 14)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
switch(DATA(packet)[14] >> 4) {
|
||||
case 4:
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
break;
|
||||
case 6:
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
break;
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version %d while reading packet from %s %s", DATA(packet)[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 14;
|
||||
break;
|
||||
case 6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = inlen + 14;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
abort();
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = inlen + 14;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info);
|
||||
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
323
src/sptps.c
323
src/sptps.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
sptps.c -- Simple Peer-to-Peer Security
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2011-2014 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
|
||||
|
|
@ -20,9 +20,8 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "cipher.h"
|
||||
#include "chacha-poly1305/chacha-poly1305.h"
|
||||
#include "crypto.h"
|
||||
#include "digest.h"
|
||||
#include "ecdh.h"
|
||||
#include "ecdsa.h"
|
||||
#include "logger.h"
|
||||
|
|
@ -40,7 +39,7 @@ unsigned int sptps_replaywin = 16;
|
|||
|
||||
Sign all handshake messages up to ECDHE kex with long-term public keys. (done)
|
||||
|
||||
HMACed KEX finished message to prevent downgrade attacks and prove you have the right key material (done by virtue of ECDSA over the whole ECDHE exchange?)
|
||||
HMACed KEX finished message to prevent downgrade attacks and prove you have the right key material (done by virtue of Ed25519 over the whole ECDHE exchange?)
|
||||
|
||||
Explicit close message needs to be added.
|
||||
|
||||
|
|
@ -82,72 +81,53 @@ static void warning(sptps_t *s, const char *format, ...) {
|
|||
}
|
||||
|
||||
// Send a record (datagram version, accepts all record types, handles encryption and authentication).
|
||||
static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
|
||||
char buffer[len + 23UL];
|
||||
static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
|
||||
char buffer[len + 21UL];
|
||||
|
||||
// Create header with sequence number, length and record type
|
||||
uint32_t seqno = htonl(s->outseqno++);
|
||||
uint16_t netlen = htons(len);
|
||||
uint32_t seqno = s->outseqno++;
|
||||
uint32_t netseqno = ntohl(seqno);
|
||||
|
||||
memcpy(buffer, &netlen, 2);
|
||||
memcpy(buffer + 2, &seqno, 4);
|
||||
buffer[6] = type;
|
||||
|
||||
// Add plaintext (TODO: avoid unnecessary copy)
|
||||
memcpy(buffer + 7, data, len);
|
||||
memcpy(buffer, &netseqno, 4);
|
||||
buffer[4] = type;
|
||||
memcpy(buffer + 5, data, len);
|
||||
|
||||
if(s->outstate) {
|
||||
// If first handshake has finished, encrypt and HMAC
|
||||
if(!cipher_set_counter(s->outcipher, &seqno, sizeof seqno))
|
||||
return false;
|
||||
|
||||
if(!cipher_counter_xor(s->outcipher, buffer + 6, len + 1UL, buffer + 6))
|
||||
return false;
|
||||
|
||||
if(!digest_create(s->outdigest, buffer, len + 7UL, buffer + 7UL + len))
|
||||
return false;
|
||||
|
||||
return s->send_data(s->handle, type, buffer + 2, len + 21UL);
|
||||
chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 4, len + 1, buffer + 4, NULL);
|
||||
return s->send_data(s->handle, type, buffer, len + 21UL);
|
||||
} else {
|
||||
// Otherwise send as plaintext
|
||||
return s->send_data(s->handle, type, buffer + 2, len + 5UL);
|
||||
return s->send_data(s->handle, type, buffer, len + 5UL);
|
||||
}
|
||||
}
|
||||
// Send a record (private version, accepts all record types, handles encryption and authentication).
|
||||
static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
|
||||
static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
|
||||
if(s->datagram)
|
||||
return send_record_priv_datagram(s, type, data, len);
|
||||
|
||||
char buffer[len + 23UL];
|
||||
char buffer[len + 19UL];
|
||||
|
||||
// Create header with sequence number, length and record type
|
||||
uint32_t seqno = htonl(s->outseqno++);
|
||||
uint32_t seqno = s->outseqno++;
|
||||
uint16_t netlen = htons(len);
|
||||
|
||||
memcpy(buffer, &seqno, 4);
|
||||
memcpy(buffer + 4, &netlen, 2);
|
||||
buffer[6] = type;
|
||||
|
||||
// Add plaintext (TODO: avoid unnecessary copy)
|
||||
memcpy(buffer + 7, data, len);
|
||||
memcpy(buffer, &netlen, 2);
|
||||
buffer[2] = type;
|
||||
memcpy(buffer + 3, data, len);
|
||||
|
||||
if(s->outstate) {
|
||||
// If first handshake has finished, encrypt and HMAC
|
||||
if(!cipher_counter_xor(s->outcipher, buffer + 4, len + 3UL, buffer + 4))
|
||||
return false;
|
||||
|
||||
if(!digest_create(s->outdigest, buffer, len + 7UL, buffer + 7UL + len))
|
||||
return false;
|
||||
|
||||
return s->send_data(s->handle, type, buffer + 4, len + 19UL);
|
||||
chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 2, len + 1, buffer + 2, NULL);
|
||||
return s->send_data(s->handle, type, buffer, len + 19UL);
|
||||
} else {
|
||||
// Otherwise send as plaintext
|
||||
return s->send_data(s->handle, type, buffer + 4, len + 3UL);
|
||||
return s->send_data(s->handle, type, buffer, len + 3UL);
|
||||
}
|
||||
}
|
||||
|
||||
// Send an application record.
|
||||
bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
|
||||
bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
|
||||
// Sanity checks: application cannot send data before handshake is finished,
|
||||
// and only record types 0..127 are allowed.
|
||||
if(!s->outstate)
|
||||
|
|
@ -165,7 +145,7 @@ static bool send_kex(sptps_t *s) {
|
|||
|
||||
// Make room for our KEX message, which we will keep around since send_sig() needs it.
|
||||
if(s->mykex)
|
||||
abort();
|
||||
return false;
|
||||
s->mykex = realloc(s->mykex, 1 + 32 + keylen);
|
||||
if(!s->mykex)
|
||||
return error(s, errno, strerror(errno));
|
||||
|
|
@ -178,12 +158,12 @@ static bool send_kex(sptps_t *s) {
|
|||
|
||||
// Create a new ECDH public key.
|
||||
if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32)))
|
||||
return false;
|
||||
return error(s, EINVAL, "Failed to generate ECDH public key");
|
||||
|
||||
return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen);
|
||||
}
|
||||
|
||||
// Send a SIGnature record, containing an ECDSA signature over both KEX records.
|
||||
// Send a SIGnature record, containing an Ed25519 signature over both KEX records.
|
||||
static bool send_sig(sptps_t *s) {
|
||||
size_t keylen = ECDH_SIZE;
|
||||
size_t siglen = ecdsa_size(s->mykey);
|
||||
|
|
@ -199,7 +179,7 @@ static bool send_sig(sptps_t *s) {
|
|||
|
||||
// Sign the result.
|
||||
if(!ecdsa_sign(s->mykey, msg, sizeof msg, sig))
|
||||
return false;
|
||||
return error(s, EINVAL, "Failed to sign SIG record");
|
||||
|
||||
// Send the SIG exchange record.
|
||||
return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof sig);
|
||||
|
|
@ -209,16 +189,14 @@ static bool send_sig(sptps_t *s) {
|
|||
static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
|
||||
// Initialise cipher and digest structures if necessary
|
||||
if(!s->outstate) {
|
||||
s->incipher = cipher_open_by_name("aes-256-ecb");
|
||||
s->outcipher = cipher_open_by_name("aes-256-ecb");
|
||||
s->indigest = digest_open_by_name("sha256", 16);
|
||||
s->outdigest = digest_open_by_name("sha256", 16);
|
||||
if(!s->incipher || !s->outcipher || !s->indigest || !s->outdigest)
|
||||
return false;
|
||||
s->incipher = chacha_poly1305_init();
|
||||
s->outcipher = chacha_poly1305_init();
|
||||
if(!s->incipher || !s->outcipher)
|
||||
return error(s, EINVAL, "Failed to open cipher");
|
||||
}
|
||||
|
||||
// Allocate memory for key material
|
||||
size_t keylen = digest_keylength(s->indigest) + digest_keylength(s->outdigest) + cipher_keylength(s->incipher) + cipher_keylength(s->outcipher);
|
||||
size_t keylen = 2 * CHACHA_POLY1305_KEYLEN;
|
||||
|
||||
s->key = realloc(s->key, keylen);
|
||||
if(!s->key)
|
||||
|
|
@ -238,7 +216,7 @@ static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
|
|||
|
||||
// Use PRF to generate the key material
|
||||
if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen))
|
||||
return false;
|
||||
return error(s, EINVAL, "Failed to generate key material");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -254,17 +232,11 @@ static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
|
|||
return error(s, EIO, "Invalid ACK record length");
|
||||
|
||||
if(s->initiator) {
|
||||
bool result
|
||||
= cipher_set_counter_key(s->incipher, s->key)
|
||||
&& digest_set_key(s->indigest, s->key + cipher_keylength(s->incipher), digest_keylength(s->indigest));
|
||||
if(!result)
|
||||
return false;
|
||||
if(!chacha_poly1305_set_key(s->incipher, s->key))
|
||||
return error(s, EINVAL, "Failed to set counter");
|
||||
} else {
|
||||
bool result
|
||||
= cipher_set_counter_key(s->incipher, s->key + cipher_keylength(s->outcipher) + digest_keylength(s->outdigest))
|
||||
&& digest_set_key(s->indigest, s->key + cipher_keylength(s->outcipher) + digest_keylength(s->outdigest) + cipher_keylength(s->incipher), digest_keylength(s->indigest));
|
||||
if(!result)
|
||||
return false;
|
||||
if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN))
|
||||
return error(s, EINVAL, "Failed to set counter");
|
||||
}
|
||||
|
||||
free(s->key);
|
||||
|
|
@ -284,7 +256,7 @@ static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
|
|||
|
||||
// Make a copy of the KEX message, send_sig() and receive_sig() need it
|
||||
if(s->hiskex)
|
||||
abort();
|
||||
return error(s, EINVAL, "Received a second KEX message before first has been processed");
|
||||
s->hiskex = realloc(s->hiskex, len);
|
||||
if(!s->hiskex)
|
||||
return error(s, errno, strerror(errno));
|
||||
|
|
@ -313,12 +285,12 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
|
|||
|
||||
// Verify signature.
|
||||
if(!ecdsa_verify(s->hiskey, msg, sizeof msg, data))
|
||||
return false;
|
||||
return error(s, EIO, "Failed to verify SIG record");
|
||||
|
||||
// Compute shared secret.
|
||||
char shared[ECDH_SHARED_SIZE];
|
||||
if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared))
|
||||
return false;
|
||||
return error(s, EINVAL, "Failed to compute ECDH shared secret");
|
||||
s->ecdh = NULL;
|
||||
|
||||
// Generate key material from shared secret.
|
||||
|
|
@ -337,17 +309,11 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
|
|||
|
||||
// TODO: only set new keys after ACK has been set/received
|
||||
if(s->initiator) {
|
||||
bool result
|
||||
= cipher_set_counter_key(s->outcipher, s->key + cipher_keylength(s->incipher) + digest_keylength(s->indigest))
|
||||
&& digest_set_key(s->outdigest, s->key + cipher_keylength(s->incipher) + digest_keylength(s->indigest) + cipher_keylength(s->outcipher), digest_keylength(s->outdigest));
|
||||
if(!result)
|
||||
return false;
|
||||
if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN))
|
||||
return error(s, EINVAL, "Failed to set key");
|
||||
} else {
|
||||
bool result
|
||||
= cipher_set_counter_key(s->outcipher, s->key)
|
||||
&& digest_set_key(s->outdigest, s->key + cipher_keylength(s->outcipher), digest_keylength(s->outdigest));
|
||||
if(!result)
|
||||
return false;
|
||||
if(!chacha_poly1305_set_key(s->outcipher, s->key))
|
||||
return error(s, EINVAL, "Failed to set key");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -404,18 +370,73 @@ static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) {
|
||||
// Replay protection using a sliding window of configurable size.
|
||||
// s->inseqno is expected sequence number
|
||||
// seqno is received sequence number
|
||||
// s->late[] is a circular buffer, a 1 bit means a packet has not been received yet
|
||||
// The circular buffer contains bits for sequence numbers from s->inseqno - s->replaywin * 8 to (but excluding) s->inseqno.
|
||||
if(s->replaywin) {
|
||||
if(seqno != s->inseqno) {
|
||||
if(seqno >= s->inseqno + s->replaywin * 8) {
|
||||
// Prevent packets that jump far ahead of the queue from causing many others to be dropped.
|
||||
bool farfuture = s->farfuture < s->replaywin >> 2;
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
// Mark all packets in the replay window as being late.
|
||||
memset(s->late, 255, s->replaywin);
|
||||
}
|
||||
} 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);
|
||||
} else if (update_state) {
|
||||
// We missed some packets. Mark them in the bitmap as being late.
|
||||
for(int i = s->inseqno; i < seqno; i++)
|
||||
s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_state) {
|
||||
// Mark the current packet as not being late.
|
||||
s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8);
|
||||
s->farfuture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_state) {
|
||||
if(seqno >= s->inseqno)
|
||||
s->inseqno = seqno + 1;
|
||||
|
||||
if(!s->inseqno)
|
||||
s->received = 0;
|
||||
else
|
||||
s->received++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check datagram for valid HMAC
|
||||
bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len) {
|
||||
bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
|
||||
if(!s->instate || len < 21)
|
||||
return error(s, EIO, "Received short packet");
|
||||
|
||||
uint32_t seqno;
|
||||
memcpy(&seqno, data, 4);
|
||||
seqno = ntohl(seqno);
|
||||
if (!sptps_check_seqno(s, seqno, false))
|
||||
return false;
|
||||
|
||||
char buffer[len + 23];
|
||||
uint16_t netlen = htons(len - 21);
|
||||
|
||||
memcpy(buffer, &netlen, 2);
|
||||
memcpy(buffer + 2, data, len);
|
||||
|
||||
return digest_verify(s->indigest, buffer, len - 14, buffer + len - 14);
|
||||
char buffer[len];
|
||||
size_t outlen;
|
||||
return chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen);
|
||||
}
|
||||
|
||||
// Receive incoming data, datagram version.
|
||||
|
|
@ -441,77 +462,31 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
|
|||
return receive_handshake(s, data + 5, len - 5);
|
||||
}
|
||||
|
||||
// Check HMAC.
|
||||
uint16_t netlen = htons(len - 21);
|
||||
// Decrypt
|
||||
|
||||
char buffer[len + 23];
|
||||
char buffer[len];
|
||||
|
||||
memcpy(buffer, &netlen, 2);
|
||||
memcpy(buffer + 2, data, len);
|
||||
size_t outlen;
|
||||
|
||||
if(!digest_verify(s->indigest, buffer, len - 14, buffer + len - 14))
|
||||
return error(s, EIO, "Invalid HMAC");
|
||||
if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen))
|
||||
return error(s, EIO, "Failed to decrypt and verify packet");
|
||||
|
||||
// Replay protection using a sliding window of configurable size.
|
||||
// s->inseqno is expected sequence number
|
||||
// seqno is received sequence number
|
||||
// s->late[] is a circular buffer, a 1 bit means a packet has not been received yet
|
||||
// The circular buffer contains bits for sequence numbers from s->inseqno - s->replaywin * 8 to (but excluding) s->inseqno.
|
||||
if(s->replaywin) {
|
||||
if(seqno != s->inseqno) {
|
||||
if(seqno >= s->inseqno + s->replaywin * 8) {
|
||||
// Prevent packets that jump far ahead of the queue from causing many others to be dropped.
|
||||
if(s->farfuture++ < s->replaywin >> 2)
|
||||
return error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture);
|
||||
|
||||
// Unless we have seen lots of them, in which case we consider the others lost.
|
||||
warning(s, "Lost %d packets\n", seqno - s->inseqno);
|
||||
// Mark all packets in the replay window as being late.
|
||||
memset(s->late, 255, s->replaywin);
|
||||
} 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);
|
||||
} else {
|
||||
// We missed some packets. Mark them in the bitmap as being late.
|
||||
for(int i = s->inseqno; i < seqno; i++)
|
||||
s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the current packet as not being late.
|
||||
s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8);
|
||||
s->farfuture = 0;
|
||||
}
|
||||
|
||||
if(seqno >= s->inseqno)
|
||||
s->inseqno = seqno + 1;
|
||||
|
||||
if(!s->inseqno)
|
||||
s->received = 0;
|
||||
else
|
||||
s->received++;
|
||||
|
||||
// Decrypt.
|
||||
memcpy(&seqno, buffer + 2, 4);
|
||||
if(!cipher_set_counter(s->incipher, &seqno, sizeof seqno))
|
||||
return false;
|
||||
if(!cipher_counter_xor(s->incipher, buffer + 6, len - 4, buffer + 6))
|
||||
if(!sptps_check_seqno(s, seqno, true))
|
||||
return false;
|
||||
|
||||
// Append a NULL byte for safety.
|
||||
buffer[len - 14] = 0;
|
||||
buffer[len - 20] = 0;
|
||||
|
||||
uint8_t type = buffer[6];
|
||||
uint8_t type = buffer[0];
|
||||
|
||||
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 + 7, len - 21))
|
||||
return false;
|
||||
if(!s->receive_record(s->handle, type, buffer + 1, len - 21))
|
||||
abort();
|
||||
} else if(type == SPTPS_HANDSHAKE) {
|
||||
if(!receive_handshake(s, buffer + 7, len - 21))
|
||||
return false;
|
||||
if(!receive_handshake(s, buffer + 1, len - 21))
|
||||
abort();
|
||||
} else {
|
||||
return error(s, EIO, "Invalid record type %d", type);
|
||||
}
|
||||
|
|
@ -520,7 +495,7 @@ 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 char *data, size_t len) {
|
||||
bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
|
||||
if(!s->state)
|
||||
return error(s, EIO, "Invalid session state zero");
|
||||
|
||||
|
|
@ -529,8 +504,8 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
|
|||
|
||||
while(len) {
|
||||
// First read the 2 length bytes.
|
||||
if(s->buflen < 6) {
|
||||
size_t toread = 6 - s->buflen;
|
||||
if(s->buflen < 2) {
|
||||
size_t toread = 2 - s->buflen;
|
||||
if(toread > len)
|
||||
toread = len;
|
||||
|
||||
|
|
@ -541,36 +516,26 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
|
|||
data += toread;
|
||||
|
||||
// Exit early if we don't have the full length.
|
||||
if(s->buflen < 6)
|
||||
if(s->buflen < 2)
|
||||
return true;
|
||||
|
||||
// Decrypt the length bytes
|
||||
|
||||
if(s->instate) {
|
||||
if(!cipher_counter_xor(s->incipher, s->inbuf + 4, 2, &s->reclen))
|
||||
return false;
|
||||
} else {
|
||||
memcpy(&s->reclen, s->inbuf + 4, 2);
|
||||
}
|
||||
// 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 + 23UL);
|
||||
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
|
||||
if(!s->inbuf)
|
||||
return error(s, errno, strerror(errno));
|
||||
|
||||
// Add sequence number.
|
||||
uint32_t seqno = htonl(s->inseqno++);
|
||||
memcpy(s->inbuf, &seqno, 4);
|
||||
|
||||
// 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 ? 23UL : 7UL) - s->buflen;
|
||||
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
|
||||
if(toread > len)
|
||||
toread = len;
|
||||
|
||||
|
|
@ -580,43 +545,44 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
|
|||
data += toread;
|
||||
|
||||
// If we don't have a whole record, exit.
|
||||
if(s->buflen < s->reclen + (s->instate ? 23UL : 7UL))
|
||||
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
|
||||
return true;
|
||||
|
||||
// Update sequence number.
|
||||
|
||||
uint32_t seqno = s->inseqno++;
|
||||
|
||||
// Check HMAC and decrypt.
|
||||
if(s->instate) {
|
||||
if(!digest_verify(s->indigest, s->inbuf, s->reclen + 7UL, s->inbuf + s->reclen + 7UL))
|
||||
return error(s, EIO, "Invalid HMAC");
|
||||
|
||||
if(!cipher_counter_xor(s->incipher, s->inbuf + 6UL, s->reclen + 1UL, s->inbuf + 6UL))
|
||||
return false;
|
||||
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 + 7UL] = 0;
|
||||
s->inbuf[s->reclen + 3UL] = 0;
|
||||
|
||||
uint8_t type = s->inbuf[6];
|
||||
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 + 7, s->reclen))
|
||||
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 + 7, s->reclen))
|
||||
if(!receive_handshake(s, s->inbuf + 3, s->reclen))
|
||||
return false;
|
||||
} else {
|
||||
return error(s, EIO, "Invalid record type %d", type);
|
||||
}
|
||||
|
||||
s->buflen = 4;
|
||||
s->buflen = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start a SPTPS session.
|
||||
bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
|
||||
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) {
|
||||
// Initialise struct sptps
|
||||
memset(s, 0, sizeof *s);
|
||||
|
||||
|
|
@ -641,8 +607,7 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_
|
|||
s->inbuf = malloc(7);
|
||||
if(!s->inbuf)
|
||||
return error(s, errno, strerror(errno));
|
||||
s->buflen = 4;
|
||||
memset(s->inbuf, 0, 4);
|
||||
s->buflen = 0;
|
||||
}
|
||||
|
||||
memcpy(s->label, label, labellen);
|
||||
|
|
@ -659,10 +624,8 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_
|
|||
// Stop a SPTPS session.
|
||||
bool sptps_stop(sptps_t *s) {
|
||||
// Clean up any resources.
|
||||
cipher_close(s->incipher);
|
||||
cipher_close(s->outcipher);
|
||||
digest_close(s->indigest);
|
||||
digest_close(s->outdigest);
|
||||
chacha_poly1305_exit(s->incipher);
|
||||
chacha_poly1305_exit(s->outcipher);
|
||||
ecdh_free(s->ecdh);
|
||||
free(s->inbuf);
|
||||
free(s->mykex);
|
||||
|
|
|
|||
26
src/sptps.h
26
src/sptps.h
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
sptps.h -- Simple Peer-to-Peer Security
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2011-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
|
||||
|
|
@ -22,8 +22,7 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "cipher.h"
|
||||
#include "digest.h"
|
||||
#include "chacha-poly1305/chacha-poly1305.h"
|
||||
#include "ecdh.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
|
|
@ -40,8 +39,11 @@
|
|||
#define SPTPS_SIG 3 // Waiting for a SIGnature record
|
||||
#define SPTPS_ACK 4 // Waiting for an ACKnowledgement record
|
||||
|
||||
typedef bool (*send_data_t)(void *handle, uint8_t type, const char *data, size_t len);
|
||||
typedef bool (*receive_record_t)(void *handle, uint8_t type, const char *data, uint16_t len);
|
||||
// Overhead for datagrams
|
||||
#define SPTPS_DATAGRAM_OVERHEAD 21
|
||||
|
||||
typedef bool (*send_data_t)(void *handle, uint8_t type, const void *data, size_t len);
|
||||
typedef bool (*receive_record_t)(void *handle, uint8_t type, const void *data, uint16_t len);
|
||||
|
||||
typedef struct sptps {
|
||||
bool initiator;
|
||||
|
|
@ -53,8 +55,7 @@ typedef struct sptps {
|
|||
uint16_t reclen;
|
||||
|
||||
bool instate;
|
||||
cipher_t *incipher;
|
||||
digest_t *indigest;
|
||||
chacha_poly1305_ctx_t *incipher;
|
||||
uint32_t inseqno;
|
||||
uint32_t received;
|
||||
unsigned int replaywin;
|
||||
|
|
@ -62,8 +63,7 @@ typedef struct sptps {
|
|||
char *late;
|
||||
|
||||
bool outstate;
|
||||
cipher_t *outcipher;
|
||||
digest_t *outdigest;
|
||||
chacha_poly1305_ctx_t *outcipher;
|
||||
uint32_t outseqno;
|
||||
|
||||
ecdsa_t *mykey;
|
||||
|
|
@ -85,11 +85,11 @@ extern unsigned int sptps_replaywin;
|
|||
extern void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap);
|
||||
extern void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap);
|
||||
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 char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record);
|
||||
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 char *data, uint16_t len);
|
||||
extern bool sptps_receive_data(sptps_t *s, const char *data, size_t len);
|
||||
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 bool sptps_force_kex(sptps_t *s);
|
||||
extern bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len);
|
||||
extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
108
src/sptps_keypair.c
Normal file
108
src/sptps_keypair.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
sptps_test.c -- Simple Peer-to-Peer Security test program
|
||||
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 <getopt.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "ecdsagen.h"
|
||||
#include "utils.h"
|
||||
|
||||
static char *program_name;
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s [options] private_key_file public_key_file\n\n", program_name);
|
||||
fprintf(stderr, "Valid options are:\n"
|
||||
" --help Display this help and exit.\n"
|
||||
"\n");
|
||||
fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
|
||||
}
|
||||
|
||||
static struct option const long_options[] = {
|
||||
{"help", no_argument, NULL, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
program_name = argv[0];
|
||||
int r;
|
||||
int option_index = 0;
|
||||
|
||||
while((r = getopt_long(argc, argv, "", long_options, &option_index)) != EOF) {
|
||||
switch (r) {
|
||||
case 0: /* long option */
|
||||
break;
|
||||
|
||||
case '?': /* wrong options */
|
||||
usage();
|
||||
return 1;
|
||||
|
||||
case 1: /* help */
|
||||
usage();
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind - 1;
|
||||
argv += optind - 1;
|
||||
|
||||
if(argc != 3) {
|
||||
fprintf(stderr, "Wrong number of arguments.\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_init();
|
||||
|
||||
ecdsa_t *key = ecdsa_generate();
|
||||
if(!key)
|
||||
return 1;
|
||||
|
||||
FILE *fp = fopen(argv[1], "w");
|
||||
if(fp) {
|
||||
ecdsa_write_pem_private_key(key, fp);
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp = fopen(argv[2], "w");
|
||||
if(fp) {
|
||||
ecdsa_write_pem_public_key(key, fp);
|
||||
fclose(fp);
|
||||
} else {
|
||||
fprintf(stderr, "Could not open '%s' for writing: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
232
src/sptps_speed.c
Normal file
232
src/sptps_speed.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
sptps_speed.c -- SPTPS benchmark
|
||||
Copyright (C) 2013-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 "utils.h"
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "ecdh.h"
|
||||
#include "ecdsa.h"
|
||||
#include "ecdsagen.h"
|
||||
#include "sptps.h"
|
||||
|
||||
// Symbols necessary to link with logger.o
|
||||
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;
|
||||
struct timeval now;
|
||||
|
||||
static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
int fd = *(int *)handle;
|
||||
send(fd, data, len, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void receive_data(sptps_t *sptps) {
|
||||
char buf[4096];
|
||||
int fd = *(int *)sptps->handle;
|
||||
size_t len = recv(fd, buf, sizeof buf, 0);
|
||||
if(!sptps_receive_data(sptps, buf, len))
|
||||
abort();
|
||||
}
|
||||
|
||||
struct timespec start;
|
||||
struct timespec end;
|
||||
double elapsed;
|
||||
double rate;
|
||||
unsigned int count;
|
||||
|
||||
static void clock_start() {
|
||||
count = 0;
|
||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
|
||||
}
|
||||
|
||||
static bool clock_countto(double seconds) {
|
||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
|
||||
elapsed = end.tv_sec + end.tv_nsec * 1e-9 - start.tv_sec - start.tv_nsec * 1e-9;
|
||||
if(elapsed < seconds)
|
||||
return ++count;
|
||||
|
||||
rate = count / elapsed;
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ecdsa_t *key1, *key2;
|
||||
ecdh_t *ecdh1, *ecdh2;
|
||||
sptps_t sptps1, sptps2;
|
||||
char buf1[4096], buf2[4096], buf3[4096];
|
||||
double duration = argc > 1 ? atof(argv[1]) : 10;
|
||||
|
||||
crypto_init();
|
||||
|
||||
randomize(buf1, sizeof buf1);
|
||||
randomize(buf2, sizeof buf2);
|
||||
randomize(buf3, sizeof buf3);
|
||||
|
||||
// Key generation
|
||||
|
||||
fprintf(stderr, "Generating keys for %lg seconds: ", duration);
|
||||
for(clock_start(); clock_countto(duration);)
|
||||
ecdsa_free(ecdsa_generate());
|
||||
fprintf(stderr, "%17.2lf op/s\n", rate);
|
||||
|
||||
key1 = ecdsa_generate();
|
||||
key2 = ecdsa_generate();
|
||||
|
||||
// Ed25519 signatures
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
fprintf(stderr, "%28.2lf op/s\n", rate);
|
||||
ecdh_free(ecdh1);
|
||||
|
||||
// SPTPS authentication phase
|
||||
|
||||
int fd[2];
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
|
||||
fprintf(stderr, "Could not create a UNIX socket pair: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct pollfd pfd[2] = {{fd[0], POLLIN}, {fd[1], POLLIN}};
|
||||
|
||||
fprintf(stderr, "SPTPS/TCP authenticate for %lg seconds: ", duration);
|
||||
for(clock_start(); clock_countto(duration);) {
|
||||
sptps_start(&sptps1, fd + 0, true, false, key1, key2, "sptps_speed", 11, send_data, receive_record);
|
||||
sptps_start(&sptps2, fd + 1, false, false, key2, key1, "sptps_speed", 11, send_data, receive_record);
|
||||
while(poll(pfd, 2, 0)) {
|
||||
if(pfd[0].revents)
|
||||
receive_data(&sptps1);
|
||||
if(pfd[1].revents)
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
sptps_stop(&sptps1);
|
||||
sptps_stop(&sptps2);
|
||||
}
|
||||
fprintf(stderr, "%10.2lf op/s\n", rate * 2);
|
||||
|
||||
// SPTPS data
|
||||
|
||||
sptps_start(&sptps1, fd + 0, true, false, key1, key2, "sptps_speed", 11, send_data, receive_record);
|
||||
sptps_start(&sptps2, fd + 1, false, false, key2, key1, "sptps_speed", 11, send_data, receive_record);
|
||||
while(poll(pfd, 2, 0)) {
|
||||
if(pfd[0].revents)
|
||||
receive_data(&sptps1);
|
||||
if(pfd[1].revents)
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
fprintf(stderr, "SPTPS/TCP transmit for %lg seconds: ", duration);
|
||||
for(clock_start(); clock_countto(duration);) {
|
||||
if(!sptps_send_record(&sptps1, 0, buf1, 1451))
|
||||
abort();
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
rate *= 2 * 1451 * 8;
|
||||
if(rate > 1e9)
|
||||
fprintf(stderr, "%14.2lf Gbit/s\n", rate / 1e9);
|
||||
else if(rate > 1e6)
|
||||
fprintf(stderr, "%14.2lf Mbit/s\n", rate / 1e6);
|
||||
else if(rate > 1e3)
|
||||
fprintf(stderr, "%14.2lf kbit/s\n", rate / 1e3);
|
||||
sptps_stop(&sptps1);
|
||||
sptps_stop(&sptps2);
|
||||
|
||||
// SPTPS datagram authentication phase
|
||||
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_DGRAM, 0, fd)) {
|
||||
fprintf(stderr, "Could not create a UNIX socket pair: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "SPTPS/UDP authenticate for %lg seconds: ", duration);
|
||||
for(clock_start(); clock_countto(duration);) {
|
||||
sptps_start(&sptps1, fd + 0, true, true, key1, key2, "sptps_speed", 11, send_data, receive_record);
|
||||
sptps_start(&sptps2, fd + 1, false, true, key2, key1, "sptps_speed", 11, send_data, receive_record);
|
||||
while(poll(pfd, 2, 0)) {
|
||||
if(pfd[0].revents)
|
||||
receive_data(&sptps1);
|
||||
if(pfd[1].revents)
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
sptps_stop(&sptps1);
|
||||
sptps_stop(&sptps2);
|
||||
}
|
||||
fprintf(stderr, "%10.2lf op/s\n", rate * 2);
|
||||
|
||||
// SPTPS datagram data
|
||||
|
||||
sptps_start(&sptps1, fd + 0, true, true, key1, key2, "sptps_speed", 11, send_data, receive_record);
|
||||
sptps_start(&sptps2, fd + 1, false, true, key2, key1, "sptps_speed", 11, send_data, receive_record);
|
||||
while(poll(pfd, 2, 0)) {
|
||||
if(pfd[0].revents)
|
||||
receive_data(&sptps1);
|
||||
if(pfd[1].revents)
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
fprintf(stderr, "SPTPS/UDP transmit for %lg seconds: ", duration);
|
||||
for(clock_start(); clock_countto(duration);) {
|
||||
if(!sptps_send_record(&sptps1, 0, buf1, 1451))
|
||||
abort();
|
||||
receive_data(&sptps2);
|
||||
}
|
||||
rate *= 2 * 1451 * 8;
|
||||
if(rate > 1e9)
|
||||
fprintf(stderr, "%14.2lf Gbit/s\n", rate / 1e9);
|
||||
else if(rate > 1e6)
|
||||
fprintf(stderr, "%14.2lf Mbit/s\n", rate / 1e6);
|
||||
else if(rate > 1e3)
|
||||
fprintf(stderr, "%14.2lf kbit/s\n", rate / 1e3);
|
||||
sptps_stop(&sptps1);
|
||||
sptps_stop(&sptps2);
|
||||
|
||||
// Clean up
|
||||
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
ecdsa_free(key1);
|
||||
ecdsa_free(key2);
|
||||
crypto_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
109
src/sptps_test.c
109
src/sptps_test.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
sptps_test.c -- Simple Peer-to-Peer Security test program
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2011-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
|
||||
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#ifdef HAVE_LINUX
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
|
@ -33,23 +37,28 @@ bool send_meta(void *c, const char *msg , int len) { return false; }
|
|||
char *logfilename = NULL;
|
||||
struct timeval now;
|
||||
|
||||
static bool verbose;
|
||||
static bool readonly;
|
||||
static bool writeonly;
|
||||
static int in = 0;
|
||||
static int out = 1;
|
||||
|
||||
static bool send_data(void *handle, uint8_t type, const char *data, size_t len) {
|
||||
static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
char hex[len * 2 + 1];
|
||||
bin2hex(data, hex, len);
|
||||
fprintf(stderr, "Sending %d bytes of data:\n%s\n", (int)len, hex);
|
||||
if(verbose)
|
||||
fprintf(stderr, "Sending %d bytes of data:\n%s\n", (int)len, hex);
|
||||
const int *sock = handle;
|
||||
if(send(*sock, data, len, 0) != len)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool receive_record(void *handle, uint8_t type, const char *data, uint16_t len) {
|
||||
fprintf(stderr, "Received type %d record of %hu bytes:\n", type, len);
|
||||
static bool receive_record(void *handle, uint8_t type, const void *data, uint16_t len) {
|
||||
if(verbose)
|
||||
fprintf(stderr, "Received type %d record of %hu bytes:\n", type, len);
|
||||
if(!writeonly)
|
||||
fwrite(data, len, 1, stdout);
|
||||
write(out, data, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +69,7 @@ static struct option const long_options[] = {
|
|||
{"writeonly", no_argument, NULL, 'w'},
|
||||
{"packet-loss", required_argument, NULL, 'L'},
|
||||
{"replay-window", required_argument, NULL, 'W'},
|
||||
{"verbose", required_argument, NULL, 'v'},
|
||||
{"help", no_argument, NULL, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
|
@ -67,14 +77,18 @@ static struct option const long_options[] = {
|
|||
const char *program_name;
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s [options] my_ecdsa_key_file his_ecdsa_key_file [host] port\n\n", program_name);
|
||||
fprintf(stderr, "Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n\n", program_name);
|
||||
fprintf(stderr, "Valid options are:\n"
|
||||
" -d, --datagram Enable datagram mode.\n"
|
||||
" -q, --quit Quit when EOF occurs on stdin.\n"
|
||||
" -r, --readonly Only send data from the socket to stdout.\n"
|
||||
#ifdef HAVE_LINUX
|
||||
" -t, --tun Use a tun device instead of stdio.\n"
|
||||
#endif
|
||||
" -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"
|
||||
" -v, --verbose Display debug messages.\n"
|
||||
"\n");
|
||||
fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
|
||||
}
|
||||
|
|
@ -83,13 +97,16 @@ int main(int argc, char *argv[]) {
|
|||
program_name = argv[0];
|
||||
bool initiator = false;
|
||||
bool datagram = false;
|
||||
#ifdef HAVE_LINUX
|
||||
bool tun = false;
|
||||
#endif
|
||||
int packetloss = 0;
|
||||
int r;
|
||||
int option_index = 0;
|
||||
ecdsa_t *mykey = NULL, *hiskey = NULL;
|
||||
bool quit = false;
|
||||
|
||||
while((r = getopt_long(argc, argv, "dqrwL:W:", long_options, &option_index)) != EOF) {
|
||||
while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) {
|
||||
switch (r) {
|
||||
case 0: /* long option */
|
||||
break;
|
||||
|
|
@ -106,6 +123,16 @@ int main(int argc, char *argv[]) {
|
|||
readonly = true;
|
||||
break;
|
||||
|
||||
case 't': /* read only */
|
||||
#ifdef HAVE_LINUX
|
||||
tun = true;
|
||||
#else
|
||||
fprintf(stderr, "--tun is only supported on Linux.\n");
|
||||
usage();
|
||||
return 1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'w': /* write only */
|
||||
writeonly = true;
|
||||
break;
|
||||
|
|
@ -118,6 +145,10 @@ int main(int argc, char *argv[]) {
|
|||
sptps_replaywin = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'v': /* be verbose */
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
case '?': /* wrong options */
|
||||
usage();
|
||||
return 1;
|
||||
|
|
@ -145,6 +176,25 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
srand(time(NULL));
|
||||
|
||||
#ifdef HAVE_LINUX
|
||||
if(tun) {
|
||||
in = out = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
|
||||
if(in < 0) {
|
||||
fprintf(stderr, "Could not open tun device: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
struct ifreq ifr = {
|
||||
.ifr_flags = IFF_TUN
|
||||
};
|
||||
if(ioctl(in, TUNSETIFF, &ifr)) {
|
||||
fprintf(stderr, "Could not configure tun interface: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
fprintf(stderr, "Using tun interface %s\n", ifr.ifr_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
static struct WSAData wsa_state;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsa_state))
|
||||
|
|
@ -160,13 +210,13 @@ int main(int argc, char *argv[]) {
|
|||
hint.ai_flags = initiator ? 0 : AI_PASSIVE;
|
||||
|
||||
if(getaddrinfo(initiator ? argv[3] : NULL, initiator ? argv[4] : argv[3], &hint, &ai) || !ai) {
|
||||
fprintf(stderr, "getaddrinfo() failed: %s\n", strerror(errno));
|
||||
fprintf(stderr, "getaddrinfo() failed: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if(sock < 0) {
|
||||
fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not create socket: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -175,26 +225,26 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if(initiator) {
|
||||
if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
|
||||
fprintf(stderr, "Could not connect to peer: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not connect to peer: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Connected\n");
|
||||
} else {
|
||||
if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
|
||||
fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not bind socket: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!datagram) {
|
||||
if(listen(sock, 1)) {
|
||||
fprintf(stderr, "Could not listen on socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not listen on socket: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "Listening...\n");
|
||||
|
||||
sock = accept(sock, NULL, NULL);
|
||||
if(sock < 0) {
|
||||
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -205,12 +255,12 @@ int main(int argc, char *argv[]) {
|
|||
socklen_t addrlen = sizeof addr;
|
||||
|
||||
if(recvfrom(sock, buf, sizeof buf, MSG_PEEK, &addr, &addrlen) <= 0) {
|
||||
fprintf(stderr, "Could not read from socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(connect(sock, &addr, addrlen)) {
|
||||
fprintf(stderr, "Could not accept connection: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not accept connection: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -230,7 +280,8 @@ int main(int argc, char *argv[]) {
|
|||
return 1;
|
||||
fclose(fp);
|
||||
|
||||
fprintf(stderr, "Keys loaded\n");
|
||||
if(verbose)
|
||||
fprintf(stderr, "Keys loaded\n");
|
||||
|
||||
sptps_t s;
|
||||
if(!sptps_start(&s, &sock, initiator, datagram, mykey, hiskey, "sptps_test", 10, send_data, receive_record))
|
||||
|
|
@ -246,15 +297,14 @@ int main(int argc, char *argv[]) {
|
|||
FD_ZERO(&fds);
|
||||
#ifndef HAVE_MINGW
|
||||
if(!readonly && s.instate)
|
||||
FD_SET(0, &fds);
|
||||
FD_SET(in, &fds);
|
||||
#endif
|
||||
FD_SET(sock, &fds);
|
||||
if(select(sock + 1, &fds, NULL, NULL, NULL) <= 0)
|
||||
return 1;
|
||||
|
||||
if(FD_ISSET(0, &fds)) {
|
||||
ssize_t len = read(0, buf, sizeof buf);
|
||||
fprintf(stderr, "%zd\n", len);
|
||||
if(FD_ISSET(in, &fds)) {
|
||||
ssize_t len = read(in, buf, sizeof buf);
|
||||
if(len < 0) {
|
||||
fprintf(stderr, "Could not read from stdin: %s\n", strerror(errno));
|
||||
return 1;
|
||||
|
|
@ -274,25 +324,28 @@ int main(int argc, char *argv[]) {
|
|||
if(len > 1)
|
||||
sptps_send_record(&s, 0, buf, len);
|
||||
} else
|
||||
if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, buf[0] == '\n' ? 0 : buf[0] == '*' ? sizeof buf : len))
|
||||
if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof buf : len))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(FD_ISSET(sock, &fds)) {
|
||||
ssize_t len = recv(sock, buf, sizeof buf, 0);
|
||||
if(len < 0) {
|
||||
fprintf(stderr, "Could not read from socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
|
||||
return 1;
|
||||
}
|
||||
if(len == 0) {
|
||||
fprintf(stderr, "Connection terminated by peer.\n");
|
||||
break;
|
||||
}
|
||||
char hex[len * 2 + 1];
|
||||
bin2hex(buf, hex, len);
|
||||
fprintf(stderr, "Received %d bytes of data:\n%s\n", (int)len, hex);
|
||||
if((rand() % 100) < packetloss) {
|
||||
fprintf(stderr, "Dropped.\n");
|
||||
if(verbose) {
|
||||
char hex[len * 2 + 1];
|
||||
bin2hex(buf, hex, len);
|
||||
fprintf(stderr, "Received %d bytes of data:\n%s\n", (int)len, hex);
|
||||
}
|
||||
if(packetloss && (rand() % 100) < packetloss) {
|
||||
if(verbose)
|
||||
fprintf(stderr, "Dropped.\n");
|
||||
continue;
|
||||
}
|
||||
if(!sptps_receive_data(&s, buf, len) && !datagram)
|
||||
|
|
|
|||
44
src/subnet.c
44
src/subnet.c
|
|
@ -92,13 +92,15 @@ void subnet_add(node_t *n, subnet_t *subnet) {
|
|||
subnet->owner = n;
|
||||
|
||||
splay_insert(subnet_tree, subnet);
|
||||
splay_insert(n->subnet_tree, subnet);
|
||||
if (n)
|
||||
splay_insert(n->subnet_tree, subnet);
|
||||
|
||||
subnet_cache_flush();
|
||||
}
|
||||
|
||||
void subnet_del(node_t *n, subnet_t *subnet) {
|
||||
splay_delete(n->subnet_tree, subnet);
|
||||
if (n)
|
||||
splay_delete(n->subnet_tree, subnet);
|
||||
splay_delete(subnet_tree, subnet);
|
||||
|
||||
subnet_cache_flush();
|
||||
|
|
@ -126,7 +128,7 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
|
|||
|
||||
if(!memcmp(address, &p->net.mac.address, sizeof *address)) {
|
||||
r = p;
|
||||
if(p->owner->status.reachable)
|
||||
if(!p->owner || p->owner->status.reachable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +157,7 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
|||
|
||||
if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
|
||||
r = p;
|
||||
if(p->owner->status.reachable)
|
||||
if(!p->owner || p->owner->status.reachable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,7 +186,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
|
|||
|
||||
if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
|
||||
r = p;
|
||||
if(p->owner->status.reachable)
|
||||
if(!p->owner || p->owner->status.reachable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -205,21 +207,21 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
// Prepare environment variables to be passed to the script
|
||||
|
||||
char *envp[10] = {NULL};
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NODE=%s", owner->name);
|
||||
int n = 0;
|
||||
xasprintf(&envp[n++], "NETNAME=%s", netname ? : "");
|
||||
xasprintf(&envp[n++], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[n++], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[n++], "NODE=%s", owner->name);
|
||||
|
||||
if(owner != myself) {
|
||||
sockaddr2str(&owner->address, &address, &port);
|
||||
// 4 and 5 are reserved for SUBNET and WEIGHT
|
||||
xasprintf(&envp[6], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[7], "REMOTEPORT=%s", port);
|
||||
xasprintf(&envp[n++], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[n++], "REMOTEPORT=%s", port);
|
||||
free(port);
|
||||
free(address);
|
||||
}
|
||||
|
||||
xasprintf(&envp[8], "NAME=%s", myself->name);
|
||||
xasprintf(&envp[n++], "NAME=%s", myself->name);
|
||||
|
||||
name = up ? "subnet-up" : "subnet-down";
|
||||
|
||||
|
|
@ -236,12 +238,10 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
weight = empty;
|
||||
|
||||
// Prepare the SUBNET and WEIGHT variables
|
||||
if(envp[4])
|
||||
free(envp[4]);
|
||||
if(envp[5])
|
||||
free(envp[5]);
|
||||
xasprintf(&envp[4], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[5], "WEIGHT=%s", weight);
|
||||
free(envp[n]);
|
||||
free(envp[n + 1]);
|
||||
xasprintf(&envp[n], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
|
||||
|
||||
execute_script(name, envp);
|
||||
}
|
||||
|
|
@ -255,8 +255,8 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
weight = empty;
|
||||
|
||||
// Prepare the SUBNET and WEIGHT variables
|
||||
xasprintf(&envp[4], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[5], "WEIGHT=%s", weight);
|
||||
xasprintf(&envp[n], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
|
||||
|
||||
execute_script(name, envp);
|
||||
}
|
||||
|
|
@ -275,7 +275,7 @@ bool dump_subnets(connection_t *c) {
|
|||
|
||||
send_request(c, "%d %d %s %s",
|
||||
CONTROL, REQ_DUMP_SUBNETS,
|
||||
netstr, subnet->owner->name);
|
||||
netstr, subnet->owner ? subnet->owner->name : "(broadcast)");
|
||||
}
|
||||
|
||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Changing this default will affect ADD_SUBNET messages - beware of inconsistencies between versions */
|
||||
static const int DEFAULT_WEIGHT = 10;
|
||||
|
||||
/* Subnet mask handling */
|
||||
|
||||
int maskcmp(const void *va, const void *vb, int masklen) {
|
||||
|
|
@ -181,150 +184,121 @@ int subnet_compare(const subnet_t *a, const subnet_t *b) {
|
|||
/* Ascii representation of subnets */
|
||||
|
||||
bool str2net(subnet_t *subnet, const char *subnetstr) {
|
||||
int i, l;
|
||||
char str[1024];
|
||||
strncpy(str, subnetstr, sizeof(str));
|
||||
str[sizeof str - 1] = 0;
|
||||
int consumed;
|
||||
|
||||
int weight = DEFAULT_WEIGHT;
|
||||
char *weight_separator = strchr(str, '#');
|
||||
if (weight_separator) {
|
||||
char *weight_str = weight_separator + 1;
|
||||
if (sscanf(weight_str, "%d%n", &weight, &consumed) < 1)
|
||||
return false;
|
||||
if (weight_str[consumed])
|
||||
return false;
|
||||
*weight_separator = 0;
|
||||
}
|
||||
|
||||
int prefixlength = -1;
|
||||
char *prefixlength_separator = strchr(str, '/');
|
||||
if (prefixlength_separator) {
|
||||
char* prefixlength_str = prefixlength_separator + 1;
|
||||
if (sscanf(prefixlength_str, "%d%n", &prefixlength, &consumed) < 1)
|
||||
return false;
|
||||
if (prefixlength_str[consumed])
|
||||
return false;
|
||||
*prefixlength_separator = 0;
|
||||
|
||||
if (prefixlength < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t x[8];
|
||||
int weight = 10;
|
||||
|
||||
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
|
||||
&x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
|
||||
if(l < 0 || l > 32)
|
||||
if (sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx%n", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &consumed) >= 6 && !str[consumed]) {
|
||||
/*
|
||||
Normally we should check that each part has two digits to prevent ambiguities.
|
||||
However, in old tinc versions net2str() will agressively return MAC addresses with one-digit parts,
|
||||
so we have to accept them otherwise we would be unable to parse ADD_SUBNET messages.
|
||||
*/
|
||||
if (prefixlength >= 0)
|
||||
return false;
|
||||
|
||||
subnet->type = SUBNET_IPV4;
|
||||
subnet->net.ipv4.prefixlength = l;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(x[i] > 255)
|
||||
return false;
|
||||
subnet->net.ipv4.address.x[i] = x[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
|
||||
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
|
||||
&l, &weight) >= 9) {
|
||||
if(l < 0 || l > 128)
|
||||
return false;
|
||||
|
||||
subnet->type = SUBNET_IPV6;
|
||||
subnet->net.ipv6.prefixlength = l;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
subnet->net.ipv6.address.x[i] = htons(x[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu#%d", &x[0], &x[1], &x[2], &x[3], &weight) >= 4) {
|
||||
subnet->type = SUBNET_IPV4;
|
||||
subnet->net.ipv4.prefixlength = 32;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
if(x[i] > 255)
|
||||
return false;
|
||||
subnet->net.ipv4.address.x[i] = x[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d",
|
||||
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) {
|
||||
subnet->type = SUBNET_IPV6;
|
||||
subnet->net.ipv6.prefixlength = 128;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
subnet->net.ipv6.address.x[i] = htons(x[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
|
||||
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) {
|
||||
subnet->type = SUBNET_MAC;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(i = 0; i < 6; i++)
|
||||
for(int i = 0; i < 6; i++)
|
||||
subnet->net.mac.address.x[i] = x[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// IPv6 short form
|
||||
if(strstr(subnetstr, "::")) {
|
||||
const char *p;
|
||||
char *q;
|
||||
int colons = 0;
|
||||
|
||||
// Count number of colons
|
||||
for(p = subnetstr; *p; p++)
|
||||
if(*p == ':')
|
||||
colons++;
|
||||
|
||||
if(colons > 7)
|
||||
if (sscanf(str, "%hu.%hu.%hu.%hu%n", &x[0], &x[1], &x[2], &x[3], &consumed) >= 4 && !str[consumed]) {
|
||||
if (prefixlength == -1)
|
||||
prefixlength = 32;
|
||||
if (prefixlength > 32)
|
||||
return false;
|
||||
|
||||
// Scan numbers before the double colon
|
||||
p = subnetstr;
|
||||
for(i = 0; i < colons; i++) {
|
||||
if(*p == ':')
|
||||
break;
|
||||
x[i] = strtoul(p, &q, 0x10);
|
||||
if(!q || p == q || *q != ':')
|
||||
subnet->type = SUBNET_IPV4;
|
||||
subnet->net.ipv4.prefixlength = prefixlength;
|
||||
subnet->weight = weight;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if (x[i] > 255)
|
||||
return false;
|
||||
p = ++q;
|
||||
subnet->net.ipv4.address.x[i] = x[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
p++;
|
||||
colons -= i;
|
||||
if(!i) {
|
||||
p++;
|
||||
colons--;
|
||||
}
|
||||
/* IPv6 */
|
||||
|
||||
if(!*p || *p == '/' || *p == '#')
|
||||
colons--;
|
||||
|
||||
// Fill in the blanks
|
||||
for(; i < 8 - colons; i++)
|
||||
x[i] = 0;
|
||||
|
||||
// Scan the remaining numbers
|
||||
for(; i < 8; i++) {
|
||||
x[i] = strtoul(p, &q, 0x10);
|
||||
if(!q || p == q)
|
||||
char* last_colon = strrchr(str, ':');
|
||||
if (last_colon && sscanf(last_colon, ":%hu.%hu.%hu.%hu%n", &x[0], &x[1], &x[2], &x[3], &consumed) >= 4 && !last_colon[consumed]) {
|
||||
/* Dotted quad suffix notation, convert to standard IPv6 notation */
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (x[i] > 255)
|
||||
return false;
|
||||
if(i == 7) {
|
||||
p = q;
|
||||
break;
|
||||
snprintf(last_colon, sizeof str - (last_colon - str), ":%02x%02x:%02x%02x", x[0], x[1], x[2], x[3]);
|
||||
}
|
||||
|
||||
char* double_colon = strstr(str, "::");
|
||||
if (double_colon) {
|
||||
/* Figure out how many zero groups we need to expand */
|
||||
int zero_group_count = 8;
|
||||
for (const char* cur = str; *cur; cur++)
|
||||
if (*cur != ':') {
|
||||
zero_group_count--;
|
||||
while(cur[1] && cur[1] != ':')
|
||||
cur++;
|
||||
}
|
||||
if(*q != ':')
|
||||
return false;
|
||||
p = ++q;
|
||||
}
|
||||
if (zero_group_count < 1)
|
||||
return false;
|
||||
|
||||
l = 128;
|
||||
if(*p == '/')
|
||||
sscanf(p, "/%d#%d", &l, &weight);
|
||||
else if(*p == '#')
|
||||
sscanf(p, "#%d", &weight);
|
||||
/* Split the double colon in the middle to make room for zero groups */
|
||||
double_colon++;
|
||||
memmove(double_colon + (zero_group_count * 2 - 1), double_colon, strlen(double_colon) + 1);
|
||||
|
||||
if(l < 0 || l > 128)
|
||||
/* Write zero groups in the resulting gap, overwriting the second colon */
|
||||
for (int i = 0; i < zero_group_count; i++)
|
||||
memcpy(&double_colon[i * 2], "0:", 2);
|
||||
|
||||
/* Remove any leading or trailing colons */
|
||||
if (str[0] == ':')
|
||||
memmove(&str[0], &str[1], strlen(&str[1]) + 1);
|
||||
if (str[strlen(str) - 1] == ':')
|
||||
str[strlen(str) - 1] = 0;
|
||||
}
|
||||
|
||||
if (sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx%n",
|
||||
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &consumed) >= 8 && !str[consumed]) {
|
||||
if (prefixlength == -1)
|
||||
prefixlength = 128;
|
||||
if (prefixlength > 128)
|
||||
return false;
|
||||
|
||||
subnet->type = SUBNET_IPV6;
|
||||
subnet->net.ipv6.prefixlength = l;
|
||||
subnet->net.ipv6.prefixlength = prefixlength;
|
||||
subnet->weight = weight;
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
for(int i = 0; i < 8; i++)
|
||||
subnet->net.ipv6.address.x[i] = htons(x[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -337,46 +311,101 @@ bool net2str(char *netstr, int len, const subnet_t *subnet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int result;
|
||||
int prefixlength = -1;
|
||||
switch (subnet->type) {
|
||||
case SUBNET_MAC:
|
||||
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
|
||||
result = snprintf(netstr, len, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
subnet->net.mac.address.x[0],
|
||||
subnet->net.mac.address.x[1],
|
||||
subnet->net.mac.address.x[2],
|
||||
subnet->net.mac.address.x[3],
|
||||
subnet->net.mac.address.x[4],
|
||||
subnet->net.mac.address.x[5],
|
||||
subnet->weight);
|
||||
subnet->net.mac.address.x[5]);
|
||||
netstr += result;
|
||||
len -= result;
|
||||
break;
|
||||
|
||||
case SUBNET_IPV4:
|
||||
snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d#%d",
|
||||
result = snprintf(netstr, len, "%u.%u.%u.%u",
|
||||
subnet->net.ipv4.address.x[0],
|
||||
subnet->net.ipv4.address.x[1],
|
||||
subnet->net.ipv4.address.x[2],
|
||||
subnet->net.ipv4.address.x[3],
|
||||
subnet->net.ipv4.prefixlength,
|
||||
subnet->weight);
|
||||
subnet->net.ipv4.address.x[3]);
|
||||
netstr += result;
|
||||
len -= result;
|
||||
prefixlength = subnet->net.ipv4.prefixlength;
|
||||
if (prefixlength == 32)
|
||||
prefixlength = -1;
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
|
||||
ntohs(subnet->net.ipv6.address.x[0]),
|
||||
ntohs(subnet->net.ipv6.address.x[1]),
|
||||
ntohs(subnet->net.ipv6.address.x[2]),
|
||||
ntohs(subnet->net.ipv6.address.x[3]),
|
||||
ntohs(subnet->net.ipv6.address.x[4]),
|
||||
ntohs(subnet->net.ipv6.address.x[5]),
|
||||
ntohs(subnet->net.ipv6.address.x[6]),
|
||||
ntohs(subnet->net.ipv6.address.x[7]),
|
||||
subnet->net.ipv6.prefixlength,
|
||||
subnet->weight);
|
||||
case SUBNET_IPV6: {
|
||||
/* Find the longest sequence of consecutive zeroes */
|
||||
int max_zero_length = 0;
|
||||
int max_zero_length_index = 0;
|
||||
int current_zero_length = 0;
|
||||
int current_zero_length_index = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (subnet->net.ipv6.address.x[i] != 0)
|
||||
current_zero_length = 0;
|
||||
else {
|
||||
if (current_zero_length == 0)
|
||||
current_zero_length_index = i;
|
||||
current_zero_length++;
|
||||
if (current_zero_length > max_zero_length) {
|
||||
max_zero_length = current_zero_length;
|
||||
max_zero_length_index = current_zero_length_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the address */
|
||||
for (int i = 0; i < 8;) {
|
||||
if (max_zero_length > 1 && max_zero_length_index == i) {
|
||||
/* Shorten the representation as per RFC 5952 */
|
||||
const char* const FORMATS[] = { "%.1s", "%.2s", "%.3s" };
|
||||
const char* const* format = &FORMATS[0];
|
||||
if (i == 0)
|
||||
format++;
|
||||
if (i + max_zero_length == 8)
|
||||
format++;
|
||||
result = snprintf(netstr, len, *format, ":::");
|
||||
i += max_zero_length;
|
||||
} else {
|
||||
result = snprintf(netstr, len, "%hx:", ntohs(subnet->net.ipv6.address.x[i]));
|
||||
i++;
|
||||
}
|
||||
netstr += result;
|
||||
len -= result;
|
||||
}
|
||||
|
||||
/* Remove the trailing colon */
|
||||
netstr--;
|
||||
len++;
|
||||
*netstr = 0;
|
||||
|
||||
prefixlength = subnet->net.ipv6.prefixlength;
|
||||
if (prefixlength == 128)
|
||||
prefixlength = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "net2str() was called with unknown subnet type %d, exiting!", subnet->type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (prefixlength >= 0) {
|
||||
result = snprintf(netstr, len, "/%d", prefixlength);
|
||||
netstr += result;
|
||||
len -= result;
|
||||
}
|
||||
|
||||
if (subnet->weight != DEFAULT_WEIGHT) {
|
||||
snprintf(netstr, len, "#%d", subnet->weight);
|
||||
netstr += result;
|
||||
len -= result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
232
src/tincctl.c
232
src/tincctl.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
tincctl.c -- Controlling a running tincd
|
||||
Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
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
|
||||
|
|
@ -38,6 +38,11 @@
|
|||
#include "utils.h"
|
||||
#include "tincctl.h"
|
||||
#include "top.h"
|
||||
#include "version.h"
|
||||
|
||||
#ifndef MSG_NOSIGNAL
|
||||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
static char **orig_argv;
|
||||
static int orig_argc;
|
||||
|
|
@ -67,8 +72,10 @@ bool confbasegiven = false;
|
|||
bool netnamegiven = false;
|
||||
char *scriptinterpreter = NULL;
|
||||
char *scriptextension = "";
|
||||
static char *prompt;
|
||||
|
||||
static struct option const long_options[] = {
|
||||
{"batch", no_argument, NULL, 'b'},
|
||||
{"config", required_argument, NULL, 'c'},
|
||||
{"net", required_argument, NULL, 'n'},
|
||||
{"help", no_argument, NULL, 1},
|
||||
|
|
@ -80,8 +87,8 @@ static struct option const long_options[] = {
|
|||
|
||||
static void version(void) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
VERSION, __DATE__, __TIME__, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2012 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2014 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"
|
||||
|
|
@ -94,6 +101,7 @@ static void usage(bool status) {
|
|||
} else {
|
||||
printf("Usage: %s [options] command\n\n", program_name);
|
||||
printf("Valid options are:\n"
|
||||
" -b, --batch Don't ask for anything (non-interactive mode).\n"
|
||||
" -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"
|
||||
|
|
@ -111,9 +119,9 @@ 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"
|
||||
" generate-keys [bits] Generate new RSA and ECDSA public/private keypairs.\n"
|
||||
" generate-keys [bits] Generate new RSA and Ed25519 public/private keypairs.\n"
|
||||
" generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n"
|
||||
" generate-ecdsa-keys Generate a new ECDSA public/private keypair.\n"
|
||||
" 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"
|
||||
" edges - all known connections in the VPN\n"
|
||||
|
|
@ -137,6 +145,7 @@ static void usage(bool status) {
|
|||
" exchange-all [--force] 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"
|
||||
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
|
||||
"\n");
|
||||
printf("Report bugs to tinc@tinc-vpn.org.\n");
|
||||
}
|
||||
|
|
@ -151,6 +160,10 @@ static bool parse_options(int argc, char **argv) {
|
|||
case 0: /* long option */
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
tty = false;
|
||||
break;
|
||||
|
||||
case 'c': /* config file */
|
||||
confbase = xstrdup(optarg);
|
||||
confbasegiven = true;
|
||||
|
|
@ -240,19 +253,19 @@ static void disable_old_keys(const char *filename, const char *what) {
|
|||
|
||||
while(fgets(buf, sizeof buf, r)) {
|
||||
if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
|
||||
if((strstr(buf, " EC ") && strstr(what, "ECDSA")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
|
||||
if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
|
||||
disabled = true;
|
||||
block = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ecdsapubkey = !strncasecmp(buf, "ECDSAPublicKey", 14) && strchr(" \t=", buf[14]) && strstr(what, "ECDSA");
|
||||
bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
|
||||
|
||||
if(ecdsapubkey)
|
||||
if(ed25519pubkey)
|
||||
disabled = true;
|
||||
|
||||
if(w) {
|
||||
if(block || ecdsapubkey)
|
||||
if(block || ed25519pubkey)
|
||||
fputc('#', w);
|
||||
if(fputs(buf, w) < 0) {
|
||||
error = true;
|
||||
|
|
@ -308,8 +321,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
|
|||
/* Check stdin and stdout */
|
||||
if(ask && tty) {
|
||||
/* Ask for a file and/or directory name. */
|
||||
fprintf(stdout, "Please enter a file to save %s to [%s]: ", what, filename);
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Please enter a file to save %s to [%s]: ", what, filename);
|
||||
|
||||
if(fgets(buf, sizeof buf, stdin) == NULL) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
|
||||
|
|
@ -350,15 +362,15 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
|
|||
}
|
||||
|
||||
/*
|
||||
Generate a public/private ECDSA keypair, and ask for a file to store
|
||||
Generate a public/private Ed25519 keypair, and ask for a file to store
|
||||
them in.
|
||||
*/
|
||||
static bool ecdsa_keygen(bool ask) {
|
||||
static bool ed25519_keygen(bool ask) {
|
||||
ecdsa_t *key;
|
||||
FILE *f;
|
||||
char *pubname, *privname;
|
||||
|
||||
fprintf(stderr, "Generating ECDSA keypair:\n");
|
||||
fprintf(stderr, "Generating Ed25519 keypair:\n");
|
||||
|
||||
if(!(key = ecdsa_generate())) {
|
||||
fprintf(stderr, "Error during key generation!\n");
|
||||
|
|
@ -366,8 +378,8 @@ static bool ecdsa_keygen(bool ask) {
|
|||
} else
|
||||
fprintf(stderr, "Done.\n");
|
||||
|
||||
xasprintf(&privname, "%s" SLASH "ecdsa_key.priv", confbase);
|
||||
f = ask_and_open(privname, "private ECDSA key", "a", ask, 0600);
|
||||
xasprintf(&privname, "%s" SLASH "ed25519_key.priv", confbase);
|
||||
f = ask_and_open(privname, "private Ed25519 key", "a", ask, 0600);
|
||||
free(privname);
|
||||
|
||||
if(!f)
|
||||
|
|
@ -385,16 +397,16 @@ static bool ecdsa_keygen(bool ask) {
|
|||
if(name)
|
||||
xasprintf(&pubname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
else
|
||||
xasprintf(&pubname, "%s" SLASH "ecdsa_key.pub", confbase);
|
||||
xasprintf(&pubname, "%s" SLASH "ed25519_key.pub", confbase);
|
||||
|
||||
f = ask_and_open(pubname, "public ECDSA key", "a", ask, 0666);
|
||||
f = ask_and_open(pubname, "public Ed25519 key", "a", ask, 0666);
|
||||
free(pubname);
|
||||
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
char *pubkey = ecdsa_get_base64_public_key(key);
|
||||
fprintf(f, "ECDSAPublicKey = %s\n", pubkey);
|
||||
fprintf(f, "Ed25519PublicKey = %s\n", pubkey);
|
||||
free(pubkey);
|
||||
|
||||
fclose(f);
|
||||
|
|
@ -412,6 +424,15 @@ static bool rsa_keygen(int bits, bool ask) {
|
|||
FILE *f;
|
||||
char *pubname, *privname;
|
||||
|
||||
// Make sure the key size is a multiple of 8 bits.
|
||||
bits &= ~0x7;
|
||||
|
||||
// Force them to be between 1024 and 8192 bits long.
|
||||
if(bits < 1024)
|
||||
bits = 1024;
|
||||
if(bits > 8192)
|
||||
bits = 8192;
|
||||
|
||||
fprintf(stderr, "Generating %d bits keys:\n", bits);
|
||||
|
||||
if(!(key = rsa_generate(bits, 0x10001))) {
|
||||
|
|
@ -471,7 +492,7 @@ bool recvline(int fd, char *line, size_t len) {
|
|||
|
||||
while(!(newline = memchr(buffer, '\n', blen))) {
|
||||
int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
|
||||
if(result == -1 && errno == EINTR)
|
||||
if(result == -1 && sockerrno == EINTR)
|
||||
continue;
|
||||
else if(result <= 0)
|
||||
return false;
|
||||
|
|
@ -497,7 +518,7 @@ bool recvdata(int fd, char *data, size_t len) {
|
|||
|
||||
while(blen < len) {
|
||||
int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
|
||||
if(result == -1 && errno == EINTR)
|
||||
if(result == -1 && sockerrno == EINTR)
|
||||
continue;
|
||||
else if(result <= 0)
|
||||
return false;
|
||||
|
|
@ -528,8 +549,8 @@ bool sendline(int fd, char *format, ...) {
|
|||
blen++;
|
||||
|
||||
while(blen) {
|
||||
int result = send(fd, p, blen, 0);
|
||||
if(result == -1 && errno == EINTR)
|
||||
int result = send(fd, p, blen, MSG_NOSIGNAL);
|
||||
if(result == -1 && sockerrno == EINTR)
|
||||
continue;
|
||||
else if(result <= 0)
|
||||
return false;
|
||||
|
|
@ -709,7 +730,7 @@ bool connect_tincd(bool verbose) {
|
|||
|
||||
if(getaddrinfo(host, port, &hints, &res) || !res) {
|
||||
if(verbose)
|
||||
fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, strerror(errno));
|
||||
fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -740,6 +761,11 @@ bool connect_tincd(bool verbose) {
|
|||
freeaddrinfo(res);
|
||||
#endif
|
||||
|
||||
#ifdef SO_NOSIGPIPE
|
||||
static const int one = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof one);
|
||||
#endif
|
||||
|
||||
char data[4096];
|
||||
int version;
|
||||
|
||||
|
|
@ -790,16 +816,31 @@ static int cmd_start(int argc, char *argv[]) {
|
|||
int nargc = 0;
|
||||
char **nargv = xzalloc((optind + argc) * sizeof *nargv);
|
||||
|
||||
nargv[nargc++] = c;
|
||||
char *arg0 = c;
|
||||
#ifdef HAVE_MINGW
|
||||
/*
|
||||
Windows has no real concept of an "argv array". A command line is just one string.
|
||||
The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention)
|
||||
it uses quotes to handle spaces in arguments.
|
||||
Therefore we need to quote all arguments that might contain spaces. No, execvp() won't do that for us (see MSDN).
|
||||
If we don't do that, then execvp() will run fine but any spaces in the filename contained in arg0 will bleed
|
||||
into the next arguments when the spawned process' CRT parses its command line, resulting in chaos.
|
||||
*/
|
||||
xasprintf(&arg0, "\"%s\"", arg0);
|
||||
#endif
|
||||
nargv[nargc++] = arg0;
|
||||
for(int i = 1; i < optind; i++)
|
||||
nargv[nargc++] = orig_argv[i];
|
||||
for(int i = 1; i < argc; i++)
|
||||
nargv[nargc++] = argv[i];
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
execvp(c, nargv);
|
||||
fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
|
||||
return 1;
|
||||
int status = spawnvp(_P_WAIT, c, nargv);
|
||||
if (status == -1) {
|
||||
fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
return status;
|
||||
#else
|
||||
pid_t pid = fork();
|
||||
if(pid == -1) {
|
||||
|
|
@ -961,11 +1002,14 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
break;
|
||||
|
||||
char node[4096];
|
||||
char id[4096];
|
||||
char from[4096];
|
||||
char to[4096];
|
||||
char subnet[4096];
|
||||
char host[4096];
|
||||
char port[4096];
|
||||
char local_host[4096];
|
||||
char local_port[4096];
|
||||
char via[4096];
|
||||
char nexthop[4096];
|
||||
int cipher, digest, maclength, compression, distance, socket, weight;
|
||||
|
|
@ -976,8 +1020,8 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
|
||||
switch(req) {
|
||||
case REQ_DUMP_NODES: {
|
||||
int n = sscanf(line, "%*d %*d %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
|
||||
if(n != 16) {
|
||||
int n = sscanf(line, "%*d %*d %s %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
|
||||
if(n != 17) {
|
||||
fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1000,14 +1044,14 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
} else {
|
||||
if(only_reachable && !status.reachable)
|
||||
continue;
|
||||
printf("%s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
|
||||
node, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
|
||||
printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
|
||||
node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
|
||||
}
|
||||
} break;
|
||||
|
||||
case REQ_DUMP_EDGES: {
|
||||
int n = sscanf(line, "%*d %*d %s %s %s port %s %x %d", from, to, host, port, &options, &weight);
|
||||
if(n != 6) {
|
||||
int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d", from, to, host, port, local_host, local_port, &options, &weight);
|
||||
if(n != 8) {
|
||||
fprintf(stderr, "Unable to parse edge dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1019,7 +1063,7 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
else if(do_graph == 2)
|
||||
printf(" %s -> %s [w = %f, weight = %f];\n", node1, node2, w, w);
|
||||
} else {
|
||||
printf("%s to %s at %s port %s options %x weight %d\n", from, to, host, port, options, weight);
|
||||
printf("%s to %s at %s port %s local %s port %s options %x weight %d\n", from, to, host, port, local_host, local_port, options, weight);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
@ -1262,7 +1306,7 @@ char *get_my_name(bool verbose) {
|
|||
continue;
|
||||
if(*value) {
|
||||
fclose(f);
|
||||
return strdup(value);
|
||||
return replace_name(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1279,12 +1323,14 @@ const var_t variables[] = {
|
|||
{"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
|
||||
{"BindToInterface", VAR_SERVER},
|
||||
{"Broadcast", VAR_SERVER | VAR_SAFE},
|
||||
{"BroadcastSubnet", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
|
||||
{"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
|
||||
{"DecrementTTL", VAR_SERVER},
|
||||
{"Device", VAR_SERVER},
|
||||
{"DeviceStandby", VAR_SERVER},
|
||||
{"DeviceType", VAR_SERVER},
|
||||
{"DirectOnly", VAR_SERVER},
|
||||
{"ECDSAPrivateKeyFile", VAR_SERVER},
|
||||
{"Ed25519PrivateKeyFile", VAR_SERVER},
|
||||
{"ExperimentalProtocol", VAR_SERVER},
|
||||
{"Forwarding", VAR_SERVER},
|
||||
{"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
|
||||
|
|
@ -1292,6 +1338,7 @@ const var_t variables[] = {
|
|||
{"IffOneQueue", VAR_SERVER},
|
||||
{"Interface", VAR_SERVER},
|
||||
{"KeyExpire", VAR_SERVER},
|
||||
{"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
|
||||
{"LocalDiscovery", VAR_SERVER},
|
||||
{"MACExpire", VAR_SERVER},
|
||||
{"MaxConnectionBurst", VAR_SERVER},
|
||||
|
|
@ -1321,8 +1368,8 @@ const var_t variables[] = {
|
|||
{"ClampMSS", VAR_SERVER | VAR_HOST},
|
||||
{"Compression", VAR_SERVER | VAR_HOST},
|
||||
{"Digest", VAR_SERVER | VAR_HOST},
|
||||
{"ECDSAPublicKey", VAR_HOST},
|
||||
{"ECDSAPublicKeyFile", VAR_SERVER | VAR_HOST},
|
||||
{"Ed25519PublicKey", VAR_HOST},
|
||||
{"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
|
||||
{"IndirectData", VAR_SERVER | VAR_HOST},
|
||||
{"MACLength", VAR_SERVER | VAR_HOST},
|
||||
{"PMTU", VAR_SERVER | VAR_HOST},
|
||||
|
|
@ -1591,9 +1638,12 @@ static int cmd_config(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
if(action < -1) {
|
||||
if(!found)
|
||||
if(found) {
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "No matching configuration variables found.\n");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we wrote everything...
|
||||
|
|
@ -1606,7 +1656,7 @@ static int cmd_config(int argc, char *argv[]) {
|
|||
if(action < 0 && !removed) {
|
||||
remove(tmpfile);
|
||||
fprintf(stderr, "No configuration variables deleted.\n");
|
||||
return *value != 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Replace the configuration file with the new one
|
||||
|
|
@ -1628,18 +1678,6 @@ static int cmd_config(int argc, char *argv[]) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool check_id(const char *name) {
|
||||
if(!name || !*name)
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < strlen(name); i++) {
|
||||
if(!isalnum(name[i]) && name[i] != '_')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool try_bind(int port) {
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo hint = {
|
||||
|
|
@ -1710,8 +1748,7 @@ static int cmd_init(int argc, char *argv[]) {
|
|||
} else if(argc < 2) {
|
||||
if(tty) {
|
||||
char buf[1024];
|
||||
fprintf(stdout, "Enter the Name you want your tinc node to have: ");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Enter the Name you want your tinc node to have: ");
|
||||
if(!fgets(buf, sizeof buf, stdin)) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
|
||||
return 1;
|
||||
|
|
@ -1763,7 +1800,7 @@ static int cmd_init(int argc, char *argv[]) {
|
|||
fprintf(f, "Name = %s\n", name);
|
||||
fclose(f);
|
||||
|
||||
if(!rsa_keygen(2048, false) || !ecdsa_keygen(false))
|
||||
if(!rsa_keygen(2048, false) || !ed25519_keygen(false))
|
||||
return 1;
|
||||
|
||||
check_port(name);
|
||||
|
|
@ -1777,7 +1814,7 @@ static int cmd_init(int argc, char *argv[]) {
|
|||
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
|
||||
fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1795,7 +1832,7 @@ 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) && ecdsa_keygen(true));
|
||||
return !(rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true) && ed25519_keygen(true));
|
||||
}
|
||||
|
||||
static int cmd_generate_rsa_keys(int argc, char *argv[]) {
|
||||
|
|
@ -1810,7 +1847,7 @@ static int cmd_generate_rsa_keys(int argc, char *argv[]) {
|
|||
return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
|
||||
}
|
||||
|
||||
static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
|
||||
static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
|
||||
if(argc > 1) {
|
||||
fprintf(stderr, "Too many arguments!\n");
|
||||
return 1;
|
||||
|
|
@ -1819,7 +1856,7 @@ static int cmd_generate_ecdsa_keys(int argc, char *argv[]) {
|
|||
if(!name)
|
||||
name = get_my_name(false);
|
||||
|
||||
return !ecdsa_keygen(true);
|
||||
return !ed25519_keygen(true);
|
||||
}
|
||||
|
||||
static int cmd_help(int argc, char *argv[]) {
|
||||
|
|
@ -2067,6 +2104,72 @@ static int cmd_exchange_all(int argc, char *argv[]) {
|
|||
return cmd_export_all(argc, argv) ?: cmd_import(argc, argv);
|
||||
}
|
||||
|
||||
static int switch_network(char *name) {
|
||||
if(fd >= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
free(confbase);
|
||||
confbase = NULL;
|
||||
free(pidfilename);
|
||||
pidfilename = NULL;
|
||||
free(logfilename);
|
||||
logfilename = NULL;
|
||||
free(unixsocketname);
|
||||
unixsocketname = NULL;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_network(int argc, char *argv[]) {
|
||||
if(argc > 2) {
|
||||
fprintf(stderr, "Too many arguments!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(argc == 2)
|
||||
return switch_network(argv[1]);
|
||||
|
||||
DIR *dir = opendir(confdir);
|
||||
if(!dir) {
|
||||
fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while((ent = readdir(dir))) {
|
||||
if(*ent->d_name == '.')
|
||||
continue;
|
||||
|
||||
if(!strcmp(ent->d_name, "tinc.conf")) {
|
||||
printf(".\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
char *fname;
|
||||
xasprintf(&fname, "%s/%s/tinc.conf", confdir, ent->d_name);
|
||||
if(!access(fname, R_OK))
|
||||
printf("%s\n", ent->d_name);
|
||||
free(fname);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *command;
|
||||
int (*function)(int argc, char *argv[]);
|
||||
|
|
@ -2094,7 +2197,7 @@ static const struct {
|
|||
{"init", cmd_init},
|
||||
{"generate-keys", cmd_generate_keys},
|
||||
{"generate-rsa-keys", cmd_generate_rsa_keys},
|
||||
{"generate-ecdsa-keys", cmd_generate_ecdsa_keys},
|
||||
{"generate-ed25519-keys", cmd_generate_ed25519_keys},
|
||||
{"help", cmd_help},
|
||||
{"version", cmd_version},
|
||||
{"info", cmd_info},
|
||||
|
|
@ -2106,6 +2209,7 @@ static const struct {
|
|||
{"exchange-all", cmd_exchange_all},
|
||||
{"invite", cmd_invite},
|
||||
{"join", cmd_join},
|
||||
{"network", cmd_network},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
@ -2232,7 +2336,6 @@ static char **completion (const char *text, int start, int end) {
|
|||
#endif
|
||||
|
||||
static int cmd_shell(int argc, char *argv[]) {
|
||||
char *prompt;
|
||||
xasprintf(&prompt, "%s> ", identname);
|
||||
int result = 0;
|
||||
char buf[4096];
|
||||
|
|
@ -2336,6 +2439,7 @@ int main(int argc, char *argv[]) {
|
|||
program_name = argv[0];
|
||||
orig_argv = argv;
|
||||
orig_argc = argc;
|
||||
tty = isatty(0) && isatty(1);
|
||||
|
||||
if(!parse_options(argc, argv))
|
||||
return 1;
|
||||
|
|
@ -2366,8 +2470,6 @@ int main(int argc, char *argv[]) {
|
|||
srand(time(NULL));
|
||||
crypto_init();
|
||||
|
||||
tty = isatty(0) && isatty(1);
|
||||
|
||||
if(optind >= argc)
|
||||
return cmd_shell(argc, argv);
|
||||
|
||||
|
|
|
|||
44
src/tincd.c
44
src/tincd.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
tincd.c -- the main file for tincd
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2014 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>
|
||||
|
|
@ -49,6 +49,7 @@
|
|||
#include "control.h"
|
||||
#include "crypto.h"
|
||||
#include "device.h"
|
||||
#include "event.h"
|
||||
#include "logger.h"
|
||||
#include "names.h"
|
||||
#include "net.h"
|
||||
|
|
@ -57,6 +58,7 @@
|
|||
#include "protocol.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
#include "version.h"
|
||||
|
||||
/* If nonzero, display usage information and exit. */
|
||||
static bool show_help = false;
|
||||
|
|
@ -106,7 +108,6 @@ static struct option const long_options[] = {
|
|||
|
||||
#ifdef HAVE_MINGW
|
||||
static struct WSAData wsa_state;
|
||||
CRITICAL_SECTION mutex;
|
||||
int main2(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
|
|
@ -303,6 +304,17 @@ static bool drop_privs(void) {
|
|||
|
||||
#ifdef HAVE_MINGW
|
||||
# define setpriority(level) !SetPriorityClass(GetCurrentProcess(), (level))
|
||||
|
||||
static void stop_handler(void *data, int flags) {
|
||||
event_exit();
|
||||
}
|
||||
|
||||
static BOOL WINAPI console_ctrl_handler(DWORD type) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got console shutdown request");
|
||||
if (WSASetEvent(stop_io.event) == FALSE)
|
||||
abort();
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
# define NORMAL_PRIORITY_CLASS 0
|
||||
# define BELOW_NORMAL_PRIORITY_CLASS 10
|
||||
|
|
@ -320,8 +332,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
if(show_version) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
VERSION, __DATE__, __TIME__, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2013 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2014 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"
|
||||
|
|
@ -371,15 +383,24 @@ int main(int argc, char **argv) {
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
if(!do_detach || !init_service())
|
||||
return main2(argc, argv);
|
||||
else
|
||||
return 1;
|
||||
io_add_event(&stop_io, stop_handler, NULL, WSACreateEvent());
|
||||
if (stop_io.event == FALSE)
|
||||
abort();
|
||||
|
||||
int result;
|
||||
if(!do_detach || !init_service()) {
|
||||
SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
|
||||
result = main2(argc, argv);
|
||||
} else
|
||||
result = 1;
|
||||
|
||||
if (WSACloseEvent(stop_io.event) == FALSE)
|
||||
abort();
|
||||
io_del(&stop_io);
|
||||
return result;
|
||||
}
|
||||
|
||||
int main2(int argc, char **argv) {
|
||||
InitializeCriticalSection(&mutex);
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
char *priority = NULL;
|
||||
|
||||
|
|
@ -440,9 +461,6 @@ int main2(int argc, char **argv) {
|
|||
|
||||
/* Shutdown properly. */
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS)
|
||||
devops.dump_stats();
|
||||
|
||||
end:
|
||||
close_network_connections();
|
||||
|
||||
|
|
|
|||
25
src/top.c
25
src/top.c
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#ifdef HAVE_CURSES
|
||||
|
||||
#undef KEY_EVENT /* There are conflicting declarations for KEY_EVENT in Windows wincon.h and curses.h. */
|
||||
#include <curses.h>
|
||||
|
||||
#include "control_common.h"
|
||||
|
|
@ -66,8 +67,10 @@ static float bscale = 1;
|
|||
static const char *punit = "pkts";
|
||||
static float pscale = 1;
|
||||
|
||||
static void update(int fd) {
|
||||
sendline(fd, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
|
||||
static bool update(int fd) {
|
||||
if(!sendline(fd, "%d %d", CONTROL, REQ_DUMP_TRAFFIC))
|
||||
return false;
|
||||
|
||||
gettimeofday(&cur, NULL);
|
||||
|
||||
timersub(&cur, &prev, &diff);
|
||||
|
|
@ -90,13 +93,10 @@ static void update(int fd) {
|
|||
int n = sscanf(line, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, &code, &req, name, &in_packets, &in_bytes, &out_packets, &out_bytes);
|
||||
|
||||
if(n == 2)
|
||||
break;
|
||||
return true;
|
||||
|
||||
if(n != 7) {
|
||||
endwin();
|
||||
fprintf(stderr, "Error receiving traffic information\n");
|
||||
exit(1);
|
||||
}
|
||||
if(n != 7)
|
||||
return false;
|
||||
|
||||
nodestats_t *found = NULL;
|
||||
|
||||
|
|
@ -133,6 +133,8 @@ static void update(int fd) {
|
|||
found->out_packets = out_packets;
|
||||
found->out_bytes = out_bytes;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cmpfloat(float a, float b) {
|
||||
|
|
@ -213,7 +215,8 @@ static void redraw(void) {
|
|||
for(int i = 0; i < n; i++)
|
||||
sorted[i]->i = i;
|
||||
|
||||
qsort(sorted, n, sizeof *sorted, sortfunc);
|
||||
if(sorted)
|
||||
qsort(sorted, n, sizeof *sorted, sortfunc);
|
||||
|
||||
for(int i = 0, row = 3; i < n; i++, row++) {
|
||||
nodestats_t *node = sorted[i];
|
||||
|
|
@ -245,7 +248,9 @@ void top(int fd) {
|
|||
bool running = true;
|
||||
|
||||
while(running) {
|
||||
update(fd);
|
||||
if(!update(fd))
|
||||
break;
|
||||
|
||||
redraw();
|
||||
|
||||
switch(getch()) {
|
||||
|
|
|
|||
|
|
@ -38,9 +38,6 @@ static int write_fd = -1;
|
|||
static int state = 0;
|
||||
static char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
enum request_type { REQ_NEW_CONTROL };
|
||||
|
||||
static struct request {
|
||||
|
|
@ -159,22 +156,29 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
void close_device(void) {
|
||||
if(listen_fd >= 0)
|
||||
close(listen_fd);
|
||||
if(listen_fd >= 0) {
|
||||
close(listen_fd); listen_fd = -1;
|
||||
}
|
||||
|
||||
if(request_fd >= 0)
|
||||
close(request_fd);
|
||||
if(request_fd >= 0) {
|
||||
close(request_fd); request_fd = -1;
|
||||
}
|
||||
|
||||
if(data_fd >= 0)
|
||||
close(data_fd);
|
||||
if(data_fd >= 0) {
|
||||
close(data_fd); data_fd = -1;
|
||||
}
|
||||
|
||||
if(write_fd >= 0)
|
||||
close(write_fd);
|
||||
if(write_fd >= 0) {
|
||||
close(write_fd); write_fd = -1;
|
||||
}
|
||||
|
||||
unlink(device);
|
||||
|
||||
free(device);
|
||||
if(iface) free(iface);
|
||||
free(device); device = NULL;
|
||||
if(iface) {
|
||||
free(iface); iface = NULL;
|
||||
}
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -240,7 +244,7 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
case 2: {
|
||||
if((inlen = read(data_fd, packet->data, MTU)) <= 0) {
|
||||
if((inlen = read(data_fd, DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
event_exit();
|
||||
|
|
@ -249,8 +253,6 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
packet->len = inlen;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
|
|
@ -273,7 +275,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(write(write_fd, packet->data, packet->len) < 0) {
|
||||
if(write(write_fd, DATA(packet), packet->len) < 0) {
|
||||
if(errno != EINTR && errno != EAGAIN) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||
event_exit();
|
||||
|
|
@ -282,21 +284,12 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t uml_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
75
src/utils.c
75
src/utils.c
|
|
@ -18,10 +18,10 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "../src/logger.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static const char hexadecimals[] = "0123456789ABCDEF";
|
||||
static const char base64_original[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
|
@ -52,14 +52,16 @@ static int charhex2bin(char c) {
|
|||
return toupper(c) - 'A' + 10;
|
||||
}
|
||||
|
||||
int hex2bin(const char *src, char *dst, int length) {
|
||||
int hex2bin(const char *src, void *vdst, int length) {
|
||||
char *dst = vdst;
|
||||
int i;
|
||||
for(i = 0; i < length && isxdigit(src[i * 2]) && isxdigit(src[i * 2 + 1]); i++)
|
||||
dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]);
|
||||
return i;
|
||||
}
|
||||
|
||||
int bin2hex(const char *src, char *dst, int length) {
|
||||
int bin2hex(const void *vsrc, char *dst, int length) {
|
||||
const char *src = vsrc;
|
||||
for(int i = length - 1; i >= 0; i--) {
|
||||
dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
|
||||
dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4];
|
||||
|
|
@ -68,12 +70,12 @@ int bin2hex(const char *src, char *dst, int length) {
|
|||
return length * 2;
|
||||
}
|
||||
|
||||
int b64decode(const char *src, char *dst, int length) {
|
||||
int b64decode(const char *src, void *dst, int length) {
|
||||
int i;
|
||||
uint32_t triplet = 0;
|
||||
unsigned char *udst = (unsigned char *)dst;
|
||||
|
||||
for(i = 0; i < length / 3 * 4 && src[i]; i++) {
|
||||
for(i = 0; i < length && src[i]; i++) {
|
||||
triplet |= base64_decode[src[i] & 0xff] << (6 * (i & 3));
|
||||
if((i & 3) == 3) {
|
||||
if(triplet & 0xff000000U)
|
||||
|
|
@ -99,7 +101,7 @@ int b64decode(const char *src, char *dst, int length) {
|
|||
}
|
||||
}
|
||||
|
||||
static int b64encode_internal(const char *src, char *dst, int length, const char *alphabet) {
|
||||
static int b64encode_internal(const void *src, char *dst, int length, const char *alphabet) {
|
||||
uint32_t triplet;
|
||||
const unsigned char *usrc = (unsigned char *)src;
|
||||
int si = length / 3 * 3;
|
||||
|
|
@ -112,14 +114,14 @@ static int b64encode_internal(const char *src, char *dst, int length, const char
|
|||
dst[di + 1] = alphabet[triplet & 63]; triplet >>= 6;
|
||||
dst[di + 2] = alphabet[triplet];
|
||||
dst[di + 3] = 0;
|
||||
length = di + 2;
|
||||
length = di + 3;
|
||||
break;
|
||||
case 1:
|
||||
triplet = usrc[si];
|
||||
dst[di] = alphabet[triplet & 63]; triplet >>= 6;
|
||||
dst[di + 1] = alphabet[triplet];
|
||||
dst[di + 2] = 0;
|
||||
length = di + 1;
|
||||
length = di + 2;
|
||||
break;
|
||||
default:
|
||||
dst[di] = 0;
|
||||
|
|
@ -140,11 +142,11 @@ static int b64encode_internal(const char *src, char *dst, int length, const char
|
|||
return length;
|
||||
}
|
||||
|
||||
int b64encode(const char *src, char *dst, int length) {
|
||||
int b64encode(const void *src, char *dst, int length) {
|
||||
return b64encode_internal(src, dst, length, base64_original);
|
||||
}
|
||||
|
||||
int b64encode_urlsafe(const char *src, char *dst, int length) {
|
||||
int b64encode_urlsafe(const void *src, char *dst, int length) {
|
||||
return b64encode_internal(src, dst, length, base64_urlsafe);
|
||||
}
|
||||
|
||||
|
|
@ -177,3 +179,54 @@ unsigned int bitfield_to_int(const void *bitfield, size_t size) {
|
|||
memcpy(&value, bitfield, size);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool check_id(const char *id) {
|
||||
if(!id || !*id)
|
||||
return false;
|
||||
|
||||
for(; *id; id++)
|
||||
if(!isalnum(*id) && *id != '_')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Windows doesn't define HOST_NAME_MAX. */
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 255
|
||||
#endif
|
||||
|
||||
char *replace_name(const char *name) {
|
||||
char *ret_name;
|
||||
|
||||
if (name[0] == '$') {
|
||||
char *envname = getenv(name + 1);
|
||||
char hostname[HOST_NAME_MAX+1];
|
||||
if (!envname) {
|
||||
if (strcmp(name + 1, "HOST")) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
|
||||
return NULL;
|
||||
}
|
||||
if (gethostname(hostname, sizeof hostname) || !*hostname) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", sockstrerror(sockerrno));
|
||||
return NULL;
|
||||
}
|
||||
hostname[HOST_NAME_MAX] = 0;
|
||||
envname = hostname;
|
||||
}
|
||||
ret_name = xstrdup(envname);
|
||||
for (char *c = ret_name; *c; c++)
|
||||
if (!isalnum(*c))
|
||||
*c = '_';
|
||||
} else {
|
||||
ret_name = xstrdup(name);
|
||||
}
|
||||
|
||||
if (!check_id(ret_name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
|
||||
free(ret_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret_name;
|
||||
}
|
||||
|
|
|
|||
15
src/utils.h
15
src/utils.h
|
|
@ -21,12 +21,12 @@
|
|||
#ifndef __TINC_UTILS_H__
|
||||
#define __TINC_UTILS_H__
|
||||
|
||||
extern int hex2bin(const char *src, char *dst, int length);
|
||||
extern int bin2hex(const char *src, char *dst, int length);
|
||||
extern int hex2bin(const char *src, void *dst, int length);
|
||||
extern int bin2hex(const void *src, char *dst, int length);
|
||||
|
||||
extern int b64encode(const char *src, char *dst, int length);
|
||||
extern int b64encode_urlsafe(const char *src, char *dst, int length);
|
||||
extern int b64decode(const char *src, char *dst, int length);
|
||||
extern int b64encode(const void *src, char *dst, int length);
|
||||
extern int b64encode_urlsafe(const void *src, char *dst, int length);
|
||||
extern int b64decode(const char *src, void *dst, int length);
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
extern const char *winerror(int);
|
||||
|
|
@ -37,6 +37,7 @@ extern const char *winerror(int);
|
|||
#define sockmsgsize(x) ((x) == WSAEMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == WSAEINPROGRESS || (x) == WSAEWOULDBLOCK)
|
||||
#define sockinuse(x) ((x) == WSAEADDRINUSE)
|
||||
#define socknotconn(x) ((x) == WSAENOTCONN)
|
||||
#else
|
||||
#define sockerrno errno
|
||||
#define sockstrerror(x) strerror(x)
|
||||
|
|
@ -44,8 +45,12 @@ extern const char *winerror(int);
|
|||
#define sockmsgsize(x) ((x) == EMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == EINPROGRESS)
|
||||
#define sockinuse(x) ((x) == EADDRINUSE)
|
||||
#define socknotconn(x) ((x) == ENOTCONN)
|
||||
#endif
|
||||
|
||||
extern unsigned int bitfield_to_int(const void *bitfield, size_t size);
|
||||
|
||||
extern bool check_id(const char *);
|
||||
char *replace_name(const char *name);
|
||||
|
||||
#endif /* __TINC_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ static int port = 0;
|
|||
static char *group = NULL;
|
||||
static char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
libvdeplug_dynopen(plug);
|
||||
|
||||
|
|
@ -85,19 +82,22 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
static void close_device(void) {
|
||||
if(conn)
|
||||
plug.vde_close(conn);
|
||||
if(conn) {
|
||||
plug.vde_close(conn); conn = NULL;
|
||||
}
|
||||
|
||||
if(plug.dl_handle)
|
||||
libvdeplug_dynclose(plug);
|
||||
|
||||
free(device);
|
||||
free(device); device = NULL;
|
||||
|
||||
free(iface);
|
||||
free(iface); iface = NULL;
|
||||
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin = (ssize_t)plug.vde_recv(conn, packet->data, MTU, 0);
|
||||
int lenin = (ssize_t)plug.vde_recv(conn, DATA(packet), MTU, 0);
|
||||
if(lenin <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
||||
event_exit();
|
||||
|
|
@ -105,14 +105,14 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
packet->len = lenin;
|
||||
device_total_in += packet->len;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
if((ssize_t)plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
|
||||
if((ssize_t)plug.vde_send(conn, DATA(packet), packet->len, 0) < 0) {
|
||||
if(errno != EINTR && errno != EAGAIN) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||
event_exit();
|
||||
|
|
@ -121,21 +121,12 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t vde_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
24
src/version.c
Normal file
24
src/version.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
version.c -- version information
|
||||
Copyright (C) 2014 Etienne Dechamps <etienne@edechamps.fr>
|
||||
|
||||
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 "version.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__;
|
||||
26
src/version.h
Normal file
26
src/version.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
version.h -- header for version.c
|
||||
Copyright (C) 2014 Etienne Dechamps <etienne@edechamps.fr>
|
||||
|
||||
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_VERSION_H__
|
||||
#define __TINC_VERSION_H__
|
||||
|
||||
extern const char* const BUILD_DATE;
|
||||
extern const char* const BUILD_TIME;
|
||||
|
||||
#endif /* __TINC_VERSION_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue