├── .ci ├── package │ ├── deb │ │ ├── debian │ │ │ ├── compat │ │ │ ├── rules │ │ │ ├── tinc.default │ │ │ ├── doc-base.tinc │ │ │ ├── preinst │ │ │ ├── control │ │ │ └── copyright │ │ └── build.sh │ ├── win │ │ ├── build.sh │ │ └── installer.nsi │ ├── rpm │ │ ├── build.sh │ │ └── tinc.spec │ └── build.sh ├── cross │ ├── linux │ │ ├── mipsel │ │ └── armhf │ ├── msvc │ │ └── arm64 │ └── windows │ │ └── amd64 ├── sanitizers │ ├── ignore.txt │ ├── suppress.txt │ └── run.sh ├── README.md ├── bsd │ └── run.sh ├── build.sh ├── windows │ ├── test.cmd │ └── build.cmd ├── test │ ├── prepare.sh │ └── run.sh ├── warn │ └── run.sh ├── conf.sh └── muon │ └── run.sh ├── src ├── version_git.h.in ├── legacy.h ├── ed25519 │ ├── .clang-tidy │ ├── sc.h │ ├── keypair.c │ ├── meson.build │ ├── sha512.h │ ├── sign.c │ ├── ed25519.h │ ├── fe.h │ ├── verify.c │ ├── ecdh.c │ ├── key_exchange.c │ ├── ge.h │ └── ecdsagen.c ├── chacha-poly1305 │ ├── .clang-tidy │ ├── meson.build │ ├── poly1305.h │ ├── chacha.h │ └── chacha-poly1305.h ├── openssl │ ├── log.h │ ├── log.c │ ├── meson.build │ ├── cipher.h │ ├── crypto.c │ └── digest.h ├── solaris │ └── meson.build ├── nolegacy │ ├── meson.build │ └── crypto.c ├── bsd │ ├── openbsd │ │ ├── meson.build │ │ ├── sandbox.c │ │ ├── tincctl.c │ │ └── sandbox.h │ ├── meson.build │ └── darwin │ │ ├── meson.build │ │ └── tunemu.h ├── console.h ├── include │ └── meson.build ├── gcrypt │ ├── crypto.c │ ├── asn1.h │ ├── meson.build │ ├── pem.h │ ├── digest.h │ ├── cipher.h │ └── rsa.h ├── random.h ├── conf_net.h ├── pidfile.h ├── sandbox.c ├── watchdog.h ├── windows │ ├── meson.build │ └── random.c ├── linux │ ├── meson.build │ └── watchdog.c ├── buffer.h ├── compression.h ├── console.c ├── conf_net.c ├── fs.h ├── keys.h ├── pidfile.c ├── top.h ├── fsck.h ├── autoconnect.h ├── upnp.h ├── graph.h ├── info.h ├── control.h ├── version.h ├── prf.h ├── sandbox.h ├── random.c ├── invitation.h ├── rsagen.h ├── cipher.c ├── digest.c ├── ecdsagen.h ├── version.c ├── process.h ├── system.h ├── ifconfig.h ├── ecdh.h ├── names.h ├── crypto.h ├── control_common.h ├── meta.h ├── script.h ├── device.h ├── rsa.h ├── route.h ├── dummy_device.c ├── ecdsa.h ├── address_cache.h ├── xoshiro.c ├── tincctl.h ├── netutl.h ├── edge.h ├── digest.h ├── signal.c ├── cipher.h └── event.h ├── doc ├── sample-config │ ├── rsa_key.priv │ ├── tinc-down │ ├── hosts │ │ ├── alpha │ │ └── beta │ ├── tinc-up │ └── tinc.conf ├── tincinclude.texi.in ├── meson.build ├── tinc-gui.8.in └── CONNECTIVITY ├── test ├── meson.build ├── integration │ ├── testlib │ │ ├── template │ │ │ ├── script.cmd.tpl │ │ │ ├── netns.py.tpl │ │ │ └── script.py.tpl │ │ ├── __init__.py │ │ ├── feature.py │ │ ├── const.py │ │ ├── log.py │ │ ├── event.py │ │ ├── test.py │ │ ├── template.py │ │ ├── path.py │ │ └── cmd.py │ ├── executables.py │ ├── net.py │ ├── basic.py │ ├── algorithms.py │ ├── import_export.py │ ├── device_raw_socket.py │ ├── ns_ping.py │ ├── meson.build │ ├── splice.py │ ├── cmd_net.py │ └── legacy_protocol.py └── unit │ ├── unittest.h │ ├── test_memzero_null.c │ ├── test_random_noinit.c │ ├── test_protocol.c │ ├── test_dropin.c │ ├── test_net.c │ ├── test_xalloc.c │ ├── test_random.c │ ├── test_utils.c │ └── test_netutl.c ├── bash_completion.d └── meson.build ├── .astylerc ├── .pylintrc ├── .builds ├── openbsd.yml ├── netbsd.yml └── freebsd.yml ├── subprojects ├── lz4.wrap ├── zlib.wrap ├── lzo2.wrap └── openssl.wrap ├── .clang-tidy ├── systemd ├── tinc@.service.in ├── tinc.service.in └── meson.build ├── version.py ├── COPYING.README ├── .gitignore ├── AUTHORS ├── SECURITY.md ├── lint.py ├── README.md └── meson_options.txt /.ci/package/deb/debian/compat: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /src/version_git.h.in: -------------------------------------------------------------------------------- 1 | #define GIT_DESCRIPTION "@VCS_TAG@" 2 | 3 | -------------------------------------------------------------------------------- /doc/sample-config/rsa_key.priv: -------------------------------------------------------------------------------- 1 | # Generate this file with `tincd -n example -K` 2 | -------------------------------------------------------------------------------- /test/meson.build: -------------------------------------------------------------------------------- 1 | if python.found() 2 | subdir('integration') 3 | endif 4 | 5 | subdir('unit') 6 | 7 | -------------------------------------------------------------------------------- /.ci/cross/linux/mipsel: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'mipsel-linux-gnu-gcc' 3 | pkgconfig = 'mipsel-linux-gnu-pkg-config' 4 | 5 | -------------------------------------------------------------------------------- /doc/sample-config/tinc-down: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file closes down the tap device. 3 | 4 | ifconfig $INTERFACE down 5 | -------------------------------------------------------------------------------- /test/integration/testlib/template/script.cmd.tpl: -------------------------------------------------------------------------------- 1 | @echo off 2 | $VARIABLES 3 | "$PYTHON_PATH" $PYTHON_CMD "$SCRIPT_PATH" 4 | -------------------------------------------------------------------------------- /.ci/cross/linux/armhf: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'arm-linux-gnueabihf-gcc' 3 | pkgconfig = 'arm-linux-gnueabihf-pkg-config' 4 | 5 | -------------------------------------------------------------------------------- /.ci/sanitizers/ignore.txt: -------------------------------------------------------------------------------- 1 | # meson 2 | src:../src/ed25519/* 3 | src:../src/chacha-poly1305/* 4 | src:../src/xoshiro.c 5 | 6 | -------------------------------------------------------------------------------- /src/legacy.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_LEGACY_H 2 | #define TINC_LEGACY_H 3 | 4 | typedef int nid_t; 5 | 6 | #endif // TINC_LEGACY_H 7 | -------------------------------------------------------------------------------- /src/ed25519/.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*,misc-definitions-in-headers' 2 | CheckOptions: 3 | - { key: HeaderFileExtensions, value: "dummy" } 4 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | %: 4 | dh $@ --buildsystem=meson 5 | 6 | override_dh_auto_test: 7 | # Disable tests. 8 | -------------------------------------------------------------------------------- /src/chacha-poly1305/.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*,misc-definitions-in-headers' 2 | CheckOptions: 3 | - { key: HeaderFileExtensions, value: "dummy" } 4 | -------------------------------------------------------------------------------- /src/openssl/log.h: -------------------------------------------------------------------------------- 1 | #ifndef OPENSSL_LOG_H 2 | #define OPENSSL_LOG_H 3 | 4 | extern void openssl_err(const char *msg); 5 | 6 | #endif // OPENSSL_LOG_H 7 | -------------------------------------------------------------------------------- /src/solaris/meson.build: -------------------------------------------------------------------------------- 1 | src_tincd += [ 2 | files('device.c'), 3 | src_event_select, 4 | ] 5 | 6 | deps_common += cc.find_library('libsocket') 7 | 8 | -------------------------------------------------------------------------------- /.ci/sanitizers/suppress.txt: -------------------------------------------------------------------------------- 1 | # known leak from one-time allocation 2 | # upstream refuses to fix such things: https://dev.gnupg.org/T4499 3 | leak:libgcrypt.so 4 | 5 | -------------------------------------------------------------------------------- /bash_completion.d/meson.build: -------------------------------------------------------------------------------- 1 | dir_compl = dir_data / 'bash-completion' / 'completions' 2 | 3 | install_data( 4 | 'tinc', 5 | install_dir: dir_compl, 6 | ) 7 | 8 | -------------------------------------------------------------------------------- /doc/tincinclude.texi.in: -------------------------------------------------------------------------------- 1 | @set VERSION @VERSION@ 2 | @set PACKAGE @PACKAGE@ 3 | @set sysconfdir @sysconfdir@ 4 | @set localstatedir @localstatedir@ 5 | @set runstatedir @runstatedir@ 6 | -------------------------------------------------------------------------------- /.ci/README.md: -------------------------------------------------------------------------------- 1 | # Continuous Integration 2 | 3 | This directory contains scripts and other files used by the continuous 4 | integration system. 5 | 6 | You probably should not run them manually. 7 | -------------------------------------------------------------------------------- /src/nolegacy/meson.build: -------------------------------------------------------------------------------- 1 | src_lib_crypto = files( 2 | 'crypto.c', 3 | 'prf.c', 4 | ) 5 | 6 | dep_crypto = dependency('', required: false) 7 | 8 | cdata.set('DISABLE_LEGACY', 1) 9 | 10 | -------------------------------------------------------------------------------- /test/integration/testlib/__init__.py: -------------------------------------------------------------------------------- 1 | """Testing library with a few helper classes and functions for use in tinc integration tests.""" 2 | 3 | import sys 4 | 5 | assert sys.version_info >= (3, 6) 6 | -------------------------------------------------------------------------------- /.ci/bsd/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | flavor=$1 6 | 7 | cd tinc 8 | 9 | meson setup "$flavor" -D crypto="$flavor" -D miniupnpc=auto 10 | 11 | meson test -C "$flavor" --verbose 12 | -------------------------------------------------------------------------------- /.ci/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | dir="$1" 6 | shift 7 | 8 | flags=$(./.ci/conf.sh "$@") 9 | 10 | # shellcheck disable=SC2086 11 | meson setup "$dir" $flags 12 | 13 | ninja -C "$dir" 14 | -------------------------------------------------------------------------------- /.ci/cross/msvc/arm64: -------------------------------------------------------------------------------- 1 | [host_machine] 2 | system = 'windows' 3 | cpu_family = 'aarch64' 4 | cpu = 'armv8' 5 | endian = 'little' 6 | 7 | [binaries] 8 | c = 'cl' 9 | cpp = 'cl' 10 | ar = 'lib' 11 | windres = 'rc' 12 | -------------------------------------------------------------------------------- /src/bsd/openbsd/meson.build: -------------------------------------------------------------------------------- 1 | if not opt_sandbox.disabled() 2 | src_lib_common += files('sandbox.c') 3 | src_tinc += files('tincctl.c') 4 | src_tincd += files('tincd.c') 5 | cdata.set('HAVE_SANDBOX', 1) 6 | endif 7 | -------------------------------------------------------------------------------- /.ci/package/win/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | curl -o wintap.exe -L 'https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe' 6 | 7 | makensis .ci/package/win/installer.nsi 8 | -------------------------------------------------------------------------------- /src/console.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_CONSOLE_H 2 | #define TINC_CONSOLE_H 3 | 4 | #include "system.h" 5 | 6 | // true if stderr supports ANSI escape sequences. 7 | extern bool use_ansi_escapes(FILE *out); 8 | 9 | #endif // TINC_CONSOLE_H 10 | -------------------------------------------------------------------------------- /src/include/meson.build: -------------------------------------------------------------------------------- 1 | configure_file(output: 'config.h', configuration: cdata) 2 | 3 | src_lib_common += vcs_tag( 4 | command: [python_path, src_root / 'version.py'], 5 | input: '../version_git.h.in', 6 | output: 'version_git.h', 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /src/gcrypt/crypto.c: -------------------------------------------------------------------------------- 1 | #include "../system.h" 2 | 3 | #include 4 | 5 | #include "../crypto.h" 6 | 7 | void crypto_init(void) { 8 | gcry_control(GCRYCTL_INIT_SECMEM, 32 * 1024, 0); 9 | gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); 10 | } 11 | -------------------------------------------------------------------------------- /src/random.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_RANDOM_H 2 | #define TINC_RANDOM_H 3 | 4 | #include "system.h" 5 | 6 | extern void random_init(void); 7 | extern void random_exit(void); 8 | extern void randomize(void *vout, size_t outlen); 9 | 10 | #endif // TINC_RANDOM_H 11 | -------------------------------------------------------------------------------- /src/gcrypt/asn1.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GCRYPT_ASN1_H 2 | #define TINC_GCRYPT_ASN1_H 3 | 4 | // https://luca.ntop.org/Teaching/Appunti/asn1.html 5 | typedef enum { 6 | TAG_INTEGER = 2, 7 | TAG_SEQUENCE = 16, 8 | } asn1_tag_t; 9 | 10 | #endif // TINC_GCRYPT_ASN1_H 11 | -------------------------------------------------------------------------------- /src/conf_net.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_NET_CONF_H 2 | #define TINC_NET_CONF_H 3 | 4 | #include "system.h" 5 | #include "conf.h" 6 | #include "subnet.h" 7 | 8 | extern bool get_config_subnet(const config_t *config, struct subnet_t **result); 9 | 10 | #endif // TINC_NET_CONF_H 11 | -------------------------------------------------------------------------------- /test/unit/unittest.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_UNITTEST_H 2 | #define TINC_UNITTEST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../src/system.h" 10 | 11 | #endif // TINC_UNITTEST_H 12 | -------------------------------------------------------------------------------- /src/openssl/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "log.h" 3 | #include "../logger.h" 4 | 5 | void openssl_err(const char *msg) { 6 | const char *err = ERR_error_string(ERR_peek_last_error(), NULL); 7 | logger(DEBUG_ALWAYS, LOG_ERR, "OpenSSL error: unable to %s: %s", msg, err); 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/test_memzero_null.c: -------------------------------------------------------------------------------- 1 | // Test that memzero() with NULL pointer crashes the program 2 | 3 | #include "config.h" 4 | #undef HAVE_ATTR_NONNULL 5 | 6 | #include "unittest.h" 7 | #include "../../src/xalloc.h" 8 | 9 | int main(void) { 10 | memzero(NULL, 1); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /.astylerc: -------------------------------------------------------------------------------- 1 | --indent=tab=8 2 | --convert-tabs 3 | --exclude=subprojects 4 | --exclude=build 5 | --ignore-exclude-errors 6 | --add-braces 7 | --break-blocks 8 | --style=attach 9 | --unpad-paren 10 | --pad-oper 11 | --pad-return-type 12 | --align-pointer=name 13 | --indent-preproc-define 14 | --formatted 15 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | jobs=0 3 | persistent=yes 4 | py-version=3.6 5 | recursive=yes 6 | ignore=build 7 | 8 | [BASIC] 9 | good-names=foo, bar, baz, f, k, ex 10 | 11 | [REPORTS] 12 | output-format=colorized 13 | 14 | [DESIGN] 15 | min-public-methods=0 16 | 17 | [SIMILARITIES] 18 | min-similarity-lines=10 19 | 20 | -------------------------------------------------------------------------------- /test/integration/testlib/feature.py: -------------------------------------------------------------------------------- 1 | """Some hardcoded constants.""" 2 | 3 | from .proc import Feature, Tinc 4 | 5 | # True if tincd has sandbox support 6 | HAVE_SANDBOX = Feature.SANDBOX in Tinc().features 7 | 8 | # Maximum supported sandbox level 9 | SANDBOX_LEVEL = "high" if Feature.SANDBOX in Tinc().features else "off" 10 | -------------------------------------------------------------------------------- /src/ed25519/sc.h: -------------------------------------------------------------------------------- 1 | #ifndef SC_H 2 | #define SC_H 3 | 4 | /* 5 | The set of scalars is \Z/l 6 | where l = 2^252 + 27742317777372353535851937790883648493. 7 | */ 8 | 9 | void sc_reduce(unsigned char *s); 10 | void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/tinc.default: -------------------------------------------------------------------------------- 1 | # Extra options to be passed to tincd. 2 | # EXTRA="-d" 3 | 4 | # Limits to be configured for the tincd process. Please read your shell 5 | # (pointed by /bin/sh) documentation for ulimit. You probably want to raise the 6 | # max locked memory value if using both --mlock and --user flags. 7 | # LIMITS="-l 1024" 8 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/doc-base.tinc: -------------------------------------------------------------------------------- 1 | Document: tinc 2 | Title: tinc Manual 3 | Author: Ivo Timmermans, Guus Sliepen 4 | Abstract: This manual describes how to set up a Virtual Private 5 | Network with tinc. 6 | Section: System/Security 7 | 8 | Format: HTML 9 | Files: /usr/share/doc/tinc/tinc.html/* 10 | Index: /usr/share/doc/tinc/tinc.html/index.html 11 | -------------------------------------------------------------------------------- /src/chacha-poly1305/meson.build: -------------------------------------------------------------------------------- 1 | src_chacha_poly = files( 2 | 'chacha-poly1305.c', 3 | 'chacha.c', 4 | 'poly1305.c', 5 | ) 6 | 7 | lib_chacha_poly = static_library( 8 | 'chacha_poly', 9 | sources: src_chacha_poly, 10 | implicit_include_directories: false, 11 | include_directories: inc_conf, 12 | build_by_default: false, 13 | ) 14 | 15 | -------------------------------------------------------------------------------- /.ci/windows/test.cmd: -------------------------------------------------------------------------------- 1 | set builddir=%1 2 | 3 | REM Windows jobs on GitHub CI sometimes show surprisingly poor performance 4 | REM (building tinc with default flags can take from 3 to upwards of 20+ 5 | REM minutes, depending on which machine you happened to land on), so timeout 6 | REM is set a bit higher here. 7 | 8 | meson test -C %builddir% --timeout-multiplier 2 --verbose || exit 1 9 | -------------------------------------------------------------------------------- /.ci/windows/build.cmd: -------------------------------------------------------------------------------- 1 | set crypto=%1 2 | set builddir=%crypto% 3 | set args= 4 | set crossfile=.ci\cross\msvc\%HOST_ARCH% 5 | 6 | if exist %crossfile% ( 7 | set args=--cross-file %crossfile% 8 | ) 9 | 10 | echo configure build directory 11 | meson setup %builddir% -Dbuildtype=release -Dcrypto=%crypto% %args% || exit 1 12 | 13 | echo build project 14 | meson compile -C %builddir% || exit 1 15 | -------------------------------------------------------------------------------- /test/unit/test_random_noinit.c: -------------------------------------------------------------------------------- 1 | // Test that randomize() kills the process when called without initialization 2 | 3 | #include "unittest.h" 4 | 5 | #ifdef HAVE_GETENTROPY 6 | int main(void) { 7 | return 1; 8 | } 9 | #else 10 | #include "../../src/random.h" 11 | 12 | int main(void) { 13 | uint8_t buf[16]; 14 | randomize(buf, sizeof(buf)); 15 | return 0; 16 | } 17 | #endif // HAVE_GETENTROPY 18 | -------------------------------------------------------------------------------- /src/pidfile.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_PIDFILE_H 2 | #define TINC_PIDFILE_H 3 | 4 | #include "system.h" 5 | 6 | typedef struct pidfile_t { 7 | int pid; 8 | char host[129]; 9 | char port[129]; 10 | char cookie[65]; 11 | } pidfile_t; 12 | 13 | extern pidfile_t *read_pidfile(void) ATTR_MALLOC; 14 | extern bool write_pidfile(const char *controlcookie, const char *address); 15 | 16 | #endif // TINC_PIDFILE_H 17 | -------------------------------------------------------------------------------- /.builds/openbsd.yml: -------------------------------------------------------------------------------- 1 | image: openbsd/7.7 2 | 3 | packages: 4 | - cmocka 5 | - libgcrypt 6 | - lz4 7 | - lzo2 8 | - meson 9 | - miniupnpc 10 | - pkgconf 11 | - texinfo 12 | 13 | sources: 14 | - https://github.com/gsliepen/tinc 15 | 16 | tasks: 17 | - openssl: sh tinc/.ci/bsd/run.sh openssl 18 | - nolegacy: sh tinc/.ci/bsd/run.sh nolegacy 19 | - gcrypt: sh tinc/.ci/bsd/run.sh gcrypt 20 | -------------------------------------------------------------------------------- /src/sandbox.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | 3 | #include "sandbox.h" 4 | 5 | // Stubs for platforms without sandbox support to avoid using lots of #ifdefs. 6 | 7 | bool sandbox_can(sandbox_action_t action, sandbox_time_t when) { 8 | (void)action; 9 | (void)when; 10 | return true; 11 | } 12 | 13 | void sandbox_set_level(sandbox_level_t level) { 14 | (void)level; 15 | } 16 | 17 | bool sandbox_enter(void) { 18 | return true; 19 | } 20 | -------------------------------------------------------------------------------- /.ci/cross/windows/amd64: -------------------------------------------------------------------------------- 1 | [properties] 2 | root = '/usr/x86_64-w64-mingw32' 3 | 4 | [binaries] 5 | c = 'x86_64-w64-mingw32-gcc' 6 | ar = 'x86_64-w64-mingw32-ar' 7 | as = 'x86_64-w64-mingw32-as' 8 | strip = 'x86_64-w64-mingw32-strip' 9 | windres = 'x86_64-w64-mingw32-windres' 10 | pkgconfig = 'x86_64-w64-mingw32-pkg-config' 11 | 12 | [host_machine] 13 | system = 'windows' 14 | endian = 'little' 15 | cpu = 'x86_64' 16 | cpu_family = 'x86_64' 17 | 18 | -------------------------------------------------------------------------------- /src/bsd/meson.build: -------------------------------------------------------------------------------- 1 | check_headers += [ 2 | 'net/if_tap.h', 3 | 'net/if_tun.h', 4 | 'net/if_utun.h', 5 | 'net/tap/if_tap.h', 6 | 'net/tun/if_tun.h', 7 | ] 8 | 9 | check_functions += [ 10 | 'devname', 11 | 'fdevname', 12 | ] 13 | 14 | src_tincd += files('device.c') 15 | 16 | if os_name != 'darwin' 17 | src_tincd += files('event.c') 18 | endif 19 | 20 | if os_name in ['openbsd', 'darwin'] 21 | subdir(os_name) 22 | endif 23 | 24 | -------------------------------------------------------------------------------- /src/ed25519/keypair.c: -------------------------------------------------------------------------------- 1 | #include "ed25519.h" 2 | #include "sha512.h" 3 | #include "ge.h" 4 | 5 | 6 | void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { 7 | ge_p3 A; 8 | 9 | sha512(seed, 32, private_key); 10 | private_key[0] &= 248; 11 | private_key[31] &= 63; 12 | private_key[31] |= 64; 13 | 14 | ge_scalarmult_base(&A, private_key); 15 | ge_p3_tobytes(public_key, &A); 16 | } 17 | -------------------------------------------------------------------------------- /.ci/test/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | if [ "$(id -u)" != 0 ] && sudo --preserve-env --non-interactive true; then 6 | echo >&2 "sudo already configured" 7 | exit 0 8 | fi 9 | 10 | useradd --user-group build 11 | 12 | echo 'build ALL=(ALL) NOPASSWD: ALL' >/etc/sudoers.d/build 13 | chmod 440 /etc/sudoers.d/build 14 | visudo --check 15 | 16 | if [ -n "${HOST:-}" ]; then 17 | update-binfmts --enable 18 | rm -f /dev/net/tun 19 | fi 20 | -------------------------------------------------------------------------------- /src/bsd/darwin/meson.build: -------------------------------------------------------------------------------- 1 | dep_tunemu = dependency('tunemu', required: opt_tunemu, static: static) 2 | dep_pcap = dependency('pcap', required: opt_tunemu, static: static) 3 | 4 | if dep_tunemu.found() and dep_pcap.found() 5 | deps_tincd += [dep_tunemu, dep_pcap] 6 | src_tincd += files('tunemu.c') 7 | cdata.set('ENABLE_TUNEMU', 1) 8 | endif 9 | 10 | # macOS apparently doesn't support kqueue with TAP devices 11 | src_tincd += src_event_select 12 | 13 | -------------------------------------------------------------------------------- /src/ed25519/meson.build: -------------------------------------------------------------------------------- 1 | src_ed25519 = files( 2 | 'ecdh.c', 3 | 'ecdsa.c', 4 | 'ecdsagen.c', 5 | 'fe.c', 6 | 'ge.c', 7 | 'key_exchange.c', 8 | 'keypair.c', 9 | 'sc.c', 10 | 'sha512.c', 11 | 'sign.c', 12 | 'verify.c', 13 | ) 14 | 15 | lib_ed25519 = static_library( 16 | 'ed25519', 17 | sources: src_ed25519, 18 | implicit_include_directories: false, 19 | include_directories: inc_conf, 20 | build_by_default: false, 21 | ) 22 | 23 | -------------------------------------------------------------------------------- /src/watchdog.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_WATCHDOG_H 2 | #define TINC_WATCHDOG_H 3 | 4 | // Start sending keepalive notifications to watchdog. 5 | // Called after initialization is finished before entering the event loop. 6 | void watchdog_start(void); 7 | 8 | // Stop sending keepalive notifications. 9 | // Called shortly before exiting. 10 | void watchdog_stop(void); 11 | 12 | // Send keepalive notification. 13 | void watchdog_ping(void); 14 | 15 | #endif // TINC_WATCHDOG_H 16 | -------------------------------------------------------------------------------- /.builds/netbsd.yml: -------------------------------------------------------------------------------- 1 | image: netbsd/10.x 2 | 3 | packages: 4 | - cmocka 5 | - gtexinfo 6 | - libgcrypt 7 | - lz4 8 | - lzo 9 | - meson 10 | - miniupnpc 11 | - pkgconf 12 | 13 | sources: 14 | - https://github.com/gsliepen/tinc 15 | 16 | environment: 17 | PKG_CONFIG_PATH: /usr/pkg/lib/pkgconfig 18 | 19 | tasks: 20 | - openssl: sh tinc/.ci/bsd/run.sh openssl 21 | - nolegacy: sh tinc/.ci/bsd/run.sh nolegacy 22 | - gcrypt: sh tinc/.ci/bsd/run.sh gcrypt 23 | -------------------------------------------------------------------------------- /.builds/freebsd.yml: -------------------------------------------------------------------------------- 1 | image: freebsd/14.x 2 | 3 | packages: 4 | - cmocka 5 | - libgcrypt 6 | - liblz4 7 | - lzo2 8 | - meson 9 | - pkgconf 10 | - texinfo 11 | - vde2 12 | 13 | sources: 14 | - https://github.com/gsliepen/tinc 15 | 16 | environment: 17 | PKG_CONFIG_PATH: /usr/local/libdata/pkgconfig 18 | 19 | tasks: 20 | - openssl: sh tinc/.ci/bsd/run.sh openssl 21 | - nolegacy: sh tinc/.ci/bsd/run.sh nolegacy 22 | - gcrypt: sh tinc/.ci/bsd/run.sh gcrypt 23 | -------------------------------------------------------------------------------- /subprojects/lz4.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = lz4-1.9.3 3 | source_url = https://github.com/lz4/lz4/archive/v1.9.3.tar.gz 4 | source_filename = lz4-1.9.3.tgz 5 | source_hash = 030644df4611007ff7dc962d981f390361e6c97a34e5cbc393ddfbe019ffe2c1 6 | patch_url = https://wrapdb.mesonbuild.com/v2/lz4_1.9.3-1/get_patch 7 | patch_filename = lz4-1.9.3-1-wrap.zip 8 | patch_hash = 5a0e6e5797a51d23d5dad0009d36dfebe354b5e5eef2a1302d29788b1ee067c1 9 | 10 | [provide] 11 | liblz4 = liblz4_dep 12 | 13 | -------------------------------------------------------------------------------- /test/integration/testlib/const.py: -------------------------------------------------------------------------------- 1 | """Some hardcoded constants.""" 2 | 3 | import os 4 | 5 | # Exit code to skip current test 6 | EXIT_SKIP = 77 7 | 8 | # Family name for multiprocessing Listener/Connection 9 | MPC_FAMILY = "AF_PIPE" if os.name == "nt" else "AF_UNIX" 10 | 11 | # Do access checks on files. Disabled when not available or not applicable. 12 | RUN_ACCESS_CHECKS = os.name != "nt" and os.geteuid() != 0 13 | 14 | # Copy of the same define from net.h 15 | MAXSOCKETS = 8 16 | -------------------------------------------------------------------------------- /subprojects/zlib.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = zlib-1.2.11 3 | source_url = http://zlib.net/fossils/zlib-1.2.11.tar.gz 4 | source_filename = zlib-1.2.11.tar.gz 5 | source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 6 | patch_filename = zlib_1.2.11-6_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.2.11-6/get_patch 8 | patch_hash = f7c24c5698ce787294910ad431f94088102d35ddaf88542d04add1e54afa9212 9 | 10 | [provide] 11 | zlib = zlib_dep 12 | 13 | -------------------------------------------------------------------------------- /subprojects/lzo2.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = lzo-2.10 3 | source_url = https://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz 4 | source_filename = lzo-2.10.tar.gz 5 | source_hash = c0f892943208266f9b6543b3ae308fab6284c5c90e627931446fb49b4221a072 6 | patch_filename = lzo2_2.10-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/lzo2_2.10-1/get_patch 8 | patch_hash = 181cf865ea5317b6e8822c71385325328863489a4e5f49177ff67fd13ea1220e 9 | 10 | [provide] 11 | lzo2 = lzo2_dep 12 | 13 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: "-*,performance-*,modernize-*,misc-*,-misc-no-recursion,bugprone-*,-bugprone-macro-parentheses,-bugprone-easily-swappable-parameters,-bugprone-reserved-identifier,-bugprone-suspicious-string-compare,-bugprone-implicit-widening-of-multiplication-result,-bugprone-not-null-terminated-result,-bugprone-branch-clone,-bugprone-sizeof-expression,clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,-clang-analyzer-core.UndefinedBinaryOperatorResult" 2 | HeaderFilterRegex: ".*" 3 | WarningsAsErrors: "*" 4 | -------------------------------------------------------------------------------- /doc/sample-config/hosts/alpha: -------------------------------------------------------------------------------- 1 | # Sample host configuration file 2 | 3 | # The real IP address of this tinc host. Can be used by other tinc hosts. 4 | Address = 123.234.35.67 5 | 6 | # Portnumber for incoming connections. Default is 655. 7 | Port = 655 8 | 9 | # Subnet on the virtual private network that is local for this host. 10 | Subnet = 192.168.1.0/24 11 | 12 | # The public key generated by `tincd -n example -K' is stored here 13 | -----BEGIN RSA PUBLIC KEY----- 14 | ... 15 | -----END RSA PUBLIC KEY----- 16 | -------------------------------------------------------------------------------- /src/windows/meson.build: -------------------------------------------------------------------------------- 1 | check_headers += 'w32api.h' 2 | 3 | win_common_libs = ['ws2_32', 'iphlpapi', 'threads'] 4 | 5 | if opt_harden and cc_name != 'msvc' 6 | win_common_libs += 'ssp' 7 | endif 8 | 9 | foreach libname : win_common_libs 10 | dep = dependency(libname, required: false) 11 | if not dep.found() 12 | dep = cc.find_library(libname) 13 | endif 14 | deps_common += dep 15 | endforeach 16 | 17 | src_lib_common += files('random.c') 18 | 19 | src_tincd += files( 20 | 'device.c', 21 | 'event.c', 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /src/ed25519/sha512.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA512_H 2 | #define SHA512_H 3 | 4 | #include 5 | 6 | #include "fixedint.h" 7 | 8 | /* state */ 9 | typedef struct sha512_context_ { 10 | uint64_t length, state[8]; 11 | size_t curlen; 12 | unsigned char buf[128]; 13 | } sha512_context; 14 | 15 | 16 | int sha512_init(sha512_context *md); 17 | int sha512_final(sha512_context *md, void *out); 18 | int sha512_update(sha512_context *md, const void *in, size_t inlen); 19 | int sha512(const void *message, size_t message_len, void *out); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/linux/meson.build: -------------------------------------------------------------------------------- 1 | check_headers += [ 2 | 'linux/if_tun.h', 3 | 'netpacket/packet.h', 4 | ] 5 | 6 | check_functions += 'recvmmsg' 7 | 8 | src_tincd += files( 9 | 'device.c', 10 | 'event.c', 11 | ) 12 | 13 | dep_libsystemd = dependency('libsystemd', required: opt_systemd) 14 | if dep_libsystemd.found() 15 | src_tincd += files('watchdog.c') 16 | deps_tincd += dep_libsystemd 17 | cdata.set('HAVE_WATCHDOG', 1) 18 | endif 19 | 20 | if opt_uml 21 | src_tincd += files('uml_device.c') 22 | cdata.set('ENABLE_UML', 1) 23 | endif 24 | 25 | -------------------------------------------------------------------------------- /systemd/tinc@.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Tinc net %i 3 | Documentation=info:tinc 4 | Documentation=man:tinc(8) man:tinc.conf(5) 5 | Documentation=http://tinc-vpn.org/docs/ 6 | PartOf=tinc.service 7 | ReloadPropagatedFrom=tinc.service 8 | 9 | [Service] 10 | Type=notify 11 | WorkingDirectory=@sysconfdir@/tinc/%i 12 | ExecStart=@sbindir@/tincd -n %i -D 13 | ExecReload=@sbindir@/tinc -n %i reload 14 | KillMode=mixed 15 | Restart=on-failure 16 | RestartSec=5 17 | TimeoutStopSec=5 18 | WatchdogSec=10 19 | 20 | [Install] 21 | WantedBy=tinc.service 22 | -------------------------------------------------------------------------------- /doc/sample-config/hosts/beta: -------------------------------------------------------------------------------- 1 | # Sample host configuration file 2 | # This file was generated by host beta. 3 | 4 | # The real IP address of this tinc host. Can be used by other tinc hosts. 5 | Address = 123.45.67.189 6 | 7 | # Portnumber for incoming connections. Default is 655. 8 | Port = 6500 9 | 10 | # Subnet on the virtual private network that is local for this host. 11 | Subnet = 192.168.2.0/24 12 | 13 | # The public key generated by `tincd -n example -K' is stored here 14 | -----BEGIN RSA PUBLIC KEY----- 15 | ... 16 | -----END RSA PUBLIC KEY----- 17 | -------------------------------------------------------------------------------- /test/integration/testlib/template/netns.py.tpl: -------------------------------------------------------------------------------- 1 | # Indentation is important! This gets copied inside another Python script. 2 | import subprocess as subp 3 | 4 | iface = os.environ['INTERFACE'] 5 | log.info('using interface %s', iface) 6 | 7 | subp.run(['ip', 'link', 'set', 'dev', iface, 'netns', '$NAMESPACE'], check=True) 8 | subp.run(['ip', 'netns', 'exec', '$NAMESPACE', 'ip', 'addr', 'add', '$ADDRESS/$MASK', 'dev', iface], check=True) 9 | subp.run(['ip', 'netns', 'exec', '$NAMESPACE', 'ip', 'link', 'set', iface, 'up'], check=True) 10 | -------------------------------------------------------------------------------- /.ci/warn/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | test -n "$CC" 6 | 7 | result=0 8 | 9 | clang_tidy() { 10 | rm -f compile_commands.json 11 | ln -s "$1"/compile_commands.json . 12 | run-clang-tidy || result=$? 13 | } 14 | 15 | check_warnings() { 16 | flavor="$1" 17 | dir="${CC}_${flavor}" 18 | 19 | ./.ci/build.sh "$dir" -Dwerror=true || result=$? 20 | 21 | case "$CC" in 22 | clang*) clang_tidy "$dir" ;; 23 | esac 24 | } 25 | 26 | check_warnings default 27 | check_warnings nolegacy 28 | check_warnings gcrypt 29 | 30 | exit $result 31 | -------------------------------------------------------------------------------- /doc/sample-config/tinc-up: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This file sets up the tap device. 3 | # It gives you the freedom to do anything you want with it. 4 | # Use the correct name for the tap device: 5 | # The environment variable $INTERFACE is set to the right name 6 | # on most platforms, but if it doesn't work try to set it manually. 7 | 8 | # Give it the right ip and netmask. Remember, the subnet of the 9 | # tap device must be larger than that of the individual Subnets 10 | # as defined in the host configuration file! 11 | ifconfig $INTERFACE 192.168.1.1 netmask 255.255.0.0 12 | -------------------------------------------------------------------------------- /src/chacha-poly1305/poly1305.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */ 2 | 3 | /* 4 | * Public Domain poly1305 from Andrew Moon 5 | * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna 6 | */ 7 | 8 | #ifndef POLY1305_H 9 | #define POLY1305_H 10 | 11 | #define POLY1305_KEYLEN 32 12 | #define POLY1305_TAGLEN 16 13 | 14 | void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]); 15 | 16 | #endif /* POLY1305_H */ 17 | -------------------------------------------------------------------------------- /src/gcrypt/meson.build: -------------------------------------------------------------------------------- 1 | src_lib_crypto = files( 2 | 'cipher.c', 3 | 'crypto.c', 4 | 'digest.c', 5 | 'pem.c', 6 | 'prf.c', 7 | 'rsa.c', 8 | 'rsagen.c', 9 | ) 10 | 11 | # Under current MinGW, flags specified in libgcrypt.pc fail on static build 12 | if static and os_name == 'windows' 13 | dep_crypto = [] 14 | foreach lib : ['libgcrypt', 'gpg-error'] 15 | dep_crypto += cc.find_library(lib, static: true) 16 | endforeach 17 | else 18 | dep_crypto = dependency('libgcrypt', static: static) 19 | endif 20 | 21 | cdata.set('HAVE_LIBGCRYPT', 1) 22 | 23 | -------------------------------------------------------------------------------- /subprojects/openssl.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = openssl-3.0.2 3 | source_url = https://www.openssl.org/source/openssl-3.0.2.tar.gz 4 | source_filename = openssl-3.0.2.tar.gz 5 | source_hash = 98e91ccead4d4756ae3c9cde5e09191a8e586d9f4d50838e7ec09d6411dfdb63 6 | patch_filename = openssl_3.0.2-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.2-1/get_patch 8 | patch_hash = 762ab4ea94d02178d6a1d3eb63409c2c4d61315d358391cdac62df15211174d4 9 | 10 | [provide] 11 | libcrypto = libcrypto_dep 12 | libssl = libssl_dep 13 | openssl = openssl_dep 14 | 15 | -------------------------------------------------------------------------------- /systemd/tinc.service.in: -------------------------------------------------------------------------------- 1 | # This is a mostly empty service, but allows commands like stop, start, reload 2 | # to propagate to all tinc@ service instances. 3 | 4 | [Unit] 5 | Description=Tinc VPN 6 | Documentation=info:tinc 7 | Documentation=man:tinc(8) man:tinc.conf(5) 8 | Documentation=http://tinc-vpn.org/docs/ 9 | After=network.target 10 | Wants=network.target 11 | 12 | [Service] 13 | Type=oneshot 14 | RemainAfterExit=yes 15 | ExecStart=/bin/true 16 | ExecReload=/bin/true 17 | WorkingDirectory=@sysconfdir@/tinc 18 | 19 | [Install] 20 | WantedBy=multi-user.target 21 | -------------------------------------------------------------------------------- /src/windows/random.c: -------------------------------------------------------------------------------- 1 | #include "../system.h" 2 | 3 | #include 4 | 5 | #include "../random.h" 6 | 7 | static HCRYPTPROV prov; 8 | 9 | void random_init(void) { 10 | if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 11 | fprintf(stderr, "CryptAcquireContext() failed!\n"); 12 | abort(); 13 | } 14 | } 15 | 16 | void random_exit(void) { 17 | CryptReleaseContext(prov, 0); 18 | } 19 | 20 | void randomize(void *vout, size_t outlen) { 21 | if(!CryptGenRandom(prov, outlen, vout)) { 22 | fprintf(stderr, "CryptGenRandom() failed\n"); 23 | abort(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.ci/package/rpm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | if ! rpm -qi openssl-devel; then 6 | exit 0 7 | fi 8 | 9 | find_tag() { 10 | git describe --always --tags --match='release-*' "$@" 11 | } 12 | 13 | spec=$HOME/rpmbuild/SPECS/tinc.spec 14 | version=$(find_tag HEAD | sed 's/-/_/g') 15 | version=${version//release_/} 16 | 17 | export CONFIG_SHELL=bash 18 | 19 | yum install -y rpmdevtools 20 | rpmdev-setuptree 21 | 22 | cp "$(dirname "$0")/tinc.spec" "$spec" 23 | sed -i "s/__VERSION__/$version/" "$spec" 24 | 25 | git clean -dfx 26 | cp -a . ~/rpmbuild/BUILD 27 | 28 | rpmbuild -bb "$spec" 29 | -------------------------------------------------------------------------------- /src/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_BUFFER_H 2 | #define TINC_BUFFER_H 3 | 4 | #include "system.h" 5 | 6 | typedef struct buffer_t { 7 | char *data; 8 | uint32_t maxlen; 9 | uint32_t len; 10 | uint32_t offset; 11 | } buffer_t; 12 | 13 | extern void buffer_compact(buffer_t *buffer, uint32_t maxsize); 14 | extern char *buffer_prepare(buffer_t *buffer, uint32_t size); 15 | extern void buffer_add(buffer_t *buffer, const char *data, uint32_t size); 16 | extern char *buffer_readline(buffer_t *buffer); 17 | extern char *buffer_read(buffer_t *buffer, uint32_t size); 18 | extern void buffer_clear(buffer_t *buffer); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /.ci/package/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | build_linux() { 6 | . /etc/os-release 7 | 8 | # https://github.com/actions/checkout/issues/760 9 | git config --global --add safe.directory "$PWD" || true 10 | GIT_CEILING_DIRECTORIES=$PWD 11 | export GIT_CEILING_DIRECTORIES 12 | 13 | case "$ID" in 14 | debian | ubuntu) 15 | bash .ci/package/deb/build.sh 16 | ;; 17 | almalinux | centos | fedora) 18 | bash .ci/package/rpm/build.sh 19 | ;; 20 | esac 21 | } 22 | 23 | case "$(uname -s)" in 24 | Linux) 25 | build_linux 26 | ;; 27 | MINGW*) 28 | bash .ci/package/win/build.sh 29 | ;; 30 | esac 31 | -------------------------------------------------------------------------------- /test/integration/executables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Basic sanity checks on compiled executables.""" 4 | 5 | from subprocess import run, PIPE 6 | 7 | from testlib import path, check 8 | from testlib.log import log 9 | 10 | for exe in ( 11 | path.TINC_PATH, 12 | path.TINCD_PATH, 13 | path.SPTPS_TEST_PATH, 14 | path.SPTPS_KEYPAIR_PATH, 15 | ): 16 | cmd = [exe, "--help"] 17 | log.info('testing command "%s"', cmd) 18 | res = run(cmd, stdout=PIPE, stderr=PIPE, encoding="utf-8", timeout=10, check=False) 19 | check.success(res.returncode) 20 | check.is_in("Usage:", res.stdout, res.stderr) 21 | -------------------------------------------------------------------------------- /src/compression.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_COMPRESSION_H 2 | #define TINC_COMPRESSION_H 3 | 4 | typedef enum compression_level_t { 5 | COMPRESS_NONE = 0, 6 | 7 | COMPRESS_ZLIB_1 = 1, 8 | COMPRESS_ZLIB_2 = 2, 9 | COMPRESS_ZLIB_3 = 3, 10 | COMPRESS_ZLIB_4 = 4, 11 | COMPRESS_ZLIB_5 = 5, 12 | COMPRESS_ZLIB_6 = 6, 13 | COMPRESS_ZLIB_7 = 7, 14 | COMPRESS_ZLIB_8 = 8, 15 | COMPRESS_ZLIB_9 = 9, 16 | 17 | COMPRESS_LZO_LO = 10, 18 | COMPRESS_LZO_HI = 11, 19 | 20 | COMPRESS_LZ4 = 12, 21 | } compression_level_t; 22 | 23 | STATIC_ASSERT(sizeof(compression_level_t) == sizeof(int), "compression_level_t has invalid size"); 24 | 25 | #endif // TINC_COMPRESSION_H 26 | -------------------------------------------------------------------------------- /version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Print current tinc version for using in build scripts.""" 4 | 5 | from os import path, environ 6 | import subprocess as subp 7 | 8 | PREFIX = "release-" 9 | SOURCE_ROOT = path.dirname(path.realpath(__file__)) 10 | SOURCE_ROOT = environ.get("MESON_SOURCE_ROOT", SOURCE_ROOT) 11 | 12 | cmd = [ 13 | "git", 14 | "--git-dir", 15 | path.join(SOURCE_ROOT, ".git"), 16 | "describe", 17 | "--always", 18 | "--tags", 19 | "--match=" + PREFIX + "*", 20 | ] 21 | 22 | result = subp.run(cmd, stdout=subp.PIPE, encoding="utf-8", check=True) 23 | version = result.stdout.strip().replace("release-", "", 1) 24 | print(version) 25 | -------------------------------------------------------------------------------- /COPYING.README: -------------------------------------------------------------------------------- 1 | The following applies to tinc: 2 | 3 | > This program is released under the GPL with the additional exemption that 4 | > compiling, linking, and/or using OpenSSL is allowed. You may provide binary 5 | > packages linked to the OpenSSL libraries, provided that all other requirements 6 | > of the GPL are met. 7 | 8 | The following applies to the LZO library: 9 | 10 | > Hereby I grant a special exception to the tinc VPN project 11 | > (https://www.tinc-vpn.org/) to link the LZO library with the OpenSSL library 12 | > (https://openssl.org). 13 | > 14 | > Markus F.X.J. Oberhumer 15 | 16 | When tinc is compiled with the --enable-tunemu option, the resulting binary 17 | falls under the GPL version 3 or later. 18 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NETSFILE="/etc/tinc/nets.boot" 4 | SYSTEM="/lib/systemd/system" 5 | WANTS="/etc/systemd/system/multi-user.target.wants" 6 | 7 | set -e 8 | 9 | case "$1" in 10 | upgrade) 11 | if dpkg --compare-versions "$2" '<<' "1.1~pre11-1"; then 12 | if [ -f "$NETSFILE" ]; then 13 | echo -n "Creating systemd service instances from nets.boot:" 14 | mkdir -p "$WANTS" 15 | egrep '^[ ]*[a-zA-Z0-9_-]+' $NETSFILE | while read net args; do 16 | echo -n " $net" 17 | ln -s "$SYSTEM/tinc@.service" "$WANTS/tinc@$net.service" 2>/dev/null || true 18 | done 19 | echo "." 20 | fi 21 | fi 22 | ;; 23 | 24 | *) ;; 25 | 26 | esac 27 | 28 | #DEBHELPER# 29 | -------------------------------------------------------------------------------- /src/console.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | 3 | #include "console.h" 4 | 5 | bool use_ansi_escapes(FILE *out) { 6 | bool is_tty = isatty(fileno(out)); 7 | 8 | #ifndef HAVE_WINDOWS 9 | const char *term = getenv("TERM"); 10 | return is_tty && term && strcmp(term, "dumb"); 11 | #else 12 | HANDLE console; 13 | 14 | if(out == stdout) { 15 | console = GetStdHandle(STD_OUTPUT_HANDLE); 16 | } else if(out == stderr) { 17 | console = GetStdHandle(STD_ERROR_HANDLE); 18 | } else { 19 | return false; 20 | } 21 | 22 | DWORD mode = 0; 23 | return is_tty && 24 | console != INVALID_HANDLE_VALUE && 25 | GetConsoleMode(console, &mode) && 26 | SetConsoleMode(console, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); 27 | #endif 28 | } 29 | -------------------------------------------------------------------------------- /src/chacha-poly1305/chacha.h: -------------------------------------------------------------------------------- 1 | /* 2 | chacha-merged.c version 20080118 3 | D. J. Bernstein 4 | Public domain. 5 | */ 6 | 7 | #ifndef CHACHA_H 8 | #define CHACHA_H 9 | 10 | struct chacha_ctx { 11 | uint32_t input[16]; 12 | }; 13 | 14 | #define CHACHA_MINKEYLEN 16 15 | #define CHACHA_NONCELEN 8 16 | #define CHACHA_CTRLEN 8 17 | #define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) 18 | #define CHACHA_BLOCKLEN 64 19 | 20 | void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits); 21 | void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr); 22 | void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes); 23 | 24 | #endif /* CHACHA_H */ 25 | -------------------------------------------------------------------------------- /src/conf_net.c: -------------------------------------------------------------------------------- 1 | #include "conf_net.h" 2 | #include "logger.h" 3 | 4 | bool get_config_subnet(const config_t *cfg, subnet_t **result) { 5 | subnet_t subnet = {0}; 6 | 7 | if(!cfg) { 8 | return false; 9 | } 10 | 11 | if(!str2net(&subnet, cfg->value)) { 12 | logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d", 13 | cfg->variable, cfg->file, cfg->line); 14 | return false; 15 | } 16 | 17 | if(subnetcheck(subnet)) { 18 | *(*result = new_subnet()) = subnet; 19 | return true; 20 | } 21 | 22 | logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d", 23 | cfg->variable, cfg->file, cfg->line); 24 | return false; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/fs.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_FS_H 2 | #define TINC_FS_H 3 | 4 | #include "system.h" 5 | 6 | typedef enum { 7 | DIR_CACHE = 1 << 0, 8 | DIR_CONFBASE = 1 << 1, 9 | DIR_CONFDIR = 1 << 2, 10 | DIR_HOSTS = 1 << 3, 11 | DIR_INVITATIONS = 1 << 4, 12 | } tinc_dir_t; 13 | 14 | // Create one or multiple directories inside tincd configuration directory 15 | extern bool makedirs(tinc_dir_t dirs); 16 | 17 | // Open file. If it does not exist, create a new file with the specified access mode. 18 | extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms) ATTR_DEALLOCATOR(fclose); 19 | 20 | // Get absolute path to a possibly nonexistent file or directory 21 | extern char *absolute_path(const char *path) ATTR_MALLOC; 22 | 23 | #endif // TINC_FS_H 24 | -------------------------------------------------------------------------------- /src/keys.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_KEYS_H 2 | #define TINC_KEYS_H 3 | 4 | #include "rsa.h" 5 | #include "ecdsa.h" 6 | #include "splay_tree.h" 7 | 8 | extern bool disable_old_keys(const char *filename, const char *what); 9 | 10 | extern ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 11 | extern ecdsa_t *read_ecdsa_public_key(splay_tree_t **config_tree, const char *name) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 12 | 13 | #ifndef DISABLE_LEGACY 14 | extern rsa_t *read_rsa_private_key(splay_tree_t *config, char **keyfile) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 15 | extern rsa_t *read_rsa_public_key(splay_tree_t *config_tree, const char *name) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 16 | #endif 17 | 18 | #endif // TINC_KEYS_H 19 | -------------------------------------------------------------------------------- /src/chacha-poly1305/chacha-poly1305.h: -------------------------------------------------------------------------------- 1 | #ifndef CHACHA_POLY1305_H 2 | #define CHACHA_POLY1305_H 3 | 4 | #define CHACHA_POLY1305_KEYLEN 64 5 | 6 | typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t; 7 | 8 | extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *); 9 | extern chacha_poly1305_ctx_t *chacha_poly1305_init(void) ATTR_DEALLOCATOR(chacha_poly1305_exit); 10 | extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const uint8_t *key); 11 | 12 | extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen); 13 | extern bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen); 14 | 15 | #endif //CHACHA_POLY1305_H 16 | -------------------------------------------------------------------------------- /test/unit/test_protocol.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/protocol.h" 3 | 4 | static void test_get_invalid_request(void **state) { 5 | (void)state; 6 | 7 | assert_null(get_request_entry(ALL)); 8 | assert_null(get_request_entry(LAST)); 9 | } 10 | 11 | static void test_get_valid_request_returns_nonnull(void **state) { 12 | (void)state; 13 | 14 | for(request_t req = ID; req < LAST; ++req) { 15 | const request_entry_t *ent = get_request_entry(req); 16 | assert_non_null(ent); 17 | assert_non_null(ent->name); 18 | } 19 | } 20 | 21 | int main(void) { 22 | const struct CMUnitTest tests[] = { 23 | cmocka_unit_test(test_get_invalid_request), 24 | cmocka_unit_test(test_get_valid_request_returns_nonnull), 25 | }; 26 | return cmocka_run_group_tests(tests, NULL, NULL); 27 | } 28 | -------------------------------------------------------------------------------- /doc/sample-config/tinc.conf: -------------------------------------------------------------------------------- 1 | # Sample tinc configuration file 2 | 3 | # This is a comment. 4 | # Spaces and tabs are eliminated. 5 | # The = sign isn't strictly necessary any longer, though you may want 6 | # to leave it in as it improves readability :) 7 | # Variable names are treated case insensitive. 8 | 9 | # The name of this tinc host. Required. 10 | Name = alpha 11 | 12 | # The internet host to connect with. 13 | # Comment these out to make yourself a listen-only connection 14 | # You must use the name of another tinc host. 15 | # May be used multiple times for redundance. 16 | ConnectTo = beta 17 | 18 | # The tap device tinc will use. 19 | # Default is /dev/tap0 for ethertap or FreeBSD, 20 | # /dev/tun0 for Solaris and OpenBSD, 21 | # and /dev/net/tun for Linux tun/tap device. 22 | Device = /dev/net/tun 23 | -------------------------------------------------------------------------------- /.ci/conf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | add_flag() { 6 | printf ' %s ' "$@" 7 | } 8 | 9 | conf_linux() { 10 | HOST="${HOST:-nonexistent}" 11 | if [ "$HOST" = mingw ]; then 12 | cross=".ci/cross/windows/amd64" 13 | else 14 | cross=".ci/cross/linux/$HOST" 15 | fi 16 | if [ -f "$cross" ]; then 17 | add_flag --cross-file "$cross" 18 | fi 19 | add_flag -Dminiupnpc=auto -Duml=true 20 | } 21 | 22 | conf_windows() { 23 | add_flag -Dminiupnpc=auto 24 | } 25 | 26 | conf_macos() { 27 | openssl=$(brew --prefix openssl) 28 | add_flag -Dminiupnpc=auto -Dpkg_config_path="$openssl/lib/pkgconfig" 29 | } 30 | 31 | add_flag -Dbuildtype=release "$@" 32 | 33 | case "$(uname -s)" in 34 | Linux) conf_linux ;; 35 | MINGW*) conf_windows ;; 36 | Darwin) conf_macos ;; 37 | *) exit 1 ;; 38 | esac 39 | -------------------------------------------------------------------------------- /src/pidfile.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | 3 | #include "pidfile.h" 4 | #include "names.h" 5 | 6 | pidfile_t *read_pidfile(void) { 7 | FILE *f = fopen(pidfilename, "r"); 8 | 9 | if(!f) { 10 | return NULL; 11 | } 12 | 13 | pidfile_t *pf = malloc(sizeof(pidfile_t)); 14 | int read = fscanf(f, "%20d %64s %128s port %128s", &pf->pid, pf->cookie, pf->host, pf->port); 15 | fclose(f); 16 | 17 | if(read != 4) { 18 | free(pf); 19 | pf = NULL; 20 | } 21 | 22 | return pf; 23 | } 24 | 25 | 26 | bool write_pidfile(const char *controlcookie, const char *address) { 27 | const mode_t mask = umask(0); 28 | umask(mask | 077); 29 | FILE *f = fopen(pidfilename, "w"); 30 | 31 | if(!f) { 32 | return false; 33 | } 34 | 35 | umask(mask); 36 | fprintf(f, "%d %s %s\n", (int)getpid(), controlcookie, address); 37 | return !fclose(f); 38 | } 39 | -------------------------------------------------------------------------------- /.ci/package/win/installer.nsi: -------------------------------------------------------------------------------- 1 | !include "MUI.nsh" 2 | 3 | !define MUI_ABORTWARNING 4 | !insertmacro MUI_PAGE_WELCOME 5 | !insertmacro MUI_PAGE_LICENSE "..\..\..\COPYING" 6 | !insertmacro MUI_PAGE_DIRECTORY 7 | !insertmacro MUI_PAGE_INSTFILES 8 | !insertmacro MUI_PAGE_FINISH 9 | 10 | !insertmacro MUI_LANGUAGE "English" 11 | 12 | Name "tinc" 13 | OutFile "tinc-x64.exe" 14 | InstallDir "$PROGRAMFILES64\tinc" 15 | ShowInstDetails show 16 | RequestExecutionLevel admin 17 | 18 | Section "Tinc" 19 | SetOutPath $INSTDIR 20 | 21 | File ..\..\..\default\src\tinc.exe 22 | File ..\..\..\default\src\tincd.exe 23 | File ..\..\..\wintap.exe 24 | 25 | CreateDirectory "$SMPROGRAMS\Tinc" 26 | CreateShortCut "$SMPROGRAMS\Tinc.lnk" "$INSTDIR\tinc.exe" 27 | 28 | ExecWait "wintap.exe" 29 | 30 | CreateDirectory "$SMPROGRAMS\tinc" 31 | SectionEnd 32 | -------------------------------------------------------------------------------- /src/ed25519/sign.c: -------------------------------------------------------------------------------- 1 | #include "ed25519.h" 2 | #include "sha512.h" 3 | #include "ge.h" 4 | #include "sc.h" 5 | 6 | 7 | void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) { 8 | sha512_context hash; 9 | unsigned char hram[64]; 10 | unsigned char r[64]; 11 | ge_p3 R; 12 | 13 | 14 | sha512_init(&hash); 15 | sha512_update(&hash, private_key + 32, 32); 16 | sha512_update(&hash, message, message_len); 17 | sha512_final(&hash, r); 18 | 19 | sc_reduce(r); 20 | ge_scalarmult_base(&R, r); 21 | ge_p3_tobytes(signature, &R); 22 | 23 | sha512_init(&hash); 24 | sha512_update(&hash, signature, 32); 25 | sha512_update(&hash, public_key, 32); 26 | sha512_update(&hash, message, message_len); 27 | sha512_final(&hash, hram); 28 | 29 | sc_reduce(hram); 30 | sc_muladd(signature + 32, hram, private_key, r); 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.github/ 3 | !.ci/ 4 | !.builds/ 5 | !.gitignore 6 | !.astylerc 7 | !.clang-tidy 8 | *~ 9 | *.a 10 | *.dirstamp 11 | *.o 12 | *.orig 13 | *.swp 14 | *.gcno 15 | *.gcda 16 | *-coverage* 17 | /ChangeLog 18 | /INSTALL 19 | /README 20 | /aclocal.m4 21 | /autom4te.cache 22 | /compile 23 | /config.* 24 | /configure 25 | /depcomp 26 | /doc/sample-config.tar.gz 27 | /doc/*.tex 28 | /doc/*.info 29 | /doc/*.5 30 | /doc/*.8 31 | /doc/*.html 32 | /doc/*.pdf 33 | /doc/*.t2p 34 | /doc/tincinclude.texi 35 | /install-sh 36 | /missing 37 | /src/device.c 38 | /src/tincd 39 | /src/tinc 40 | /src/sptps_keypair 41 | /src/sptps_speed 42 | /src/sptps_test 43 | /src/version_git.h 44 | /stamp-h1 45 | /systemd/*.service 46 | /test-driver 47 | /test/*.test.* 48 | /test/*.log 49 | /test/*.trs 50 | /test/splice 51 | Makefile 52 | Makefile.in 53 | core* 54 | heaptrack.* 55 | *.tar.gz* 56 | /subprojects/* 57 | !/subprojects/*.wrap 58 | __pycache__ 59 | -------------------------------------------------------------------------------- /src/top.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_TOP_H 2 | #define TINC_TOP_H 3 | 4 | /* 5 | top.h -- header for top.c. 6 | Copyright (C) 2011 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern void top(int fd); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/bsd/openbsd/sandbox.c: -------------------------------------------------------------------------------- 1 | #include "../../system.h" 2 | 3 | #include "sandbox.h" 4 | #include "../../logger.h" 5 | 6 | void allow_path(const char *path, const char *priv) { 7 | if(path) { 8 | logger(DEBUG_ALWAYS, LOG_DEBUG, "Allowing path %s with %s", path, priv); 9 | 10 | if(unveil(path, priv)) { 11 | logger(DEBUG_ALWAYS, LOG_ERR, "unveil(%s, %s) failed: %s", path, priv, strerror(errno)); 12 | } 13 | } 14 | } 15 | 16 | void allow_paths(const unveil_path_t paths[]) { 17 | // Since some path variables may contain NULL, we check priv here. 18 | // If a NULL path is seen, just skip it. 19 | for(const unveil_path_t *p = paths; p->priv; ++p) { 20 | allow_path(p->path, p->priv); 21 | } 22 | } 23 | 24 | bool restrict_privs(const char *promises, const char *execpromises) { 25 | if(pledge(promises, execpromises)) { 26 | logger(DEBUG_ALWAYS, LOG_ERR, "pledge(%s, %s) failed: %s", promises, execpromises, strerror(errno)); 27 | return false; 28 | } else { 29 | return true; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/fsck.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_FSCK_H 2 | #define TINC_FSCK_H 3 | 4 | /* 5 | fsck.h -- header for fsck.c. 6 | Copyright (C) 2012 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern int fsck(const char *argv0); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /systemd/meson.build: -------------------------------------------------------------------------------- 1 | dep_systemd = dependency('systemd', required: opt_systemd) 2 | if not dep_systemd.found() 3 | subdir_done() 4 | endif 5 | 6 | dir_systemd = get_option('systemd_dir') 7 | if dir_systemd == '' 8 | if meson_version.version_compare('>=0.58') 9 | dir_systemd = dep_systemd.get_variable('systemdsystemunitdir', pkgconfig_define: ['prefix', prefix]) 10 | else 11 | dir_systemd = dep_systemd.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['prefix', prefix]) 12 | endif 13 | endif 14 | 15 | systemd_conf = configuration_data() 16 | systemd_conf.set('sysconfdir', dir_sysconf) 17 | systemd_conf.set('sbindir', dir_sbin) 18 | 19 | configure_file(input: 'tinc.service.in', 20 | output: 'tinc.service', 21 | configuration: systemd_conf, 22 | install_dir: dir_systemd) 23 | 24 | configure_file(input: 'tinc@.service.in', 25 | output: 'tinc@.service', 26 | configuration: systemd_conf, 27 | install_dir: dir_systemd) 28 | 29 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/control: -------------------------------------------------------------------------------- 1 | Source: tinc 2 | Section: net 3 | Priority: optional 4 | Maintainer: none 5 | Standards-Version: 4.2.1 6 | Build-Depends: libssl-dev (>>1.1.0), debhelper (>= 11), texinfo, zlib1g-dev, liblzo2-dev, libncurses5-dev, libreadline-dev, libminiupnpc-dev 7 | Homepage: https://www.tinc-vpn.org/ 8 | Vcs-Browser: https://github.com/gsliepen/tinc 9 | Vcs-Git: https://github.com/gsliepen/tinc.git 10 | Rules-Requires-Root: no 11 | 12 | Package: tinc 13 | Architecture: any 14 | Depends: ${shlibs:Depends}, ${misc:Depends} 15 | Description: Virtual Private Network daemon 16 | tinc is a daemon with which you can create a virtual private network 17 | (VPN). One daemon can handle multiple connections, so you can 18 | create an entire (moderately sized) VPN with only one daemon per 19 | participating computer. 20 | This is an automated build and is not supported by upstream. It has 21 | gone through automated testing before being published, but may or may 22 | not work on your system. Use at your own risk. 23 | -------------------------------------------------------------------------------- /src/autoconnect.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_AUTOCONNECT_H 2 | #define TINC_AUTOCONNECT_H 3 | 4 | /* 5 | autoconnect.h -- header for autoconnect.c 6 | Copyright (C) 2017 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern void do_autoconnect(void); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/upnp.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_UPNP_H 2 | #define TINC_UPNP_H 3 | 4 | /* 5 | upnp.h -- UPnP-IGD client 6 | Copyright (C) 2015 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | extern void upnp_init(bool tcp, bool udp); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/graph.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GRAPH_H 2 | #define TINC_GRAPH_H 3 | 4 | /* 5 | graph.h -- header for graph.c 6 | Copyright (C) 2001-2012 Guus Sliepen , 7 | 2001-2005 Ivo Timmermans 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | extern void graph(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/info.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_INFO_H 2 | #define TINC_INFO_H 3 | 4 | /* 5 | info.h -- header for info.c. 6 | Copyright (C) 2012 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern int info(int fd, const char *item); 24 | extern char *strip_weight(char *); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/openssl/meson.build: -------------------------------------------------------------------------------- 1 | src_lib_crypto = files( 2 | 'cipher.c', 3 | 'crypto.c', 4 | 'digest.c', 5 | 'log.c', 6 | 'prf.c', 7 | 'rsa.c', 8 | 'rsagen.c', 9 | ) 10 | 11 | # OpenBSD's 'OpenSSL' is actually LibreSSL. pkg-config on OpenBSD 7.0 reports 12 | # it as OpenSSL 1.0, but it has everything we need (unlike 'real' OpenSSL 1.0). 13 | 14 | if os_name == 'openbsd' 15 | names = ['openssl', 'eopenssl30', 'eopenssl11'] 16 | min_ver = '>=1.0.0' 17 | else 18 | names = ['openssl', 'openssl11'] 19 | min_ver = '>=1.1.0' 20 | endif 21 | 22 | if meson_version.version_compare('>=0.60') 23 | dep_crypto = dependency(names, version: min_ver, static: static) 24 | else 25 | foreach name : names 26 | dep_crypto = dependency(name, version: min_ver, static: static, required: false) 27 | if dep_crypto.found() 28 | break 29 | endif 30 | endforeach 31 | if not dep_crypto.found() 32 | dep_crypto = dependency('', static: static, fallback: ['openssl', 'openssl_dep']) 33 | endif 34 | endif 35 | 36 | cdata.set('HAVE_OPENSSL', 1) 37 | 38 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Main tinc authors: 2 | 3 | - Guus Sliepen 4 | - Ivo Timmermans (inactive) 5 | 6 | Significant code contributions from: 7 | 8 | - Brandon Black 9 | - Etienne Dechamps 10 | - Florian Forster 11 | - Grzegorz Dymarek 12 | - Julien Muchembled 13 | - Loïc Grenié 14 | - Max Rijevski 15 | - Michael Tokarev 16 | - Scott Lamb 17 | - Sven-Haegar Koch 18 | - Timothy Redaelli 19 | 20 | These files are from other sources: 21 | 22 | * lib/pidfile.h and lib/pidfile.c are by Martin Schulze, taken from 23 | the syslog 1.3 sources. 24 | 25 | * src/bsd/tunemu.c and tunemu.h are by Friedrich Schöller 26 | 27 | 28 | Also some of the macro files in the directory m4, and their 29 | accompanying files in lib, were taken from GNU fileutils. 30 | 31 | Please see the file THANKS for a list of all contributors to tinc. 32 | -------------------------------------------------------------------------------- /src/control.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_CONTROL_H 2 | #define TINC_CONTROL_H 3 | 4 | /* 5 | control.h -- header for control.c. 6 | Copyright (C) 2007 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | extern bool init_control(void); 26 | extern void exit_control(void); 27 | extern char controlcookie[]; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/nolegacy/crypto.c: -------------------------------------------------------------------------------- 1 | /* 2 | crypto.c -- Cryptographic miscellaneous functions and initialisation 3 | Copyright (C) 2007-2022 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "../crypto.h" 21 | 22 | // No-op for those cryptographic libraries that 23 | // do not require any additional initialization. 24 | void crypto_init(void) {} 25 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_VERSION_H 2 | #define TINC_VERSION_H 3 | 4 | /* 5 | version.h -- header for version.c 6 | Copyright (C) 2014 Etienne Dechamps 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern const char *const BUILD_DATE; 24 | extern const char *const BUILD_TIME; 25 | extern const char *const BUILD_VERSION; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | If you have found a security vulnerability in tinc, please email 6 | guus@tinc-vpn.org directly. You can encrypt the email using PGP if desired. We 7 | will try to respond within 48 hours. If there is no response, try to contact us 8 | via alternate means listed at https://www.tinc-vpn.org/contact/. 9 | 10 | ## Disclosure Policy 11 | 12 | We greatly prefer to use the responsible disclosure model. After we have been 13 | contacted about a potential vulnerability, we will do the following: 14 | 15 | - Confirm the problem and determine the affected versions. 16 | - Register a CVE number. 17 | - Prepare a fix for all affected versions of tinc. 18 | - Coordinate a release of the fix with Linux and BSD distributions. 19 | - Disclose the vulneratbility after the fix has been released and any agreed 20 | upon embargo period has expired. 21 | 22 | ## Supported Versions 23 | 24 | Currently we support the 1.0.x and 1.1.x branches of tinc. 25 | 26 | | Version | Supported | 27 | |---------|-----------| 28 | | 1.1.x | yes | 29 | | 1.0.x | yes | 30 | -------------------------------------------------------------------------------- /test/integration/net.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test various network-related configuration variables.""" 4 | 5 | from testlib import check, cmd 6 | from testlib.test import Test 7 | 8 | 9 | def test_tunnel_server(ctx: Test, enabled: bool) -> None: 10 | """Test TunnelServer.""" 11 | 12 | foo, mid, bar = ( 13 | ctx.node(init=True), 14 | ctx.node(init=f"set TunnelServer {'yes' if enabled else 'no'}"), 15 | ctx.node(init=True), 16 | ) 17 | 18 | mid.start() 19 | 20 | for peer in foo, bar: 21 | cmd.exchange(peer, mid) 22 | peer.cmd("add", "ConnectTo", mid.name) 23 | peer.add_script(mid.script_up) 24 | peer.start() 25 | 26 | foo[mid.script_up].wait() 27 | bar[mid.script_up].wait() 28 | 29 | edge_peers = 2 if enabled else 3 30 | 31 | check.nodes(foo, edge_peers) 32 | check.nodes(mid, 3) 33 | check.nodes(bar, edge_peers) 34 | 35 | 36 | with Test("test TunnelServer = yes") as context: 37 | test_tunnel_server(context, True) 38 | 39 | with Test("test TunnelServer = no") as context: 40 | test_tunnel_server(context, False) 41 | -------------------------------------------------------------------------------- /src/ed25519/ed25519.h: -------------------------------------------------------------------------------- 1 | #ifndef ED25519_H 2 | #define ED25519_H 3 | 4 | #include 5 | 6 | #if defined(_WIN32) 7 | #if defined(ED25519_BUILD_DLL) 8 | #define ED25519_DECLSPEC __declspec(dllexport) 9 | #elif defined(ED25519_DLL) 10 | #define ED25519_DECLSPEC __declspec(dllimport) 11 | #else 12 | #define ED25519_DECLSPEC 13 | #endif 14 | #else 15 | #define ED25519_DECLSPEC 16 | #endif 17 | 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed); 24 | 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); 25 | int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key); 26 | void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key); 27 | 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/prf.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_PRF_H 2 | #define TINC_PRF_H 3 | 4 | /* 5 | prf.h -- header file for prf.c 6 | Copyright (C) 2011-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | extern bool prf(const uint8_t *secret, size_t secretlen, uint8_t *seed, size_t seedlen, uint8_t *out, size_t outlen) ATTR_WARN_UNUSED; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/bsd/openbsd/tincctl.c: -------------------------------------------------------------------------------- 1 | #include "../../system.h" 2 | 3 | #include "sandbox.h" 4 | #include "../../sandbox.h" 5 | 6 | static const char *promises = 7 | "stdio" // General I/O 8 | " rpath" // Read configs & keys 9 | " wpath" // Write same 10 | " cpath" // Create same 11 | " fattr" // chmod() same 12 | " proc" // Check that tincd is running with kill() 13 | " dns" // Resolve domain names 14 | " inet" // Check that port is available 15 | " unix" // Control connection to tincd 16 | " exec" // Start tincd 17 | #if defined(HAVE_CURSES) || defined(HAVE_READLINE) 18 | " tty" 19 | #endif 20 | ; 21 | 22 | static sandbox_level_t current_level = SANDBOX_NONE; 23 | 24 | void sandbox_set_level(sandbox_level_t level) { 25 | current_level = level; 26 | } 27 | 28 | bool sandbox_enter() { 29 | if(current_level == SANDBOX_NONE) { 30 | return true; 31 | } else { 32 | return restrict_privs(promises, PROMISES_ALL); 33 | } 34 | } 35 | 36 | bool sandbox_can(sandbox_action_t action, sandbox_time_t when) { 37 | (void)action; 38 | (void)when; 39 | return true; 40 | } 41 | -------------------------------------------------------------------------------- /src/ed25519/fe.h: -------------------------------------------------------------------------------- 1 | #ifndef FE_H 2 | #define FE_H 3 | 4 | #include "fixedint.h" 5 | 6 | 7 | /* 8 | fe means field element. 9 | Here the field is \Z/(2^255-19). 10 | An element t, entries t[0]...t[9], represents the integer 11 | t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. 12 | Bounds on each t[i] vary depending on context. 13 | */ 14 | 15 | 16 | typedef int32_t fe[10]; 17 | 18 | 19 | void fe_0(fe h); 20 | void fe_1(fe h); 21 | 22 | void fe_frombytes(fe h, const unsigned char *s); 23 | void fe_tobytes(unsigned char *s, const fe h); 24 | 25 | void fe_copy(fe h, const fe f); 26 | int fe_isnegative(const fe f); 27 | int fe_isnonzero(const fe f); 28 | void fe_cmov(fe f, const fe g, unsigned int b); 29 | void fe_cswap(fe f, fe g, unsigned int b); 30 | 31 | void fe_neg(fe h, const fe f); 32 | void fe_add(fe h, const fe f, const fe g); 33 | void fe_invert(fe out, const fe z); 34 | void fe_sq(fe h, const fe f); 35 | void fe_sq2(fe h, const fe f); 36 | void fe_mul(fe h, const fe f, const fe g); 37 | void fe_mul121666(fe h, fe f); 38 | void fe_pow22523(fe out, const fe z); 39 | void fe_sub(fe h, const fe f, const fe g); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/sandbox.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_SANDBOX_H 2 | #define TINC_SANDBOX_H 3 | 4 | #include "system.h" 5 | 6 | typedef enum sandbox_level_t { 7 | SANDBOX_NONE, 8 | SANDBOX_NORMAL, 9 | SANDBOX_HIGH, 10 | } sandbox_level_t; 11 | 12 | typedef enum sandbox_action_t { 13 | START_PROCESSES, // Start child processes 14 | USE_NEW_PATHS, // Access to filesystem paths that were not known at the start of the process 15 | } sandbox_action_t; 16 | 17 | typedef enum sandbox_time_t { 18 | AFTER_SANDBOX, // Check if the action can be performed after entering sandbox 19 | RIGHT_NOW, // Check if the action can be performed right now 20 | } sandbox_time_t; 21 | 22 | // Check if the current process has enough privileges to perform the action 23 | extern bool sandbox_can(sandbox_action_t action, sandbox_time_t when); 24 | 25 | // Set the expected sandbox level. Call sandbox_enter() to actually apply it. 26 | extern void sandbox_set_level(sandbox_level_t level); 27 | 28 | // Enter sandbox using the passed level. Returns true if successful. 29 | // Obviously, this is a one-way function, there's no way to reverse it. 30 | extern bool sandbox_enter(void); 31 | 32 | #endif // TINC_SANDBOX_H 33 | -------------------------------------------------------------------------------- /src/openssl/cipher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_OPENSSL_CIPHER_H 2 | #define TINC_OPENSSL_CIPHER_H 3 | 4 | /* 5 | cipher.h -- header file cipher.c 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | 25 | #include "../legacy.h" 26 | 27 | typedef struct cipher { 28 | EVP_CIPHER_CTX *ctx; 29 | const EVP_CIPHER *cipher; 30 | } cipher_t; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/random.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | 3 | #include "random.h" 4 | 5 | #ifndef HAVE_GETENTROPY 6 | static int random_fd = -1; 7 | #endif 8 | 9 | void random_init(void) { 10 | #ifndef HAVE_GETENTROPY 11 | random_fd = open("/dev/urandom", O_RDONLY); 12 | 13 | if(random_fd < 0) { 14 | random_fd = open("/dev/random", O_RDONLY); 15 | } 16 | 17 | if(random_fd < 0) { 18 | fprintf(stderr, "Could not open source of random numbers: %s\n", strerror(errno)); 19 | abort(); 20 | } 21 | 22 | #endif 23 | } 24 | 25 | void random_exit(void) { 26 | #ifndef HAVE_GETENTROPY 27 | close(random_fd); 28 | #endif 29 | } 30 | 31 | void randomize(void *vout, size_t outlen) { 32 | uint8_t *out = vout; 33 | 34 | while(outlen) { 35 | #ifdef HAVE_GETENTROPY 36 | int reqlen = (int) MIN(256, outlen); 37 | int len = !getentropy(out, reqlen) ? reqlen : -1; 38 | #else 39 | ssize_t len = read(random_fd, out, outlen); 40 | #endif 41 | 42 | if(len <= 0) { 43 | if(len == -1 && (errno == EAGAIN || errno == EINTR)) { 44 | continue; 45 | } 46 | 47 | fprintf(stderr, "Could not read random numbers: %s\n", strerror(errno)); 48 | abort(); 49 | } 50 | 51 | out += len; 52 | outlen -= len; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/gcrypt/pem.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GCRYPT_PEM_H 2 | #define TINC_GCRYPT_PEM_H 3 | 4 | /* 5 | pem.h -- PEM encoding and decoding 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "../system.h" 24 | 25 | bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize); 26 | bool pem_encode(FILE *fp, const char *header, uint8_t *buf, size_t size); 27 | 28 | #endif // TINC_GCRYPT_PEM_H 29 | -------------------------------------------------------------------------------- /test/integration/basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Check that basic functionality works (tincd can be started and stopped).""" 4 | 5 | from testlib.test import Test 6 | from testlib.proc import Tinc 7 | from testlib.feature import SANDBOX_LEVEL 8 | from testlib.log import log 9 | from testlib.script import Script 10 | from testlib import check 11 | 12 | 13 | def init(ctx: Test) -> Tinc: 14 | """Initialize new test nodes.""" 15 | node = ctx.node(init=f"set Sandbox {SANDBOX_LEVEL}") 16 | node.add_script(Script.TINC_UP) 17 | return node 18 | 19 | 20 | def test(ctx: Test, *flags: str) -> None: 21 | """Run tests with flags.""" 22 | log.info("init new node") 23 | node = init(ctx) 24 | 25 | log.info('starting tincd with flags "%s"', " ".join(flags)) 26 | tincd = node.tincd(*flags) 27 | 28 | log.info("waiting for tinc-up script") 29 | node[Script.TINC_UP].wait() 30 | 31 | log.info("stopping tincd") 32 | node.cmd("stop") 33 | 34 | log.info("checking tincd exit code") 35 | check.success(tincd.wait()) 36 | 37 | 38 | with Test("foreground mode") as context: 39 | test(context, "-D") 40 | 41 | with Test("background mode") as context: 42 | test(context) 43 | -------------------------------------------------------------------------------- /test/unit/test_dropin.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | 3 | static const char buf[3]; 4 | 5 | static void test_min(void **state) { 6 | (void)state; 7 | 8 | assert_int_equal(-1, MIN(1, -1)); 9 | assert_int_equal(-2, MIN(1 + 2 * 3, 3 - 2 * 5 / 2)); 10 | 11 | assert_ptr_equal(buf[0], MIN(buf[1], buf[0])); 12 | } 13 | 14 | static void test_max(void **state) { 15 | (void)state; 16 | 17 | assert_int_equal(1, MAX(1, -1)); 18 | assert_int_equal(4, MAX(1 + 3 - 3 / 4 * 5, 10 / 5 + 2 - 2)); 19 | 20 | assert_ptr_equal(buf[1], MAX(buf[1], buf[0])); 21 | } 22 | 23 | static void test_clamp(void **state) { 24 | (void)state; 25 | 26 | assert_int_equal(10, CLAMP(INT_MAX, -10, 10)); 27 | assert_int_equal(-10, CLAMP(INT_MIN, -10, 10)); 28 | assert_int_equal(7, CLAMP(3 + 4, 6, 8)); 29 | 30 | assert_int_equal(5, CLAMP(-1000, 5, 5)); 31 | assert_int_equal(5, CLAMP(0, 5, 5)); 32 | assert_int_equal(5, CLAMP(1000, 5, 5)); 33 | 34 | assert_ptr_equal(buf[1], CLAMP(buf[2], buf[0], buf[1])); 35 | } 36 | 37 | int main(void) { 38 | const struct CMUnitTest tests[] = { 39 | cmocka_unit_test(test_min), 40 | cmocka_unit_test(test_max), 41 | cmocka_unit_test(test_clamp), 42 | }; 43 | return cmocka_run_group_tests(tests, NULL, NULL); 44 | } 45 | -------------------------------------------------------------------------------- /src/gcrypt/digest.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GCRYPT_DIGEST_H 2 | #define TINC_GCRYPT_DIGEST_H 3 | 4 | /* 5 | digest.h -- header file digest.c 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | 25 | #include "../legacy.h" 26 | 27 | typedef enum gcry_md_algos md_algo_t; 28 | 29 | typedef struct digest { 30 | md_algo_t algo; 31 | nid_t nid; 32 | size_t maclength; 33 | gcry_md_hd_t hmac; 34 | } digest_t; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/invitation.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_INVITATION_H 2 | #define TINC_INVITATION_H 3 | 4 | /* 5 | invitation.h -- header for invitation.c. 6 | Copyright (C) 2013-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | int cmd_invite(int argc, char *argv[]); 24 | int cmd_join(int argc, char *argv[]); 25 | 26 | // Wait until data can be read from socket, or a timeout occurs. 27 | // true if socket is ready, false on timeout. 28 | bool wait_socket_recv(int fd); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/bsd/darwin/tunemu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tunemu - Tun device emulation for Darwin 3 | * Copyright (C) 2009 Friedrich Schöller 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #ifndef TUNEMU_H 21 | #define TUNEMU_H 22 | 23 | #include "../../system.h" 24 | 25 | typedef char tunemu_device[7]; 26 | 27 | extern char tunemu_error[]; 28 | 29 | int tunemu_open(tunemu_device dev); 30 | int tunemu_close(int fd); 31 | ssize_t tunemu_read(int fd, uint8_t *buffer, size_t buflen); 32 | ssize_t tunemu_write(uint8_t *buffer, size_t buflen); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/gcrypt/cipher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GCRYPT_CIPHER_H 2 | #define TINC_GCRYPT_CIPHER_H 3 | 4 | /* 5 | cipher.h -- header file cipher.c 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "../system.h" 24 | 25 | #include 26 | 27 | #include "../legacy.h" 28 | 29 | typedef struct cipher { 30 | gcry_cipher_hd_t handle; 31 | uint8_t *key; 32 | nid_t nid; 33 | uint16_t keylen; 34 | uint16_t blklen; 35 | bool padding; 36 | } cipher_t; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/rsagen.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_RSAGEN_H 2 | #define TINC_RSAGEN_H 3 | 4 | /* 5 | rsagen.h -- RSA key generation and export 6 | Copyright (C) 2008-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "rsa.h" 24 | 25 | extern rsa_t *rsa_generate(size_t bits, unsigned long exponent) ATTR_DEALLOCATOR(rsa_free); 26 | extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) ATTR_WARN_UNUSED; 27 | extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) ATTR_WARN_UNUSED; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/cipher.c: -------------------------------------------------------------------------------- 1 | /* 2 | crypto.c -- stub cipher handling functions 3 | Copyright (C) 2007-2022 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "system.h" 21 | 22 | #include "cipher.h" 23 | #include "xalloc.h" 24 | 25 | #ifndef DISABLE_LEGACY 26 | 27 | cipher_t *cipher_alloc(void) { 28 | return xzalloc(sizeof(cipher_t)); 29 | } 30 | 31 | void cipher_free(cipher_t *cipher) { 32 | if(cipher) { 33 | cipher_close(cipher); 34 | free(cipher); 35 | } 36 | } 37 | 38 | #endif // DISABLE_LEGACY 39 | -------------------------------------------------------------------------------- /src/digest.c: -------------------------------------------------------------------------------- 1 | /* 2 | digest.c -- stub digest handling functions 3 | Copyright (C) 2007-2022 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "system.h" 21 | 22 | #include "digest.h" 23 | #include "xalloc.h" 24 | 25 | #ifndef DISABLE_LEGACY 26 | 27 | digest_t *digest_alloc(void) { 28 | return xzalloc(sizeof(digest_t)); 29 | } 30 | 31 | void digest_free(digest_t *digest) { 32 | if(digest) { 33 | digest_close(digest); 34 | free(digest); 35 | } 36 | } 37 | 38 | #endif // DISABLE_LEGACY 39 | -------------------------------------------------------------------------------- /src/gcrypt/rsa.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_GCRYPT_RSA_H 2 | #define TINC_GCRYPT_RSA_H 3 | 4 | /* 5 | rsa.h -- RSA key handling 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | 25 | #include "../rsa.h" 26 | #include "../xalloc.h" 27 | 28 | #define TINC_RSA_INTERNAL 29 | typedef struct rsa { 30 | gcry_mpi_t n; 31 | gcry_mpi_t e; 32 | gcry_mpi_t d; 33 | } rsa_t; 34 | 35 | extern rsa_t *rsa_new(void) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/ecdsagen.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_ECDSAGEN_H 2 | #define TINC_ECDSAGEN_H 3 | 4 | /* 5 | ecdsagen.h -- ECDSA key generation and export 6 | Copyright (C) 2011-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "ecdsa.h" 24 | 25 | extern ecdsa_t *ecdsa_generate(void) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 26 | extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) ATTR_WARN_UNUSED; 27 | extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) ATTR_WARN_UNUSED; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | version.c -- version information 3 | Copyright (C) 2014 Etienne Dechamps 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "version.h" 21 | #include "version_git.h" 22 | 23 | /* This file is always rebuilt (even if there are no changes) so that the following is updated */ 24 | const char *const BUILD_DATE = __DATE__; 25 | const char *const BUILD_TIME = __TIME__; 26 | #ifdef GIT_DESCRIPTION 27 | const char *const BUILD_VERSION = GIT_DESCRIPTION; 28 | #else 29 | const char *const BUILD_VERSION = VERSION; 30 | #endif 31 | -------------------------------------------------------------------------------- /src/openssl/crypto.c: -------------------------------------------------------------------------------- 1 | /* 2 | crypto.c -- Cryptographic miscellaneous functions and initialisation 3 | Copyright (C) 2007-2021 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "../system.h" 21 | 22 | #include 23 | #include 24 | 25 | #include "../crypto.h" 26 | 27 | void crypto_init(void) { 28 | #if OPENSSL_VERSION_MAJOR < 3 29 | ENGINE_load_builtin_engines(); 30 | #endif 31 | 32 | if(!RAND_status()) { 33 | fprintf(stderr, "Not enough entropy for the PRNG!\n"); 34 | abort(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/openssl/digest.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_OPENSSL_DIGEST_H 2 | #define TINC_OPENSSL_DIGEST_H 3 | 4 | /* 5 | digest.h -- header file digest.c 6 | Copyright (C) 2013-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "../legacy.h" 27 | 28 | struct digest { 29 | const EVP_MD *digest; 30 | #if OPENSSL_VERSION_MAJOR < 3 31 | HMAC_CTX *hmac_ctx; 32 | #else 33 | EVP_MAC_CTX *hmac_ctx; 34 | #endif 35 | EVP_MD_CTX *md_ctx; 36 | size_t maclength; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/process.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_PROCESS_H 2 | #define TINC_PROCESS_H 3 | 4 | /* 5 | process.h -- header file for process.c 6 | Copyright (C) 1999-2005 Ivo Timmermans, 7 | 2000-2013 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "system.h" 25 | 26 | extern bool do_detach; 27 | extern bool use_logfile; 28 | extern bool use_syslog; 29 | 30 | extern bool detach(void); 31 | 32 | #ifdef HAVE_WINDOWS 33 | #include "event.h" 34 | 35 | extern io_t stop_io; 36 | extern bool init_service(void); 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/bsd/openbsd/sandbox.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_BSD_OPENBSD_SANDBOX_H 2 | #define TINC_BSD_OPENBSD_SANDBOX_H 3 | 4 | #include "../../system.h" 5 | 6 | typedef struct unveil_path_t { 7 | const char *path; 8 | const char *priv; 9 | } unveil_path_t; 10 | 11 | // No restrictions 12 | static const char *PROMISES_ALL = NULL; 13 | 14 | // Full restrictions; children can call nothing but exit() 15 | static const char *PROMISES_NONE = ""; 16 | 17 | // Allow access to the paths with the specified privileges. Can be called multiple times. 18 | // This is a thin logging wrapper around unveil(2). 19 | // Paths that are equal to NULL are skipped. The last path in the array must be (NULL, NULL). 20 | // Note that after the last call to this function you should lock access to 21 | // unveil(2) using pledge(2) to prevent the program from undoing the sandbox. 22 | extern void allow_paths(const unveil_path_t paths[]); 23 | 24 | // Allow access to a single path. Logging wrapper around unveil(). 25 | extern void allow_path(const char *path, const char *priv); 26 | 27 | // Restrict privileges. Can be called multiple times to further restrict (but not regain) them. 28 | // It's a thin logging wrapper around unveil(2), see man page for details. 29 | extern bool restrict_privs(const char *promises, const char *execpromises); 30 | 31 | #endif // TINC_BSD_OPENBSD_SANDBOX_H 32 | -------------------------------------------------------------------------------- /src/system.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_SYSTEM_H 2 | #define TINC_SYSTEM_H 3 | 4 | /* 5 | system.h -- system headers 6 | Copyright (C) 1998-2005 Ivo Timmermans 7 | 2003-2016 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "config.h" 25 | 26 | #include "have.h" 27 | 28 | #ifndef HAVE_STRSIGNAL 29 | # define strsignal(p) "" 30 | #endif 31 | 32 | #if _____LP64_____ 33 | #define SUBNET_HASH_SIZE 0x10000 34 | #else 35 | #define SUBNET_HASH_SIZE 0x1000 36 | #endif 37 | 38 | /* Other functions */ 39 | 40 | #include "dropin.h" 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/ifconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_IFCONFIG_H 2 | #define TINC_IFCONFIG_H 3 | 4 | /* 5 | ifconfig.h -- header for ifconfig.c. 6 | Copyright (C) 2016 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | extern void ifconfig_dhcp(FILE *out); 26 | extern void ifconfig_dhcp6(FILE *out); 27 | extern void ifconfig_slaac(FILE *out); 28 | extern void ifconfig_address(FILE *out, const char *value); 29 | extern void ifconfig_route(FILE *out, const char *value); 30 | extern void ifconfig_header(FILE *out); 31 | extern bool ifconfig_footer(FILE *out); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/ecdh.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_ECDH_H 2 | #define TINC_ECDH_H 3 | 4 | /* 5 | ecdh.h -- header file for ecdh.c 6 | Copyright (C) 2011-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | #define ECDH_SIZE 32 26 | #define ECDH_SHARED_SIZE 32 27 | 28 | #ifndef TINC_ECDH_INTERNAL 29 | typedef struct ecdh ecdh_t; 30 | #endif 31 | 32 | extern void ecdh_free(ecdh_t *ecdh); 33 | extern ecdh_t *ecdh_generate_public(void *pubkey) ATTR_MALLOC ATTR_DEALLOCATOR(ecdh_free); 34 | extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) ATTR_WARN_UNUSED; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /.ci/package/deb/debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Ivo Timmermans on 2 | Fri, 21 Apr 2000 17:07:50 +0200. 3 | 4 | It was downloaded from http://www.tinc-vpn.org/ 5 | 6 | Upstream Authors: 7 | Guus Sliepen 8 | Ivo Timmermans 9 | 10 | Copyright (C) 1998-2005 Ivo Timmermans 11 | 1998-2008 Guus Sliepen 12 | 13 | This program is free software; you can redistribute it and/or modify 14 | it under the terms of the GNU General Public License as published by 15 | the Free Software Foundation; either version 2 of the License, or 16 | (at your option) any later version. 17 | 18 | On Debian GNU/Linux systems, the complete text of the GNU General Public 19 | License version 2 can be found in /usr/share/common-licenses/GPL-2. 20 | 21 | The following applies to tinc: 22 | 23 | This program is released under the GPL with the additional exemption 24 | that compiling, linking, and/or using OpenSSL is allowed. You may 25 | provide binary packages linked to the OpenSSL libraries, provided that 26 | all other requirements of the GPL are met. 27 | 28 | The following applies to the LZO library: 29 | 30 | Hereby I grant a special exception to the tinc VPN project 31 | (http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library 32 | (http://www.openssl.org). 33 | 34 | Markus F.X.J. Oberhumer 35 | -------------------------------------------------------------------------------- /src/names.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_NAMES_H 2 | #define TINC_NAMES_H 3 | 4 | /* 5 | names.h -- header for names.c 6 | Copyright (C) 1998-2005 Ivo Timmermans 7 | 2000-2017 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "system.h" 25 | 26 | extern char *confdir; 27 | extern char *confbase; 28 | extern bool confbase_given; 29 | extern char *netname; 30 | extern char *myname; 31 | extern char *identname; 32 | extern char *unixsocketname; 33 | extern char *logfilename; 34 | extern char *pidfilename; 35 | extern char *program_name; 36 | 37 | extern void make_names(bool daemon); 38 | extern void free_names(void); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /doc/meson.build: -------------------------------------------------------------------------------- 1 | man_pages = [ 2 | 'tinc-gui.8.in', 3 | 'tinc.8.in', 4 | 'tinc.conf.5.in', 5 | 'tincd.8.in', 6 | ] 7 | 8 | info_pages = [ 9 | 'tinc.texi', 10 | ] 11 | 12 | info_includes = [ 13 | 'tincinclude.texi.in', 14 | ] 15 | 16 | man_conf = configuration_data() 17 | man_conf.set_quoted('PACKAGE', meson.project_name()) 18 | man_conf.set_quoted('VERSION', meson.project_version()) 19 | man_conf.set_quoted('localstatedir', dir_local_state) 20 | man_conf.set_quoted('runstatedir', dir_run_state) 21 | man_conf.set_quoted('sysconfdir', dir_sysconf) 22 | 23 | foreach man_src : man_pages 24 | man = configure_file( 25 | input: man_src, 26 | output: '@BASENAME@', 27 | configuration: man_conf, 28 | ) 29 | install_man(man) 30 | endforeach 31 | 32 | prog_makeinfo = find_program('makeinfo', required: opt_docs) 33 | if not prog_makeinfo.found() 34 | subdir_done() 35 | endif 36 | 37 | foreach inc : info_includes 38 | configure_file( 39 | input: inc, 40 | output: '@BASENAME@', 41 | configuration: man_conf, 42 | ) 43 | endforeach 44 | 45 | info_cmd = [ 46 | prog_makeinfo, 47 | '-P', '@BUILD_ROOT@/doc', 48 | '@INPUT@', 49 | '--output', '@OUTPUT@', 50 | ] 51 | 52 | foreach page : info_pages 53 | custom_target( 54 | 'info-page-' + page, 55 | input: page, 56 | output: '@BASENAME@.info', 57 | command: info_cmd, 58 | install: true, 59 | install_dir: dir_info, 60 | ) 61 | endforeach 62 | 63 | -------------------------------------------------------------------------------- /src/crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_CRYPTO_H 2 | #define TINC_CRYPTO_H 3 | 4 | #include "system.h" 5 | 6 | /* 7 | crypto.h -- header for crypto.c 8 | Copyright (C) 2007-2013 Guus Sliepen 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License along 21 | with this program; if not, write to the Free Software Foundation, Inc., 22 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | */ 24 | 25 | extern void crypto_init(void); 26 | extern uint64_t xoshiro(void); 27 | extern void prng_init(void); 28 | extern void prng_randomize(void *buf, size_t buflen); 29 | 30 | static inline uint32_t prng(uint32_t limit) { 31 | uint64_t bins = UINT64_MAX / limit; 32 | uint64_t reject_after = bins * limit; 33 | uint64_t value; 34 | 35 | do { 36 | value = xoshiro(); 37 | } while(value >= reject_after); 38 | 39 | return value / bins; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /.ci/package/deb/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | . /etc/os-release 6 | 7 | bail() { 8 | echo >&2 "$@" 9 | exit 1 10 | } 11 | 12 | find_tag() { 13 | git describe --always --tags --match='release-*' "$@" 14 | } 15 | 16 | export DEBIAN_FRONTEND=noninteractive 17 | 18 | apt-get install -y devscripts git-buildpackage dh-make 19 | 20 | export USER=${USER:-$(whoami)} 21 | export EMAIL=ci@tinc-vpn.org 22 | 23 | os="$ID-${VERSION_ID:-unknown}" 24 | templates=$(dirname "$0")/debian 25 | 26 | git clean -dfx 27 | 28 | # get latest tag name 29 | curr=$(find_tag HEAD) 30 | [[ -z $curr ]] && bail 'could not determine release version' 31 | 32 | # get previous tag name 33 | prev=$(find_tag "$curr"^) 34 | [[ -z $curr ]] && bail 'could not determine previous release version' 35 | 36 | # strip release prefix to get the current version number 37 | version=${curr//release-/} 38 | 39 | # prepare a new debian directory 40 | dh_make --yes --single --createorig --copyright gpl2 --packagename "tinc_$version-$os" 41 | 42 | # write all commit messages between two most recent tags to the changelog 43 | gbp dch --since "$prev" --ignore-branch --spawn-editor=never --release 44 | 45 | # replace placeholders with files copied from https://packages.debian.org/experimental/tinc 46 | cp "$templates/"* debian/ 47 | 48 | # remove useless READMEs created by dh_make 49 | rm -f debian/README.* 50 | 51 | dpkg-buildpackage -rfakeroot -us -uc -b 52 | mv ../*.deb . 53 | -------------------------------------------------------------------------------- /test/integration/testlib/log.py: -------------------------------------------------------------------------------- 1 | """Global logger for using in test and tincd scripts.""" 2 | 3 | import logging 4 | import os 5 | import sys 6 | import typing as T 7 | from types import TracebackType 8 | 9 | from .path import TEST_WD, TEST_NAME 10 | 11 | logging.basicConfig(level=logging.DEBUG) 12 | 13 | _fmt = logging.Formatter( 14 | "%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s %(message)s" 15 | ) 16 | 17 | # Where to put log files for this test and nodes started by it 18 | _log_dir = os.path.join(TEST_WD, "logs") 19 | 20 | 21 | def new_logger(name: str) -> logging.Logger: 22 | """Create a new named logger with common logging format. 23 | Log entries will go into a separate logfile named 'name.log'. 24 | """ 25 | os.makedirs(_log_dir, exist_ok=True) 26 | 27 | logger = logging.getLogger(name) 28 | logger.setLevel(logging.DEBUG) 29 | 30 | file = logging.FileHandler(os.path.join(_log_dir, name + ".log")) 31 | file.setFormatter(_fmt) 32 | logger.addHandler(file) 33 | 34 | return logger 35 | 36 | 37 | # Main logger used by most tests 38 | log = new_logger(TEST_NAME) 39 | 40 | 41 | def _exc_hook( 42 | ex_type: T.Type[BaseException], 43 | base: BaseException, 44 | tb_type: T.Optional[TracebackType], 45 | ) -> None: 46 | """Logging handler for uncaught exceptions.""" 47 | log.error("Uncaught exception", exc_info=(ex_type, base, tb_type)) 48 | 49 | 50 | sys.excepthook = _exc_hook 51 | -------------------------------------------------------------------------------- /.ci/sanitizers/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | dir=$(realpath "$(dirname "$0")") 6 | 7 | logs="$GITHUB_WORKSPACE/sanitizer" 8 | 9 | case "$SANITIZER" in 10 | undefined) 11 | flags='-fsanitize=integer -fsanitize=nullability -fno-sanitize=unsigned-integer-overflow' 12 | export UBSAN_OPTIONS="log_path=$logs/ubsan:print_stacktrace=1" 13 | ;; 14 | 15 | address) 16 | flags='-fsanitize-address-use-after-scope -fsanitize=pointer-compare -fsanitize=pointer-subtract' 17 | export ASAN_OPTIONS="log_path=$logs/asan:detect_invalid_pointer_pairs=2:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" 18 | export LSAN_OPTIONS="suppressions=$dir/suppress.txt:print_suppressions=0" 19 | ;; 20 | 21 | thread) 22 | flags='' 23 | export TSAN_OPTIONS="log_path=$logs/tsan" 24 | ;; 25 | 26 | *) 27 | echo >&2 "unknown sanitizer $SANITIZER" 28 | exit 1 29 | ;; 30 | esac 31 | 32 | export CC='clang-12' 33 | export CPPFLAGS='-DDEBUG' 34 | export CFLAGS="-O0 -g -fsanitize=$SANITIZER -fno-omit-frame-pointer -fno-common -fsanitize-blacklist=$dir/ignore.txt $flags" 35 | 36 | sudo bash .ci/test/run.sh "$@" 37 | 38 | # Check that the sanitizer has not created any log files. 39 | # If it has, fail the job to notify the developer. 40 | log_count=$(find "$logs" -type f -printf . | wc -c) 41 | 42 | if [ "$log_count" != 0 ]; then 43 | echo "expected zero sanitizer logs, found $log_count" 44 | exit 1 45 | fi 46 | -------------------------------------------------------------------------------- /src/control_common.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_CONTROL_COMMON_H 2 | #define TINC_CONTROL_COMMON_H 3 | 4 | /* 5 | control_protocol.h -- control socket protocol. 6 | Copyright (C) 2007 Scott Lamb 7 | 2009-2012 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "protocol.h" 25 | 26 | enum request_type { 27 | REQ_INVALID = -1, 28 | REQ_STOP = 0, 29 | REQ_RELOAD, 30 | REQ_RESTART, 31 | REQ_DUMP_NODES, 32 | REQ_DUMP_EDGES, 33 | REQ_DUMP_SUBNETS, 34 | REQ_DUMP_CONNECTIONS, 35 | REQ_DUMP_GRAPH, 36 | REQ_PURGE, 37 | REQ_SET_DEBUG, 38 | REQ_RETRY, 39 | REQ_CONNECT, 40 | REQ_DISCONNECT, 41 | REQ_DUMP_TRAFFIC, 42 | REQ_PCAP, 43 | REQ_LOG, 44 | }; 45 | 46 | #define TINC_CTL_VERSION_CURRENT 0 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/ed25519/verify.c: -------------------------------------------------------------------------------- 1 | #include "ed25519.h" 2 | #include "sha512.h" 3 | #include "ge.h" 4 | #include "sc.h" 5 | 6 | static int consttime_equal(const unsigned char *x, const unsigned char *y) { 7 | unsigned char r = 0; 8 | 9 | r = x[0] ^ y[0]; 10 | #define F(i) r |= x[i] ^ y[i] 11 | F(1); 12 | F(2); 13 | F(3); 14 | F(4); 15 | F(5); 16 | F(6); 17 | F(7); 18 | F(8); 19 | F(9); 20 | F(10); 21 | F(11); 22 | F(12); 23 | F(13); 24 | F(14); 25 | F(15); 26 | F(16); 27 | F(17); 28 | F(18); 29 | F(19); 30 | F(20); 31 | F(21); 32 | F(22); 33 | F(23); 34 | F(24); 35 | F(25); 36 | F(26); 37 | F(27); 38 | F(28); 39 | F(29); 40 | F(30); 41 | F(31); 42 | #undef F 43 | 44 | return !r; 45 | } 46 | 47 | int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) { 48 | unsigned char h[64]; 49 | unsigned char checker[32]; 50 | sha512_context hash; 51 | ge_p3 A; 52 | ge_p2 R; 53 | 54 | if(signature[63] & 224) { 55 | return 0; 56 | } 57 | 58 | if(ge_frombytes_negate_vartime(&A, public_key) != 0) { 59 | return 0; 60 | } 61 | 62 | sha512_init(&hash); 63 | sha512_update(&hash, signature, 32); 64 | sha512_update(&hash, public_key, 32); 65 | sha512_update(&hash, message, message_len); 66 | sha512_final(&hash, h); 67 | 68 | sc_reduce(h); 69 | ge_double_scalarmult_vartime(&R, h, &A, signature + 32); 70 | ge_tobytes(checker, &R); 71 | 72 | if(!consttime_equal(checker, signature)) { 73 | return 0; 74 | } 75 | 76 | return 1; 77 | } 78 | -------------------------------------------------------------------------------- /.ci/muon/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Fetch and build 4 | # muon (a C reimplementation of the meson build system), 5 | # samurai (a C reimplementation of the ninja build tool), 6 | # and then use both to build tinc. 7 | 8 | set -euo pipefail 9 | 10 | git_samurai=https://github.com/michaelforney/samurai 11 | git_muon=https://git.sr.ht/~lattis/muon 12 | prefix=/opt/tinc_muon 13 | 14 | header() { 15 | echo >&2 '################################################################################' 16 | echo >&2 "# $*" 17 | echo >&2 '################################################################################' 18 | } 19 | 20 | header 'Try to make sure Python is missing' 21 | python --version && exit 1 22 | python3 --version && exit 1 23 | 24 | header 'Fetch and build samurai' 25 | 26 | git clone --depth=1 $git_samurai ~/samurai 27 | pushd ~/samurai 28 | make -j"$(nproc)" 29 | make install 30 | popd 31 | 32 | header 'Fetch and build muon' 33 | 34 | git clone --depth=1 $git_muon ~/muon 35 | pushd ~/muon 36 | ./bootstrap.sh build 37 | ./build/muon setup build 38 | samu -C build 39 | ./build/muon -C build install 40 | popd 41 | 42 | header 'Setup build directory' 43 | muon setup -D prefix=$prefix -D systemd=disabled build_muon 44 | samu -C build_muon 45 | 46 | header 'Install tinc' 47 | muon -C build_muon install 48 | 49 | header 'Run smoke tests' 50 | $prefix/sbin/tinc --version 51 | $prefix/sbin/tincd --version 52 | $prefix/sbin/tinc -c /tmp/muon_node <, 7 | 2000-2005 Ivo Timmermans 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "connection.h" 25 | 26 | extern bool send_meta(struct connection_t *c, const void *buffer, size_t length); 27 | extern void send_meta_raw(struct connection_t *c, const void *buffer, size_t length); 28 | extern bool send_meta_sptps(void *handle, uint8_t type, const void *data, size_t length); 29 | extern bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t length); 30 | extern void broadcast_meta(struct connection_t *from, const char *buffer, size_t length); 31 | extern bool receive_meta(struct connection_t *c); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/script.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_SCRIPT_H 2 | #define TINC_SCRIPT_H 3 | 4 | /* 5 | script.h -- header file for script.c 6 | Copyright (C) 1999-2005 Ivo Timmermans, 7 | 2000-2017 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "system.h" 25 | 26 | typedef struct environment { 27 | int n; 28 | int size; 29 | char **entries; 30 | } environment_t; 31 | 32 | extern int environment_add(environment_t *env, const char *format, ...) ATTR_FORMAT(printf, 2, 3); 33 | extern void environment_update(environment_t *env, int pos, const char *format, ...) ATTR_FORMAT(printf, 3, 4); 34 | extern void environment_init(environment_t *env); 35 | extern void environment_exit(environment_t *env); 36 | 37 | extern bool execute_script(const char *name, environment_t *env); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /test/integration/testlib/event.py: -------------------------------------------------------------------------------- 1 | """Classes for doing data exchange between test and tincd scripts.""" 2 | 3 | import os 4 | import sys 5 | import time 6 | import platform 7 | import typing as T 8 | 9 | _MONOTONIC_IS_SYSTEMWIDE = not ( 10 | platform.system() == "Darwin" and sys.version_info < (3, 10) 11 | ) 12 | 13 | 14 | def _time_ns() -> int: 15 | if sys.version_info <= (3, 7): 16 | return int(time.monotonic() * 1e9) 17 | return time.monotonic_ns() 18 | 19 | 20 | class Notification: 21 | """Notification about tinc script execution.""" 22 | 23 | test: str 24 | node: str 25 | script: str 26 | created_at: T.Optional[int] = None 27 | env: T.Dict[str, str] 28 | args: T.Dict[str, str] 29 | error: T.Optional[Exception] 30 | 31 | def __init__(self) -> None: 32 | self.env = dict(os.environ) 33 | 34 | # This field is used to record when the notification was created. On most 35 | # operating systems, it uses system-wide monotonic time which is the same 36 | # for all processes. Not on macOS, at least not before Python 3.10. So if 37 | # we're running such a setup, assign time local to our test process right 38 | # when we receive the notification to have a common reference point to 39 | # all measurements. 40 | if _MONOTONIC_IS_SYSTEMWIDE: 41 | self.update_time() 42 | 43 | def __str__(self) -> str: 44 | return f"{self.test}/{self.node}/{self.script}" 45 | 46 | def update_time(self) -> None: 47 | """Update creation time if it was not assigned previously.""" 48 | if self.created_at is None: 49 | self.created_at = _time_ns() 50 | -------------------------------------------------------------------------------- /.ci/package/rpm/tinc.spec: -------------------------------------------------------------------------------- 1 | Name: tinc 2 | Version: __VERSION__ 3 | Release: 3%{?dist} 4 | Summary: A virtual private network daemon 5 | 6 | License: GPLv2+ 7 | URL: https://www.tinc-vpn.org/ 8 | 9 | BuildRequires: gcc 10 | BuildRequires: meson 11 | BuildRequires: systemd 12 | BuildRequires: openssl-devel 13 | BuildRequires: lzo-devel 14 | BuildRequires: zlib-devel 15 | BuildRequires: lz4-devel 16 | BuildRequires: ncurses-devel 17 | BuildRequires: readline-devel 18 | 19 | Requires(post): systemd 20 | Requires(preun): systemd 21 | Requires(postun): systemd 22 | 23 | %description 24 | tinc is a Virtual Private Network (VPN) daemon that uses tunnelling 25 | and encryption to create a secure private network between hosts on 26 | the Internet. Because the tunnel appears to the IP level network 27 | code as a normal network device, there is no need to adapt any 28 | existing software. This tunnelling allows VPN sites to share 29 | information with each other over the Internet without exposing any 30 | information to others. 31 | 32 | %define debug_package %{nil} 33 | %define __meson_auto_features auto 34 | 35 | %prep 36 | 37 | %build 38 | %meson 39 | %meson_build 40 | 41 | %install 42 | %meson_install 43 | 44 | %post 45 | %systemd_post %{name}@.service 46 | 47 | %preun 48 | %systemd_preun %{name}@.service 49 | 50 | %postun 51 | %systemd_postun_with_restart %{name}@.service 52 | 53 | %files 54 | %doc AUTHORS COPYING.README NEWS README.md THANKS doc/sample* 55 | %license COPYING 56 | %{_mandir}/man*/%{name}*.* 57 | %{_infodir}/%{name}.info.* 58 | %{_sbindir}/%{name} 59 | %{_sbindir}/%{name}d 60 | %{_unitdir}/%{name}*.service 61 | %{_datadir}/bash-completion/completions/%{name} 62 | -------------------------------------------------------------------------------- /src/ed25519/ecdh.c: -------------------------------------------------------------------------------- 1 | /* 2 | ecdh.c -- Diffie-Hellman key exchange handling 3 | Copyright (C) 2011-2013 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "../system.h" 21 | #include "../random.h" 22 | 23 | #include "ed25519.h" 24 | 25 | #define TINC_ECDH_INTERNAL 26 | typedef struct ecdh_t { 27 | uint8_t private[64]; 28 | } ecdh_t; 29 | 30 | #include "../ecdh.h" 31 | #include "../xalloc.h" 32 | 33 | ecdh_t *ecdh_generate_public(void *pubkey) { 34 | ecdh_t *ecdh = xzalloc(sizeof(*ecdh)); 35 | 36 | uint8_t seed[32]; 37 | randomize(seed, sizeof(seed)); 38 | ed25519_create_keypair(pubkey, ecdh->private, seed); 39 | memzero(seed, sizeof(seed)); 40 | 41 | return ecdh; 42 | } 43 | 44 | bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) { 45 | ed25519_key_exchange(shared, pubkey, ecdh->private); 46 | ecdh_free(ecdh); 47 | return true; 48 | } 49 | 50 | void ecdh_free(ecdh_t *ecdh) { 51 | xzfree(ecdh, sizeof(ecdh_t)); 52 | } 53 | -------------------------------------------------------------------------------- /test/integration/testlib/template/script.py.tpl: -------------------------------------------------------------------------------- 1 | #!$PYTHON_PATH 2 | 3 | import os 4 | import sys 5 | import multiprocessing.connection as mpc 6 | import typing as T 7 | import time 8 | import signal 9 | 10 | def on_error(*args): 11 | try: 12 | log.error('Uncaught exception', exc_info=args) 13 | except NameError: 14 | print('Uncaught exception', args) 15 | os.kill(0, signal.SIGTERM) 16 | 17 | sys.excepthook = on_error 18 | 19 | os.chdir(r'$CWD') 20 | sys.path.append(r'$SRC_ROOT') 21 | 22 | from testlib.proc import Tinc 23 | from testlib.event import Notification 24 | from testlib.log import new_logger 25 | from testlib.const import MPC_FAMILY 26 | 27 | this = Tinc('$NODE_NAME') 28 | log = new_logger(this.name) 29 | 30 | def notify_test(args: T.Dict[str, T.Any] = {}, error: T.Optional[Exception] = None): 31 | log.debug(f'sending notification to %s', $NOTIFICATIONS_ADDR) 32 | 33 | evt = Notification() 34 | evt.test = '$TEST_NAME' 35 | evt.node = '$NODE_NAME' 36 | evt.script = '$SCRIPT_NAME' 37 | evt.args = args 38 | evt.error = error 39 | 40 | for retry in range(1, 10): 41 | try: 42 | with mpc.Client($NOTIFICATIONS_ADDR, family=MPC_FAMILY, authkey=$AUTH_KEY) as conn: 43 | conn.send(evt) 44 | log.debug(f'sent notification') 45 | break 46 | except Exception as ex: 47 | log.error(f'notification failed', exc_info=ex) 48 | time.sleep(0.5) 49 | 50 | try: 51 | log.debug('running user code') 52 | $SCRIPT_SOURCE 53 | log.debug('user code finished') 54 | except Exception as ex: 55 | log.error('user code failed', exc_info=ex) 56 | notify_test(error=ex) 57 | sys.exit(1) 58 | 59 | notify_test() 60 | -------------------------------------------------------------------------------- /test/unit/test_net.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/net.h" 3 | #include "../../src/script.h" 4 | 5 | static environment_t *device_env = NULL; 6 | 7 | // silence -Wmissing-prototypes 8 | void __wrap_environment_init(environment_t *env); 9 | void __wrap_environment_exit(environment_t *env); 10 | bool __wrap_execute_script(const char *name, environment_t *env); 11 | 12 | void __wrap_environment_init(environment_t *env) { 13 | assert_non_null(env); 14 | assert_null(device_env); 15 | device_env = env; 16 | } 17 | 18 | void __wrap_environment_exit(environment_t *env) { 19 | assert_ptr_equal(device_env, env); 20 | device_env = NULL; 21 | } 22 | 23 | bool __wrap_execute_script(const char *name, environment_t *env) { 24 | (void)env; 25 | 26 | check_expected_ptr(name); 27 | 28 | // Used instead of mock_type(bool) to silence clang warning 29 | return mock() ? true : false; 30 | } 31 | 32 | static void run_device_enable_disable(void (*device_func)(void), 33 | const char *script) { 34 | expect_string(__wrap_execute_script, name, script); 35 | will_return(__wrap_execute_script, true); 36 | 37 | device_func(); 38 | } 39 | 40 | static void test_device_enable_calls_tinc_up(void **state) { 41 | (void)state; 42 | 43 | run_device_enable_disable(&device_enable, "tinc-up"); 44 | } 45 | 46 | static void test_device_disable_calls_tinc_down(void **state) { 47 | (void)state; 48 | 49 | run_device_enable_disable(&device_disable, "tinc-down"); 50 | } 51 | 52 | int main(void) { 53 | const struct CMUnitTest tests[] = { 54 | cmocka_unit_test(test_device_enable_calls_tinc_up), 55 | cmocka_unit_test(test_device_disable_calls_tinc_down), 56 | }; 57 | return cmocka_run_group_tests(tests, NULL, NULL); 58 | } 59 | -------------------------------------------------------------------------------- /src/device.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_DEVICE_H 2 | #define TINC_DEVICE_H 3 | 4 | /* 5 | device.h -- generic header for device.c 6 | Copyright (C) 2001-2005 Ivo Timmermans 7 | 2001-2012 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "net.h" 25 | 26 | extern int device_fd; 27 | extern char *device; 28 | extern char *iface; 29 | 30 | #define DEVICE_DUMMY "dummy" 31 | 32 | typedef struct devops_t { 33 | bool (*setup)(void); 34 | void (*close)(void); 35 | bool (*read)(struct vpn_packet_t *); 36 | bool (*write)(struct vpn_packet_t *); 37 | void (*enable)(void); /* optional */ 38 | void (*disable)(void); /* optional */ 39 | } devops_t; 40 | 41 | extern const devops_t os_devops; 42 | extern const devops_t dummy_devops; 43 | extern const devops_t raw_socket_devops; 44 | extern const devops_t multicast_devops; 45 | extern const devops_t fd_devops; 46 | extern const devops_t uml_devops; 47 | extern const devops_t vde_devops; 48 | extern devops_t devops; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/rsa.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_RSA_H 2 | #define TINC_RSA_H 3 | 4 | /* 5 | rsa.h -- RSA key handling 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | #ifndef TINC_RSA_INTERNAL 26 | typedef struct rsa rsa_t; 27 | #endif 28 | 29 | extern void rsa_free(rsa_t *rsa); 30 | extern rsa_t *rsa_set_hex_public_key(const char *n, const char *e) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 31 | extern rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 32 | extern rsa_t *rsa_read_pem_public_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 33 | extern rsa_t *rsa_read_pem_private_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(rsa_free); 34 | extern size_t rsa_size(const rsa_t *rsa); 35 | extern bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) ATTR_WARN_UNUSED; 36 | extern bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) ATTR_WARN_UNUSED; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /test/unit/test_xalloc.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/xalloc.h" 3 | 4 | static const uint8_t ref[] = {0, 1, 2, 3, 4, 5, 6, 7}; 5 | 6 | static void test_memzero_wipes_partial(void **state) { 7 | (void)state; 8 | 9 | uint8_t buf[sizeof(ref)]; 10 | memcpy(buf, ref, sizeof(buf)); 11 | 12 | const size_t len = 2; 13 | memzero(buf, len); 14 | assert_int_equal(0, buf[0]); 15 | assert_int_equal(0, buf[1]); 16 | 17 | assert_memory_equal(&buf[len], &ref[len], sizeof(ref) - len); 18 | } 19 | 20 | static void test_memzero_wipes_buffer(void **state) { 21 | (void)state; 22 | 23 | uint8_t buf[sizeof(ref)]; 24 | uint8_t zero[sizeof(ref)] = {0}; 25 | 26 | memcpy(buf, ref, sizeof(buf)); 27 | assert_memory_equal(ref, buf, sizeof(buf)); 28 | 29 | memzero(buf, sizeof(buf)); 30 | assert_memory_not_equal(buf, ref, sizeof(buf)); 31 | assert_memory_equal(zero, buf, sizeof(buf)); 32 | } 33 | 34 | static void test_memzero_zerolen_does_not_change_memory(void **state) { 35 | (void)state; 36 | 37 | uint8_t buf[sizeof(ref)]; 38 | 39 | memcpy(buf, ref, sizeof(buf)); 40 | assert_memory_equal(ref, buf, sizeof(buf)); 41 | 42 | memzero(buf, 0); 43 | assert_memory_equal(ref, buf, sizeof(buf)); 44 | } 45 | 46 | // This test will fail under ASAN if xzfree forgets to call free() or overflows the buffer 47 | static void test_xzfree_frees_memory(void **state) { 48 | (void)state; 49 | 50 | xzfree(xmalloc(64), 64); 51 | } 52 | 53 | int main(void) { 54 | const struct CMUnitTest tests[] = { 55 | cmocka_unit_test(test_memzero_wipes_partial), 56 | cmocka_unit_test(test_memzero_wipes_buffer), 57 | cmocka_unit_test(test_memzero_zerolen_does_not_change_memory), 58 | cmocka_unit_test(test_xzfree_frees_memory), 59 | }; 60 | return cmocka_run_group_tests(tests, NULL, NULL); 61 | } 62 | -------------------------------------------------------------------------------- /src/route.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_ROUTE_H 2 | #define TINC_ROUTE_H 3 | 4 | /* 5 | route.h -- header file for route.c 6 | Copyright (C) 2000-2005 Ivo Timmermans 7 | 2000-2012 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "net.h" 25 | #include "node.h" 26 | 27 | typedef enum rmode_t { 28 | RMODE_HUB = 0, 29 | RMODE_SWITCH, 30 | RMODE_ROUTER, 31 | } rmode_t; 32 | 33 | typedef enum fmode_t { 34 | FMODE_OFF = 0, 35 | FMODE_INTERNAL, 36 | FMODE_KERNEL, 37 | } fmode_t; 38 | 39 | typedef enum bmode_t { 40 | BMODE_NONE = 0, 41 | BMODE_MST, 42 | BMODE_DIRECT, 43 | } bmode_t; 44 | 45 | extern rmode_t routing_mode; 46 | extern fmode_t forwarding_mode; 47 | extern bmode_t broadcast_mode; 48 | extern bool decrement_ttl; 49 | extern bool directonly; 50 | extern bool overwrite_mac; 51 | extern bool priorityinheritance; 52 | extern int macexpire; 53 | extern bool pcap; 54 | 55 | extern mac_t mymac; 56 | 57 | extern void route(struct node_t *source, struct vpn_packet_t *packet); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/dummy_device.c: -------------------------------------------------------------------------------- 1 | /* 2 | device.c -- Dummy device 3 | Copyright (C) 2011-2012 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "system.h" 21 | 22 | #include "device.h" 23 | #include "logger.h" 24 | #include "net.h" 25 | #include "xalloc.h" 26 | 27 | static const char *device_info = "dummy device"; 28 | 29 | static bool setup_device(void) { 30 | device = xstrdup(DEVICE_DUMMY); 31 | iface = xstrdup(DEVICE_DUMMY); 32 | logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info); 33 | return true; 34 | } 35 | 36 | static void close_device(void) { 37 | free(iface); 38 | iface = NULL; 39 | free(device); 40 | device = NULL; 41 | } 42 | 43 | static bool read_packet(vpn_packet_t *packet) { 44 | (void)packet; 45 | return false; 46 | } 47 | 48 | static bool write_packet(vpn_packet_t *packet) { 49 | (void)packet; 50 | return true; 51 | } 52 | 53 | const devops_t dummy_devops = { 54 | .setup = setup_device, 55 | .close = close_device, 56 | .read = read_packet, 57 | .write = write_packet, 58 | }; 59 | -------------------------------------------------------------------------------- /src/ecdsa.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_ECDSA_H 2 | #define TINC_ECDSA_H 3 | 4 | /* 5 | ecdsa.h -- ECDSA key handling 6 | Copyright (C) 2011-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | #ifndef TINC_ECDSA_INTERNAL 26 | typedef struct ecdsa ecdsa_t; 27 | #endif 28 | 29 | extern void ecdsa_free(ecdsa_t *ecdsa); 30 | extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 31 | extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 32 | extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free); 33 | extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) ATTR_MALLOC; 34 | extern size_t ecdsa_size(ecdsa_t *ecdsa); 35 | extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) ATTR_WARN_UNUSED; 36 | extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) ATTR_WARN_UNUSED; 37 | extern bool ecdsa_active(ecdsa_t *ecdsa); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /test/integration/testlib/test.py: -------------------------------------------------------------------------------- 1 | """Test context that wraps Tinc instances and terminates them on exit.""" 2 | 3 | import typing as T 4 | 5 | from .log import log 6 | from .proc import Tinc 7 | 8 | 9 | class Test: 10 | """Test context. Allows you to obtain Tinc instances which are automatically 11 | stopped (and killed if necessary) at __exit__. Should be wrapped in `with` 12 | statements (like the built-in `open`). Should be used sparingly (as it usually 13 | happens, thanks to Windows: service registration and removal is quite slow, 14 | which makes tests take a long time to run, especially on modest CI VMs). 15 | """ 16 | 17 | name: str 18 | _nodes: T.List[Tinc] 19 | 20 | def __init__(self, name: str) -> None: 21 | self._nodes = [] 22 | self.name = name 23 | 24 | def node(self, addr: str = "", init: T.Union[str, bool] = "") -> Tinc: 25 | """Create a Tinc instance and remember it for termination on exit.""" 26 | node = Tinc(addr=addr) 27 | self._nodes.append(node) 28 | if init: 29 | if isinstance(init, bool): 30 | init = "" 31 | stdin = f""" 32 | init {node} 33 | set Port 0 34 | set Address localhost 35 | set DeviceType dummy 36 | {init} 37 | """ 38 | node.cmd(stdin=stdin) 39 | return node 40 | 41 | def __str__(self) -> str: 42 | return self.name 43 | 44 | def __enter__(self) -> "Test": 45 | log.info("RUNNING TEST: %s", self.name) 46 | return self 47 | 48 | def __exit__(self, exc_type, exc_val, exc_tb) -> None: 49 | for node in self._nodes: 50 | node.cleanup() 51 | log.info("FINISHED TEST: %s", self.name) 52 | -------------------------------------------------------------------------------- /src/address_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_ADDRESS_CACHE_H 2 | #define TINC_ADDRESS_CACHE_H 3 | 4 | /* 5 | address_cache.h -- header for address_cache.c 6 | Copyright (C) 2018 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "net.h" 24 | 25 | #define MAX_CACHED_ADDRESSES 8 26 | #define ADDRESS_CACHE_VERSION 1 27 | 28 | typedef struct address_cache_t { 29 | struct node_t *node; 30 | struct splay_tree_t *config_tree; 31 | struct config_t *cfg; 32 | struct addrinfo *ai; 33 | struct addrinfo *aip; 34 | unsigned int tried; 35 | 36 | struct { 37 | unsigned int version; 38 | unsigned int used; 39 | sockaddr_t address[MAX_CACHED_ADDRESSES]; 40 | } data; 41 | } address_cache_t; 42 | 43 | void add_recent_address(address_cache_t *cache, const sockaddr_t *sa); 44 | const sockaddr_t *get_recent_address(address_cache_t *cache); 45 | 46 | void close_address_cache(address_cache_t *cache); 47 | address_cache_t *open_address_cache(node_t *node) ATTR_DEALLOCATOR(close_address_cache); 48 | void reset_address_cache(address_cache_t *cache); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/ed25519/key_exchange.c: -------------------------------------------------------------------------------- 1 | #include "ed25519.h" 2 | #include "fe.h" 3 | 4 | void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) { 5 | unsigned char e[32]; 6 | unsigned int i; 7 | 8 | fe x1; 9 | fe x2; 10 | fe z2; 11 | fe x3; 12 | fe z3; 13 | fe tmp0; 14 | fe tmp1; 15 | 16 | int pos; 17 | unsigned int swap; 18 | unsigned int b; 19 | 20 | /* copy the private key and make sure it's valid */ 21 | for(i = 0; i < 32; ++i) { 22 | e[i] = private_key[i]; 23 | } 24 | 25 | e[0] &= 248; 26 | e[31] &= 63; 27 | e[31] |= 64; 28 | 29 | /* unpack the public key and convert edwards to montgomery */ 30 | /* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */ 31 | fe_frombytes(x1, public_key); 32 | fe_1(tmp1); 33 | fe_add(tmp0, x1, tmp1); 34 | fe_sub(tmp1, tmp1, x1); 35 | fe_invert(tmp1, tmp1); 36 | fe_mul(x1, tmp0, tmp1); 37 | 38 | fe_1(x2); 39 | fe_0(z2); 40 | fe_copy(x3, x1); 41 | fe_1(z3); 42 | 43 | swap = 0; 44 | 45 | for(pos = 254; pos >= 0; --pos) { 46 | b = e[pos / 8] >> (pos & 7); 47 | b &= 1; 48 | swap ^= b; 49 | fe_cswap(x2, x3, swap); 50 | fe_cswap(z2, z3, swap); 51 | swap = b; 52 | 53 | /* from montgomery.h */ 54 | fe_sub(tmp0, x3, z3); 55 | fe_sub(tmp1, x2, z2); 56 | fe_add(x2, x2, z2); 57 | fe_add(z2, x3, z3); 58 | fe_mul(z3, tmp0, x2); 59 | fe_mul(z2, z2, tmp1); 60 | fe_sq(tmp0, tmp1); 61 | fe_sq(tmp1, x2); 62 | fe_add(x3, z3, z2); 63 | fe_sub(z2, z3, z2); 64 | fe_mul(x2, tmp1, tmp0); 65 | fe_sub(tmp1, tmp1, tmp0); 66 | fe_sq(z2, z2); 67 | fe_mul121666(z3, tmp1); 68 | fe_sq(x3, x3); 69 | fe_add(tmp0, tmp0, z3); 70 | fe_mul(z3, x1, z2); 71 | fe_mul(z2, tmp1, tmp0); 72 | } 73 | 74 | fe_cswap(x2, x3, swap); 75 | fe_cswap(z2, z3, swap); 76 | 77 | fe_invert(z2, z2); 78 | fe_mul(x2, x2, z2); 79 | fe_tobytes(shared_secret, x2); 80 | } 81 | -------------------------------------------------------------------------------- /test/integration/testlib/template.py: -------------------------------------------------------------------------------- 1 | """Various script and configuration file templates.""" 2 | 3 | import os 4 | import typing as T 5 | from string import Template 6 | 7 | from . import path 8 | from .notification import notifications 9 | 10 | 11 | _CMD_VARS = os.linesep.join([f"set {var}={val}" for var, val in path.env.items()]) 12 | 13 | 14 | def _read_template(tpl_name: str, maps: T.Dict[str, T.Any]) -> str: 15 | tpl_path = path.TESTLIB_ROOT.joinpath("template", tpl_name) 16 | tpl = Template(tpl_path.read_text(encoding="utf-8")) 17 | return tpl.substitute(maps) 18 | 19 | 20 | def make_script(node: str, script: str, source: str) -> str: 21 | """Create a tincd script.""" 22 | addr = notifications.address 23 | if isinstance(addr, str): 24 | addr = f'r"{addr}"' # 'r' is for Windows pipes: \\.\foo\bar 25 | maps = { 26 | "AUTH_KEY": notifications.authkey, 27 | "CWD": path.CWD, 28 | "NODE_NAME": node, 29 | "NOTIFICATIONS_ADDR": addr, 30 | "PYTHON_PATH": path.PYTHON_PATH, 31 | "SCRIPT_NAME": script, 32 | "SCRIPT_SOURCE": source, 33 | "SRC_ROOT": path.TEST_SRC_ROOT, 34 | "TEST_NAME": path.TEST_NAME, 35 | } 36 | return _read_template("script.py.tpl", maps) 37 | 38 | 39 | def make_cmd_wrap(script: str) -> str: 40 | """Create a .cmd wrapper for tincd script. Only makes sense on Windows.""" 41 | maps = { 42 | "PYTHON_CMD": path.PYTHON_CMD, 43 | "PYTHON_PATH": path.PYTHON_PATH, 44 | "SCRIPT_PATH": script, 45 | "VARIABLES": _CMD_VARS, 46 | } 47 | return _read_template("script.cmd.tpl", maps) 48 | 49 | 50 | def make_netns_config(namespace: str, ip_addr: str, mask: int) -> str: 51 | """Create a tincd script that does network namespace configuration.""" 52 | maps = {"NAMESPACE": namespace, "ADDRESS": ip_addr, "MASK": mask} 53 | return _read_template("netns.py.tpl", maps) 54 | -------------------------------------------------------------------------------- /src/xoshiro.c: -------------------------------------------------------------------------------- 1 | /* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) 2 | 3 | To the extent possible under law, the author has dedicated all copyright 4 | and related and neighboring rights to this software to the public domain 5 | worldwide. This software is distributed without any warranty. 6 | 7 | See . */ 8 | 9 | #include "system.h" 10 | 11 | #include "crypto.h" 12 | #include "random.h" 13 | 14 | /* This is xoshiro256** 1.0, one of our all-purpose, rock-solid 15 | generators. It has excellent (sub-ns) speed, a state (256 bits) that is 16 | large enough for any parallel application, and it passes all tests we 17 | are aware of. 18 | 19 | For generating just floating-point numbers, xoshiro256+ is even faster. 20 | 21 | The state must be seeded so that it is not everywhere zero. If you have 22 | a 64-bit seed, we suggest to seed a splitmix64 generator and use its 23 | output to fill s. */ 24 | 25 | static inline uint64_t rotl(const uint64_t x, int k) { 26 | return (x << k) | (x >> (64 - k)); 27 | } 28 | 29 | static uint64_t s[4]; 30 | 31 | uint64_t xoshiro(void) { 32 | const uint64_t result = rotl(s[1] * 5, 7) * 9; 33 | 34 | const uint64_t t = s[1] << 17; 35 | 36 | s[2] ^= s[0]; 37 | s[3] ^= s[1]; 38 | s[1] ^= s[2]; 39 | s[0] ^= s[3]; 40 | 41 | s[2] ^= t; 42 | 43 | s[3] = rotl(s[3], 45); 44 | 45 | return result; 46 | } 47 | 48 | void prng_init(void) { 49 | do { 50 | randomize(s, sizeof(s)); 51 | } while(!s[0] && !s[1] && !s[2] && !s[3]); 52 | } 53 | 54 | void prng_randomize(void *buf, size_t buflen) { 55 | uint8_t *p = buf; 56 | uint64_t value; 57 | 58 | while(buflen > sizeof(value)) { 59 | value = xoshiro(); 60 | memcpy(p, &value, sizeof(value)); 61 | p += sizeof(value); 62 | buflen -= sizeof(value); 63 | } 64 | 65 | if(!buflen) { 66 | return; 67 | } 68 | 69 | value = xoshiro(); 70 | memcpy(p, &value, buflen); 71 | } 72 | -------------------------------------------------------------------------------- /test/integration/algorithms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Check that legacy protocol works with different cryptographic algorithms.""" 4 | 5 | import typing as T 6 | 7 | from testlib.test import Test 8 | from testlib.proc import Tinc 9 | from testlib.log import log 10 | from testlib import cmd, check 11 | 12 | 13 | def init(ctx: Test, digest: str, cipher: str) -> T.Tuple[Tinc, Tinc]: 14 | """Initialize new test nodes.""" 15 | foo, bar = ctx.node(), ctx.node() 16 | 17 | stdin = f""" 18 | init {foo} 19 | set Port 0 20 | set DeviceType dummy 21 | set Address localhost 22 | set ExperimentalProtocol no 23 | set Digest {digest} 24 | set Cipher {cipher} 25 | """ 26 | foo.cmd(stdin=stdin) 27 | foo.start() 28 | 29 | stdin = f""" 30 | init {bar} 31 | set Port 0 32 | set DeviceType dummy 33 | set Address localhost 34 | set ExperimentalProtocol no 35 | set Digest {digest} 36 | set Cipher {cipher} 37 | """ 38 | bar.cmd(stdin=stdin) 39 | 40 | foo.add_script(bar.script_up) 41 | bar.add_script(foo.script_up) 42 | 43 | cmd.exchange(foo, bar) 44 | bar.cmd("add", "ConnectTo", foo.name) 45 | bar.cmd("start") 46 | 47 | return foo, bar 48 | 49 | 50 | def test(foo: Tinc, bar: Tinc) -> None: 51 | """Run tests on algorithm pair.""" 52 | log.info("waiting for bar to come up") 53 | foo[bar.script_up].wait() 54 | 55 | log.info("waiting for foo to come up") 56 | bar[foo.script_up].wait() 57 | 58 | log.info("checking node reachability") 59 | stdout, _ = foo.cmd("info", bar.name) 60 | check.is_in("reachable", stdout) 61 | 62 | 63 | for alg_digest in "none", "sha256", "sha512": 64 | for alg_cipher in "none", "aes-256-cbc": 65 | with Test("compression") as context: 66 | node0, node1 = init(context, alg_digest, alg_cipher) 67 | test(node0, node1) 68 | -------------------------------------------------------------------------------- /.ci/test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | bail() { 6 | echo >&2 "@" 7 | exit 1 8 | } 9 | 10 | header() { 11 | echo '################################################################################' 12 | echo "# $*" 13 | echo '################################################################################' 14 | } 15 | 16 | run_tests() { 17 | flavor="$1" 18 | shift 19 | 20 | header "Cleaning up leftovers from previous runs" 21 | 22 | for name in tinc tincd; do 23 | sudo pkill -TERM -x "$name" || true 24 | sudo pkill -KILL -x "$name" || true 25 | done 26 | 27 | if [ "$(id -u)" != 0 ]; then 28 | sudo chown -R "${USER:-$(whoami)}" . || true 29 | fi 30 | 31 | mkdir -p sanitizer /tmp/logs 32 | 33 | header "Running test flavor $flavor" 34 | 35 | ./.ci/build.sh "$flavor" "$@" 36 | 37 | if [ "${HOST:-}" = mingw ]; then 38 | echo >&2 "Integration tests cannot run under wine, skipping" 39 | return 0 40 | fi 41 | 42 | if [ -n "${HOST:-}" ]; then 43 | echo >&2 "Using higher test timeout for cross-compilation job $HOST" 44 | timeout=10 45 | else 46 | timeout=1 47 | fi 48 | 49 | code=0 50 | meson test -C "$flavor" --timeout-multiplier $timeout --verbose || code=$? 51 | 52 | sudo tar -c -z -f "/tmp/logs/tests.$flavor.tar.gz" "$flavor" sanitizer/ || true 53 | 54 | return $code 55 | } 56 | 57 | case "$(uname -s)" in 58 | MINGW* | Darwin) sudo() { "$@"; } ;; 59 | esac 60 | 61 | flavor=$1 62 | shift 63 | 64 | case "$flavor" in 65 | default) 66 | run_tests default "$@" 67 | ;; 68 | nolegacy) 69 | run_tests nolegacy -Dcrypto=nolegacy "$@" 70 | ;; 71 | gcrypt) 72 | run_tests gcrypt -Dcrypto=gcrypt "$@" 73 | ;; 74 | openssl3) 75 | if [ -d /opt/ssl3 ]; then 76 | run_tests openssl3 -Dpkg_config_path=/opt/ssl3/lib64/pkgconfig "$@" 77 | else 78 | echo >&2 "OpenSSL 3 not installed, skipping test" 79 | fi 80 | ;; 81 | *) 82 | bail "unknown test flavor $1" 83 | ;; 84 | esac 85 | -------------------------------------------------------------------------------- /src/ed25519/ge.h: -------------------------------------------------------------------------------- 1 | #ifndef GE_H 2 | #define GE_H 3 | 4 | #include "fe.h" 5 | 6 | 7 | /* 8 | ge means group element. 9 | 10 | Here the group is the set of pairs (x,y) of field elements (see fe.h) 11 | satisfying -x^2 + y^2 = 1 + d x^2y^2 12 | where d = -121665/121666. 13 | 14 | Representations: 15 | ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z 16 | ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT 17 | ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T 18 | ge_precomp (Duif): (y+x,y-x,2dxy) 19 | */ 20 | 21 | typedef struct { 22 | fe X; 23 | fe Y; 24 | fe Z; 25 | } ge_p2; 26 | 27 | typedef struct { 28 | fe X; 29 | fe Y; 30 | fe Z; 31 | fe T; 32 | } ge_p3; 33 | 34 | typedef struct { 35 | fe X; 36 | fe Y; 37 | fe Z; 38 | fe T; 39 | } ge_p1p1; 40 | 41 | typedef struct { 42 | fe yplusx; 43 | fe yminusx; 44 | fe xy2d; 45 | } ge_precomp; 46 | 47 | typedef struct { 48 | fe YplusX; 49 | fe YminusX; 50 | fe Z; 51 | fe T2d; 52 | } ge_cached; 53 | 54 | void ge_p3_tobytes(unsigned char *s, const ge_p3 *h); 55 | void ge_tobytes(unsigned char *s, const ge_p2 *h); 56 | int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s); 57 | 58 | void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); 59 | void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); 60 | void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b); 61 | void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q); 62 | void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q); 63 | void ge_scalarmult_base(ge_p3 *h, const unsigned char *a); 64 | 65 | void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p); 66 | void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p); 67 | void ge_p2_0(ge_p2 *h); 68 | void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p); 69 | void ge_p3_0(ge_p3 *h); 70 | void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p); 71 | void ge_p3_to_cached(ge_cached *r, const ge_p3 *p); 72 | void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /doc/tinc-gui.8.in: -------------------------------------------------------------------------------- 1 | .Dd 2011-06-26 2 | .Dt TINC-GUI 8 3 | .\" Manual page created by: 4 | .\" Guus Sliepen 5 | .Sh NAME 6 | .Nm tinc-gui 7 | .Nd tinc GUI 8 | .Sh SYNOPSIS 9 | .Nm 10 | .Op Fl n 11 | .Op Fl -net Ns = Ns Ar NETNAME 12 | .Op Fl -pidfile Ns = Ns Ar FILENAME 13 | .Op Fl -help 14 | .Sh DESCRIPTION 15 | This is a Python/wxWidgets based graphical user interface for tinc, a secure virtual private network (VPN) project. 16 | .Nm 17 | communicates with 18 | .Xr tincd 8 19 | to alter and inspect the running VPN's state. 20 | It can show the current settings, the list of connections, nodes, subnets, and edges. 21 | For now, the debug level can be changed from the GUI, and by right-clicking on a node in the list of connections, 22 | a pop-up menu will appear that allows one to disconnect that node. 23 | .Sh OPTIONS 24 | .Bl -tag -width indent 25 | .It Fl n, -net Ns = Ns Ar NETNAME 26 | Communicate with tincd(8) connected with 27 | .Ar NETNAME . 28 | .It Fl -pidfile Ns = Ns Ar FILENAME 29 | Use the cookie from 30 | .Ar FILENAME 31 | to authenticate with a running tinc daemon. 32 | If unspecified, the default is 33 | .Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid. 34 | .It Fl -help 35 | Display short list of options. 36 | .El 37 | .Sh BUGS 38 | The GUI is not finished yet, the final version will have much more functionality. 39 | If you find any bugs, report them to tinc@tinc-vpn.org. 40 | .Sh SEE ALSO 41 | .Xr tincd 8 , 42 | .Pa http://www.tinc-vpn.org/ . 43 | .Pp 44 | The full documentation for tinc is maintained as a Texinfo manual. 45 | If the info and tinc programs are properly installed at your site, 46 | the command 47 | .Ic info tinc 48 | should give you access to the complete manual. 49 | .Pp 50 | tinc comes with ABSOLUTELY NO WARRANTY. 51 | This is free software, and you are welcome to redistribute it under certain conditions; 52 | see the file COPYING for details. 53 | .Sh AUTHORS 54 | .An "Ivo Timmermans" 55 | .An "Guus Sliepen" Aq guus@tinc-vpn.org 56 | .Pp 57 | And thanks to many others for their contributions to tinc! 58 | -------------------------------------------------------------------------------- /src/tincctl.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_TINCCTL_H 2 | #define TINC_TINCCTL_H 3 | 4 | /* 5 | tincctl.h -- header for tincctl.c. 6 | Copyright (C) 2011-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | #include "ecdsa.h" 25 | 26 | extern bool tty; 27 | extern bool force; 28 | extern char line[4096]; 29 | extern int fd; 30 | extern char buffer[4096]; 31 | extern size_t blen; 32 | extern bool confbasegiven; 33 | extern char *tinc_conf; 34 | extern char *hosts_dir; 35 | 36 | #define VAR_SERVER 1 /* Should be in tinc.conf */ 37 | #define VAR_HOST 2 /* Can be in host config file */ 38 | #define VAR_MULTIPLE 4 /* Multiple statements allowed */ 39 | #define VAR_OBSOLETE 8 /* Should not be used anymore */ 40 | #define VAR_SAFE 16 /* Variable is safe when accepting invitations */ 41 | 42 | typedef struct { 43 | const char *name; 44 | int type; 45 | } var_t; 46 | 47 | extern const var_t variables[]; 48 | 49 | extern size_t rstrip(char *value); 50 | extern char *get_my_name(bool verbose) ATTR_MALLOC; 51 | extern bool connect_tincd(bool verbose); 52 | extern bool sendline(int fd, const char *format, ...) ATTR_FORMAT(printf, 2, 3); 53 | extern bool recvline(int fd, char *line, size_t len); 54 | extern int check_port(const char *name); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/linux/watchdog.c: -------------------------------------------------------------------------------- 1 | #include "../system.h" 2 | 3 | #include 4 | 5 | #include "../event.h" 6 | #include "../logger.h" 7 | #include "../watchdog.h" 8 | 9 | static timeout_t timer; 10 | static struct timeval interval; 11 | 12 | static uint64_t second_to_microsecond(time_t second) { 13 | return second * 1000000; 14 | } 15 | 16 | static time_t microsecond_to_second(uint64_t micros) { 17 | return (time_t)(micros / 1000000); 18 | } 19 | 20 | // Ignore errors from sd_notify() since there's nothing we can do if it breaks anyway. 21 | // Also, there's this passage in `man sd_notify.3`: 22 | // In order to support both service managers that implement this scheme and those 23 | // which do not, it is generally recommended to ignore the return value of this call. 24 | void watchdog_ping(void) { 25 | sd_notify(false, "WATCHDOG=1"); 26 | } 27 | 28 | static void watchdog_handler(void *data) { 29 | (void)data; 30 | watchdog_ping(); 31 | timeout_set(&timer, &interval); 32 | } 33 | 34 | static bool watchdog_register(void) { 35 | uint64_t timeout = 0; 36 | 37 | if(sd_watchdog_enabled(false, &timeout) <= 0 || !timeout) { 38 | return false; 39 | } 40 | 41 | if(timeout < second_to_microsecond(2)) { 42 | logger(DEBUG_ALWAYS, LOG_WARNING, "Consider using a higher watchdog timeout. Spurious failures may occur."); 43 | } 44 | 45 | // Send notifications twice per timeout period 46 | timeout /= 2; 47 | 48 | interval.tv_sec = microsecond_to_second(timeout); 49 | 50 | if(interval.tv_sec) { 51 | timeout -= second_to_microsecond(interval.tv_sec); 52 | } 53 | 54 | interval.tv_usec = (suseconds_t)timeout; 55 | 56 | timeout_add(&timer, watchdog_handler, &timer, &interval); 57 | watchdog_ping(); 58 | 59 | return true; 60 | } 61 | 62 | void watchdog_start(void) { 63 | sd_notify(false, "READY=1"); 64 | bool enabled = watchdog_register(); 65 | logger(DEBUG_ALWAYS, LOG_INFO, "Watchdog %s", enabled ? "started" : "is disabled"); 66 | } 67 | 68 | void watchdog_stop(void) { 69 | sd_notify(false, "STOPPING=1"); 70 | timeout_del(&timer); 71 | } 72 | -------------------------------------------------------------------------------- /src/netutl.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_NETUTL_H 2 | #define TINC_NETUTL_H 3 | 4 | /* 5 | netutl.h -- header file for netutl.c 6 | Copyright (C) 1998-2005 Ivo Timmermans 7 | 2000-2013 Guus Sliepen 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "net.h" 25 | 26 | extern bool hostnames; 27 | 28 | // Converts service name (as listed in /etc/services) to port number. Returns 0 on error. 29 | extern uint16_t service_to_port(const char *service); 30 | extern struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) ATTR_DEALLOCATOR(freeaddrinfo); 31 | extern sockaddr_t str2sockaddr(const char *address, const char *port); 32 | extern void sockaddr2str(const sockaddr_t *sa, char **address, char **port); 33 | extern char *sockaddr2hostname(const sockaddr_t *sa) ATTR_MALLOC; 34 | extern int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b); 35 | extern int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b); 36 | extern void sockaddrunmap(sockaddr_t *sa); 37 | extern void sockaddrfree(sockaddr_t *sa); 38 | extern void sockaddrcpy(sockaddr_t *dest, const sockaddr_t *src); 39 | extern void sockaddr_setport(sockaddr_t *sa, const char *port); 40 | extern uint16_t get_bound_port(int sockfd); 41 | extern bool is_local_connection(const sockaddr_t *sa); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /test/integration/import_export.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test peer information import and export.""" 4 | 5 | from testlib import check, cmd 6 | from testlib.log import log 7 | from testlib.proc import Script 8 | from testlib.test import Test 9 | 10 | 11 | def run_tests(ctx: Test) -> None: 12 | """Run all tests.""" 13 | foo, bar, baz = ctx.node(init=True), ctx.node(init=True), ctx.node(init=True) 14 | 15 | tinc_up = f""" 16 | bar, baz = Tinc('{bar}'), Tinc('{baz}') 17 | bar.cmd('add', 'ConnectTo', this.name) 18 | baz.cmd('add', 'ConnectTo', this.name) 19 | """ 20 | foo.add_script(Script.TINC_UP, tinc_up) 21 | foo.start() 22 | 23 | log.info("run exchange") 24 | cmd.exchange(foo, bar) 25 | 26 | log.info("run exchange with export-all") 27 | cmd.exchange(foo, baz, export_all=True) 28 | 29 | log.info("run exchange-all") 30 | out, err = foo.cmd("exchange-all", code=1) 31 | check.is_in("No host configuration files imported", err) 32 | 33 | log.info("run import") 34 | bar.cmd("import", stdin=out) 35 | 36 | for first, second in ( 37 | (foo.sub("hosts", foo.name), bar.sub("hosts", foo.name)), 38 | (foo.sub("hosts", foo.name), baz.sub("hosts", foo.name)), 39 | (foo.sub("hosts", bar.name), bar.sub("hosts", bar.name)), 40 | (foo.sub("hosts", bar.name), baz.sub("hosts", bar.name)), 41 | (foo.sub("hosts", baz.name), bar.sub("hosts", baz.name)), 42 | (foo.sub("hosts", baz.name), baz.sub("hosts", baz.name)), 43 | ): 44 | log.info("comparing configs %s and %s", first, second) 45 | check.files_eq(first, second) 46 | 47 | log.info("create %s scripts", foo) 48 | foo.add_script(bar.script_up) 49 | foo.add_script(baz.script_up) 50 | 51 | log.info("start nodes") 52 | bar.cmd("start") 53 | baz.cmd("start") 54 | 55 | log.info("wait for up scripts") 56 | foo[bar.script_up].wait() 57 | foo[baz.script_up].wait() 58 | 59 | for tinc in foo, bar, baz: 60 | check.nodes(tinc, 3) 61 | 62 | 63 | with Test("import-export") as context: 64 | run_tests(context) 65 | -------------------------------------------------------------------------------- /src/edge.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_EDGE_H 2 | #define TINC_EDGE_H 3 | 4 | /* 5 | edge.h -- header for edge.c 6 | Copyright (C) 2001-2012 Guus Sliepen , 7 | 2001-2005 Ivo Timmermans 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "splay_tree.h" 25 | #include "connection.h" 26 | #include "net.h" 27 | #include "node.h" 28 | 29 | typedef struct edge_t { 30 | struct node_t *from; 31 | struct node_t *to; 32 | sockaddr_t address; 33 | sockaddr_t local_address; 34 | 35 | uint32_t options; /* options turned on for this edge */ 36 | int weight; /* weight of this edge */ 37 | 38 | struct connection_t *connection; /* connection associated with this edge, if available */ 39 | struct edge_t *reverse; /* edge in the opposite direction, if available */ 40 | } edge_t; 41 | 42 | extern splay_tree_t edge_weight_tree; /* Tree with all known edges sorted on weight */ 43 | 44 | extern void exit_edges(void); 45 | extern void free_edge(edge_t *e); 46 | extern edge_t *new_edge(void) ATTR_MALLOC ATTR_DEALLOCATOR(free_edge); 47 | extern void init_edge_tree(splay_tree_t *tree); 48 | extern void edge_add(edge_t *e); 49 | extern void edge_del(edge_t *e); 50 | extern edge_t *lookup_edge(struct node_t *from, struct node_t *to); 51 | extern bool dump_edges(struct connection_t *c); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /test/integration/testlib/path.py: -------------------------------------------------------------------------------- 1 | """Paths to compiled binaries, and a few other important environment variables.""" 2 | 3 | import os 4 | import pathlib 5 | import sys 6 | 7 | env = { 8 | "TEST_NAME": os.getenv("TEST_NAME"), 9 | "TINC_PATH": os.getenv("TINC_PATH"), 10 | "TINCD_PATH": os.getenv("TINCD_PATH"), 11 | "SPLICE_PATH": os.getenv("SPLICE_PATH"), 12 | "PYTHON_PATH": os.getenv("PYTHON_PATH"), 13 | "SPTPS_TEST_PATH": os.getenv("SPTPS_TEST_PATH"), 14 | "SPTPS_KEYPAIR_PATH": os.getenv("SPTPS_KEYPAIR_PATH"), 15 | } 16 | 17 | # Not strictly necessary, used for better autocompletion and search by reference. 18 | TEST_NAME = str(env["TEST_NAME"]) 19 | TINC_PATH = str(env["TINC_PATH"]) 20 | TINCD_PATH = str(env["TINCD_PATH"]) 21 | SPLICE_PATH = str(env["SPLICE_PATH"]) 22 | PYTHON_PATH = str(env["PYTHON_PATH"]) 23 | SPTPS_TEST_PATH = str(env["SPTPS_TEST_PATH"]) 24 | SPTPS_KEYPAIR_PATH = str(env["SPTPS_KEYPAIR_PATH"]) 25 | 26 | PYTHON_CMD = "runpython" if "meson.exe" in PYTHON_PATH.lower() else "" 27 | PYTHON_INTERPRETER = f"{PYTHON_PATH} {PYTHON_CMD}".rstrip() 28 | 29 | 30 | def _check() -> bool: 31 | """Basic sanity checks on passed environment variables.""" 32 | for key, val in env.items(): 33 | if not val or (key != "TEST_NAME" and not os.path.isfile(val)): 34 | return False 35 | return True 36 | 37 | 38 | if not _check(): 39 | MSG = """ 40 | Please run tests using 41 | $ meson test -C build 42 | or 43 | $ ninja -C build test 44 | """ 45 | print(MSG, file=sys.stderr) 46 | sys.exit(1) 47 | 48 | # Current working directory 49 | CWD = os.getcwd() 50 | 51 | # Path to the testing library 52 | TESTLIB_ROOT = pathlib.Path(__file__).parent 53 | 54 | # Source root for the integration test suite 55 | TEST_SRC_ROOT = TESTLIB_ROOT.parent.resolve() 56 | 57 | _wd = os.path.join(CWD, "wd") 58 | os.makedirs(_wd, exist_ok=True) 59 | 60 | # Useful when running tests manually 61 | _gitignore = os.path.join(_wd, ".gitignore") 62 | if not os.path.exists(_gitignore): 63 | with open(_gitignore, "w", encoding="utf-8") as f: 64 | f.write("*") 65 | 66 | # Working directory for this test 67 | TEST_WD = os.path.join(_wd, TEST_NAME) 68 | -------------------------------------------------------------------------------- /test/integration/testlib/cmd.py: -------------------------------------------------------------------------------- 1 | """Wrappers for more complicated tinc/tincd commands.""" 2 | 3 | import typing as T 4 | 5 | from . import check 6 | from .log import log 7 | from .proc import Tinc 8 | 9 | ExchangeIO = T.Tuple[ 10 | T.Tuple[str, str], 11 | T.Tuple[str, str], 12 | T.Tuple[str, str], 13 | ] 14 | 15 | 16 | def connect(node0: Tinc, node1: Tinc) -> ExchangeIO: 17 | """Exchange configuration between nodes and start 18 | them in such an order that `Port 0` works on both sides. 19 | """ 20 | node0.add_script(node1.script_up) 21 | node0.start() 22 | result = exchange(node0, node1) 23 | node1.add_script(node0.script_up) 24 | node1.cmd("add", "ConnectTo", node0.name) 25 | node1.start() 26 | node0[node1.script_up].wait() 27 | node1[node0.script_up].wait() 28 | return result 29 | 30 | 31 | def exchange(node0: Tinc, node1: Tinc, export_all: bool = False) -> ExchangeIO: 32 | """Run `export(-all) | exchange | import` between the passed nodes. 33 | `export-all` is used if export_all is set to True. 34 | """ 35 | export_cmd = "export-all" if export_all else "export" 36 | log.debug("%s between %s and %s", export_cmd, node0.name, node1.name) 37 | 38 | exp_out, exp_err = node0.cmd(export_cmd) 39 | log.debug( 40 | 'exchange: %s %s returned ("%s", "%s")', export_cmd, node0, exp_out, exp_err 41 | ) 42 | check.is_in("Name =", exp_out) 43 | 44 | xch_out, xch_err = node1.cmd("exchange", stdin=exp_out) 45 | log.debug('exchange: exchange %s returned ("%s", "%s")', node1, xch_out, xch_err) 46 | check.is_in("Name =", xch_out) 47 | check.is_in("Imported ", xch_err) 48 | 49 | imp_out, imp_err = node0.cmd("import", stdin=xch_out) 50 | log.debug('exchange: import %s returned ("%s", "%s")', node0, imp_out, imp_err) 51 | check.is_in("Imported ", imp_err) 52 | 53 | return ( 54 | (exp_out, exp_err), 55 | (xch_out, xch_err), 56 | (imp_out, imp_err), 57 | ) 58 | 59 | 60 | def get(tinc: Tinc, var: str) -> str: 61 | """Get the value of the variable, stripped of whitespace.""" 62 | assert var 63 | stdout, _ = tinc.cmd("get", var) 64 | return stdout.strip() 65 | -------------------------------------------------------------------------------- /doc/CONNECTIVITY: -------------------------------------------------------------------------------- 1 | This document describes how nodes in a VPN find and connect to each other and 2 | maintain a stable network. 3 | 4 | Copyright 2001-2006 Guus Sliepen 5 | 6 | Permission is granted to make and distribute verbatim copies of 7 | this documentation provided the copyright notice and this 8 | permission notice are preserved on all copies. 9 | 10 | Permission is granted to copy and distribute modified versions of 11 | this documentation under the conditions for verbatim copying, 12 | provided that the entire resulting derived work is distributed 13 | under the terms of a permission notice identical to this one. 14 | 15 | 1. Synchronisation 16 | ================== 17 | 18 | Each tinc daemon has zero or more connections to other tinc daemons. It will 19 | try to keep its own information synchronised with the other tinc daemons. If 20 | one of its peers sends information, the tinc daemon will check if it is new 21 | information. If so, it will update its own information and forward the new 22 | information to all the other peers. 23 | 24 | This scheme will make sure that after a short amount of time all tinc daemons 25 | share the same information. It will also almost completely prevent information 26 | from looping, because "new" information that is already known is ignored and 27 | not forwarded any further. However, since information can also be deleted 28 | there's the possibility of a looping sequence of add/delete messages. This is 29 | resolved by additionally adding a unique identifier to each broadcasted message. 30 | Messages are dropped if the same message with that identifier has already been 31 | seen. 32 | 33 | 2. Routing 34 | ========== 35 | 36 | Every node tells its peers to which other peers it is connected. This way 37 | every node will eventually know every connection every node has on the VPN. 38 | Each node will use graph algorithms to determine if other nodes are reachable or not and 39 | what the best route is to other nodes. 40 | 41 | Because all nodes share the same information, using a deterministic algorithm 42 | each node will calculate the same minimum spanning tree for the entire VPN. 43 | The MST will be used to send broadcast VPN packets. 44 | -------------------------------------------------------------------------------- /lint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Run linters on project code. Add --fix to autofix files with linters that support it.""" 4 | 5 | import sys 6 | import subprocess as subp 7 | from glob import glob 8 | from os import path, environ, chdir 9 | 10 | DRY = "--fix" not in sys.argv or environ.get("CI") 11 | HEADER = "#" * 24 12 | 13 | if DRY: 14 | MSG = """ 15 | You're running linters in non-destructive readonly mode. 16 | Some of them support automated fixes (like reformatting code). 17 | To apply them, run `lint.py --fix` or `ninja -C build reformat`. 18 | """ 19 | print(MSG, file=sys.stderr) 20 | 21 | source_root = path.dirname(path.realpath(__file__)) 22 | source_root = environ.get("MESON_SOURCE_ROOT", source_root) 23 | chdir(source_root) 24 | 25 | # It's best not to use globs that cover everything in the project — if integration 26 | # tests are run with a large --repeat value, test working directory can reach 27 | # enormous sizes, and linters either get very slow, or start crashing. 28 | linters = ( 29 | [ 30 | "astyle", 31 | "--recursive", 32 | "--options=.astylerc", 33 | "--dry-run" if DRY else "--formatted", 34 | "./*.c", 35 | "./*.h", 36 | ], 37 | ["shfmt", "-d" if DRY else "-w", "-i", "2", "-s", "."], 38 | ["black", "--check" if DRY else ".", "."], 39 | ["pylint", "."], 40 | ["mypy", "--exclude", "build", "."], 41 | ["shellcheck", "-x", *glob(".ci/**/*.sh", recursive=True)], 42 | ["markflow", "--line-length", "80", "--check" if DRY else "--verbose", ".", ".ci"], 43 | ) 44 | 45 | failed: bool = False 46 | 47 | for cmd in linters: 48 | exe = cmd[0] 49 | print(f"{HEADER} Running linter '{exe}' {HEADER}") 50 | 51 | try: 52 | res = subp.run( 53 | cmd, 54 | check=False, 55 | stdout=subp.PIPE, 56 | encoding="utf-8", 57 | ) 58 | failed = ( 59 | failed 60 | or bool(res.returncode) 61 | or (exe == "astyle" and "Formatted " in res.stdout) 62 | ) 63 | print(res.stdout) 64 | except FileNotFoundError as e: 65 | print(f"Warning: linter {exe} is missing", file=sys.stderr) 66 | 67 | sys.exit(int(failed)) 68 | -------------------------------------------------------------------------------- /test/integration/device_raw_socket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test raw socket device support.""" 4 | 5 | import sys 6 | import subprocess as subp 7 | 8 | from testlib import check, util 9 | from testlib.log import log 10 | from testlib.const import EXIT_SKIP 11 | from testlib.proc import Script 12 | from testlib.test import Test 13 | from testlib.external import veth_add, move_dev, ping 14 | 15 | util.require_root() 16 | util.require_command("ip", "link") 17 | 18 | FAKE_DEV = "cqhqdr7knaLzYeMSdy" 19 | 20 | IP_NETNS = "10.198.96.1" 21 | IP_HOST = "10.198.96.2" 22 | 23 | 24 | def test_device_raw_socket(ctx: Test) -> None: 25 | """Test raw socket device.""" 26 | 27 | foo = ctx.node(init="set DeviceType raw_socket") 28 | foo_log = foo.sub("log") 29 | 30 | log.info("test with a bad Interface") 31 | _, err = foo.cmd("start", "-o", f"Interface={FAKE_DEV}", code=1) 32 | if "Raw socket device not supported" in err: 33 | sys.exit(EXIT_SKIP) 34 | check.is_in(f"Can't find interface {FAKE_DEV}", err) 35 | 36 | log.info("create a veth pair") 37 | dev0, dev1 = util.random_string(10), util.random_string(10) 38 | veth_add(dev0, dev1) 39 | 40 | log.info("configure the veth pair") 41 | move_dev(dev1, dev1, f"{IP_NETNS}/30") 42 | subp.run(["ip", "addr", "add", f"{IP_HOST}/30", "dev", dev0], check=True) 43 | subp.run(["ip", "link", "set", dev0, "up"], check=True) 44 | 45 | log.info("set Interface and Device") 46 | foo.cmd("set", "Interface", dev0) 47 | foo.cmd("set", "Device", f"dev_{dev0}") 48 | foo.add_script(Script.TINC_UP) 49 | 50 | log.info("start tincd") 51 | _, err = foo.cmd("start", "--logfile", foo_log, "-d10") 52 | check.is_in(f"dev_{dev0} is a raw_socket", err) 53 | 54 | log.info("send some data to tincd interface") 55 | foo[Script.TINC_UP].wait() 56 | assert ping(IP_NETNS) 57 | 58 | log.info("stop tincd") 59 | foo.add_script(Script.TINC_DOWN) 60 | foo.cmd("stop") 61 | foo[Script.TINC_DOWN].wait() 62 | 63 | log.info("check that tincd received some data") 64 | check.in_file(foo_log, "Writing packet of") 65 | check.in_file(foo_log, "Read packet of") 66 | 67 | 68 | with Test("test raw socket device") as context: 69 | test_device_raw_socket(context) 70 | -------------------------------------------------------------------------------- /src/digest.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_DIGEST_H 2 | #define TINC_DIGEST_H 3 | 4 | /* 5 | digest.h -- header file digest.c 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | #define DIGEST_MAX_SIZE 64 26 | #define DIGEST_ALGO_SIZE ((size_t) -1) 27 | 28 | #ifndef DISABLE_LEGACY 29 | 30 | #ifdef HAVE_OPENSSL 31 | #include "openssl/digest.h" 32 | #elif HAVE_LIBGCRYPT 33 | #include "gcrypt/digest.h" 34 | #else 35 | #error Incorrect cryptographic library, please reconfigure. 36 | #endif 37 | 38 | typedef struct digest digest_t; 39 | 40 | extern bool digest_open_by_name(digest_t *digest, const char *name, size_t maclength); 41 | extern bool digest_open_by_nid(digest_t *digest, nid_t nid, size_t maclength); 42 | extern void digest_free(digest_t *digest); 43 | extern digest_t *digest_alloc(void) ATTR_MALLOC ATTR_DEALLOCATOR(digest_free); 44 | extern void digest_close(digest_t *digest); 45 | extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) ATTR_WARN_UNUSED; 46 | extern bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *digestdata) ATTR_WARN_UNUSED; 47 | extern bool digest_set_key(digest_t *digest, const void *key, size_t len) ATTR_WARN_UNUSED; 48 | extern nid_t digest_get_nid(const digest_t *digest); 49 | extern size_t digest_keylength(const digest_t *digest); 50 | extern size_t digest_length(const digest_t *digest); 51 | extern bool digest_active(const digest_t *digest); 52 | 53 | #endif // DISABLE_LEGACY 54 | 55 | #endif // TINC_DIGEST_H 56 | -------------------------------------------------------------------------------- /test/integration/ns_ping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Create two network namespaces and run ping between them.""" 4 | 5 | import typing as T 6 | 7 | from testlib import external as ext, util, template, cmd 8 | from testlib.log import log 9 | from testlib.proc import Tinc, Script 10 | from testlib.test import Test 11 | from testlib.external import ping 12 | 13 | util.require_root() 14 | util.require_command("ip", "netns", "list") 15 | util.require_path("/dev/net/tun") 16 | 17 | IP_FOO = "192.168.1.1" 18 | IP_BAR = "192.168.1.2" 19 | MASK = 24 20 | 21 | 22 | def init(ctx: Test) -> T.Tuple[Tinc, Tinc]: 23 | """Initialize new test nodes.""" 24 | foo, bar = ctx.node(), ctx.node() 25 | 26 | log.info("create network namespaces") 27 | assert ext.netns_add(foo.name) 28 | assert ext.netns_add(bar.name) 29 | 30 | log.info("initialize two nodes") 31 | 32 | stdin = f""" 33 | init {foo} 34 | set Port 0 35 | set Subnet {IP_FOO} 36 | set Interface {foo} 37 | set Address localhost 38 | set AutoConnect no 39 | """ 40 | foo.cmd(stdin=stdin) 41 | foo.add_script(Script.TINC_UP, template.make_netns_config(foo.name, IP_FOO, MASK)) 42 | foo.start() 43 | 44 | stdin = f""" 45 | init {bar} 46 | set Port 0 47 | set Subnet {IP_BAR} 48 | set Interface {bar} 49 | set Address localhost 50 | set AutoConnect no 51 | """ 52 | bar.cmd(stdin=stdin) 53 | bar.add_script(Script.TINC_UP, template.make_netns_config(bar.name, IP_BAR, MASK)) 54 | 55 | cmd.exchange(foo, bar) 56 | 57 | return foo, bar 58 | 59 | 60 | with Test("ns-ping") as context: 61 | foo_node, bar_node = init(context) 62 | bar_node.cmd("start") 63 | 64 | log.info("waiting for nodes to come up") 65 | bar_node[Script.TINC_UP].wait() 66 | 67 | log.info("ping must not work when there is no connection") 68 | assert not ping(IP_BAR, foo_node.name) 69 | 70 | log.info("add script foo/host-up") 71 | bar_node.add_script(foo_node.script_up) 72 | 73 | log.info("add ConnectTo clause") 74 | bar_node.cmd("add", "ConnectTo", foo_node.name) 75 | 76 | log.info("bar waits for foo") 77 | bar_node[foo_node.script_up].wait() 78 | 79 | log.info("ping must work after connection is up") 80 | assert ping(IP_BAR, foo_node.name) 81 | -------------------------------------------------------------------------------- /src/signal.c: -------------------------------------------------------------------------------- 1 | /* 2 | signal.c -- signal handling 3 | Copyright (C) 2012-2022 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "system.h" 21 | 22 | #include "event.h" 23 | 24 | // From Matz's Ruby 25 | #ifndef NSIG 26 | # define NSIG (_SIGMAX + 1) /* For QNX */ 27 | #endif 28 | 29 | static io_t signalio; 30 | static int pipefd[2] = {-1, -1}; 31 | static signal_t *signal_handle[NSIG + 1] = {NULL}; 32 | 33 | static void signal_handler(int signum) { 34 | unsigned char num = signum; 35 | 36 | if(write(pipefd[1], &num, 1) != 1) { 37 | // Pipe full or broken, nothing we can do about it. 38 | } 39 | } 40 | 41 | static void signalio_handler(void *data, int flags) { 42 | (void)data; 43 | (void)flags; 44 | unsigned char signum; 45 | 46 | if(read(pipefd[0], &signum, 1) != 1) { 47 | return; 48 | } 49 | 50 | signal_t *sig = signal_handle[signum]; 51 | 52 | if(sig) { 53 | sig->cb(sig->data); 54 | } 55 | } 56 | 57 | static void pipe_init(void) { 58 | if(!pipe(pipefd)) { 59 | io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ); 60 | } 61 | } 62 | 63 | void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) { 64 | if(sig->cb) { 65 | return; 66 | } 67 | 68 | sig->signum = signum; 69 | sig->cb = cb; 70 | sig->data = data; 71 | 72 | if(pipefd[0] == -1) { 73 | pipe_init(); 74 | } 75 | 76 | signal(signum, signal_handler); 77 | 78 | signal_handle[signum] = sig; 79 | } 80 | 81 | void signal_del(signal_t *sig) { 82 | if(!sig->cb) { 83 | return; 84 | } 85 | 86 | signal(sig->signum, SIG_DFL); 87 | 88 | signal_handle[sig->signum] = NULL; 89 | sig->cb = NULL; 90 | } 91 | -------------------------------------------------------------------------------- /src/ed25519/ecdsagen.c: -------------------------------------------------------------------------------- 1 | /* 2 | ecdsagen.c -- ECDSA key generation and export 3 | Copyright (C) 2011-2013 Guus Sliepen 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "../system.h" 21 | 22 | #include "ed25519.h" 23 | 24 | #define TINC_ECDSA_INTERNAL 25 | typedef struct { 26 | uint8_t private[64]; 27 | uint8_t public[32]; 28 | } ecdsa_t; 29 | 30 | #include "../ecdsagen.h" 31 | #include "../utils.h" 32 | #include "../xalloc.h" 33 | #include "../random.h" 34 | 35 | // Generate ECDSA key 36 | 37 | ecdsa_t *ecdsa_generate(void) { 38 | ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa)); 39 | 40 | uint8_t seed[32]; 41 | randomize(seed, sizeof(seed)); 42 | ed25519_create_keypair(ecdsa->public, ecdsa->private, seed); 43 | memzero(seed, sizeof(seed)); 44 | 45 | return ecdsa; 46 | } 47 | 48 | // Write PEM ECDSA keys 49 | 50 | static bool write_pem(FILE *fp, const char *type, void *vbuf, size_t size) { 51 | fprintf(fp, "-----BEGIN %s-----\n", type); 52 | 53 | char *buf = vbuf; 54 | char base64[65]; 55 | 56 | while(size) { 57 | size_t todo = size > 48 ? 48 : size; 58 | b64encode_tinc(buf, base64, todo); 59 | fprintf(fp, "%s\n", base64); 60 | buf += todo; 61 | size -= todo; 62 | } 63 | 64 | memzero(base64, sizeof(base64)); 65 | 66 | fprintf(fp, "-----END %s-----\n", type); 67 | return !ferror(fp); 68 | } 69 | 70 | bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) { 71 | return write_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public)); 72 | } 73 | 74 | bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) { 75 | return write_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa)); 76 | } 77 | -------------------------------------------------------------------------------- /test/unit/test_random.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/random.h" 3 | #include "../../src/xalloc.h" 4 | 5 | static int setup(void **state) { 6 | (void)state; 7 | random_init(); 8 | return 0; 9 | } 10 | 11 | static int teardown(void **state) { 12 | (void)state; 13 | random_exit(); 14 | return 0; 15 | } 16 | 17 | #define zerolen 128 18 | static const uint8_t zero[zerolen] = {0}; 19 | 20 | static void test_randomize_zero_must_not_change_memory(void **state) { 21 | (void)state; 22 | 23 | uint8_t buf[zerolen] = {0}; 24 | randomize(buf, 0); 25 | 26 | assert_memory_equal(zero, buf, sizeof(buf)); 27 | } 28 | 29 | static void test_randomize_does_not_overflow(void **state) { 30 | (void)state; 31 | 32 | uint8_t buf[zerolen] = {0}; 33 | const size_t half = sizeof(buf) / 2; 34 | randomize(buf, half); 35 | 36 | assert_memory_not_equal(zero, buf, half); 37 | assert_memory_equal(zero, &buf[half], half); 38 | } 39 | 40 | static void test_randomize_full_changes_memory(void **state) { 41 | (void)state; 42 | 43 | uint8_t buf[zerolen] = {0}; 44 | randomize(buf, sizeof(buf)); 45 | 46 | assert_memory_not_equal(zero, buf, sizeof(buf)); 47 | } 48 | 49 | static void test_randomize_does_not_repeat(void **state) { 50 | (void)state; 51 | 52 | // Ask randomize() for small chunks so there's more 53 | // chance for it to repeat itself (within reason). 54 | #define chunklen 16 55 | 56 | const size_t chunks = 1024; 57 | uint8_t (*buffers)[chunklen] = xzalloc(chunks * chunklen); 58 | 59 | // Fill buffers with (hopefully) random data 60 | for(size_t i = 0; i < chunks; ++i) { 61 | randomize(buffers[i], chunklen); 62 | 63 | // Check there was no overflow to the right 64 | if(i < chunks - 1) { 65 | assert_memory_equal(zero, buffers[i + 1], chunklen); 66 | } 67 | } 68 | 69 | // Check there were no repetitions (with 128-bit buffers collisions are very unlikely) 70 | for(size_t i = 0; i < chunks - 1; ++i) { 71 | for(size_t j = i + 1; j < chunks; ++j) { 72 | assert_memory_not_equal(buffers[i], buffers[j], chunklen); 73 | } 74 | } 75 | 76 | free(buffers); 77 | #undef chunklen 78 | } 79 | 80 | int main(void) { 81 | const struct CMUnitTest tests[] = { 82 | cmocka_unit_test(test_randomize_zero_must_not_change_memory), 83 | cmocka_unit_test(test_randomize_does_not_overflow), 84 | cmocka_unit_test(test_randomize_full_changes_memory), 85 | cmocka_unit_test(test_randomize_does_not_repeat), 86 | }; 87 | return cmocka_run_group_tests(tests, setup, teardown); 88 | } 89 | -------------------------------------------------------------------------------- /src/cipher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_CIPHER_H 2 | #define TINC_CIPHER_H 3 | 4 | /* 5 | cipher.h -- header file cipher.c 6 | Copyright (C) 2007-2022 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | 25 | #define CIPHER_MAX_BLOCK_SIZE 32 26 | #define CIPHER_MAX_IV_SIZE 16 27 | #define CIPHER_MAX_KEY_SIZE 32 28 | 29 | #ifndef DISABLE_LEGACY 30 | 31 | #ifdef HAVE_OPENSSL 32 | #include "openssl/cipher.h" 33 | #elif HAVE_LIBGCRYPT 34 | #include "gcrypt/cipher.h" 35 | #else 36 | #error Incorrect cryptographic library, please reconfigure. 37 | #endif 38 | 39 | extern void cipher_free(cipher_t *cipher); 40 | extern cipher_t *cipher_alloc(void) ATTR_MALLOC ATTR_DEALLOCATOR(cipher_free); 41 | extern bool cipher_open_by_name(cipher_t *cipher, const char *name); 42 | extern bool cipher_open_by_nid(cipher_t *cipher, nid_t nid); 43 | extern void cipher_close(cipher_t *cipher); 44 | extern size_t cipher_keylength(const cipher_t *cipher); 45 | extern size_t cipher_blocksize(const cipher_t *cipher); 46 | extern uint64_t cipher_budget(const cipher_t *cipher); 47 | extern bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) ATTR_WARN_UNUSED; 48 | extern bool cipher_set_key_from_rsa(cipher_t *cipher, void *rsa, size_t len, bool encrypt) ATTR_WARN_UNUSED; 49 | extern bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) ATTR_WARN_UNUSED; 50 | extern bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) ATTR_WARN_UNUSED; 51 | extern nid_t cipher_get_nid(const cipher_t *cipher); 52 | extern bool cipher_active(const cipher_t *cipher); 53 | 54 | #endif // DISABLE_LEGACY 55 | 56 | #endif // TINC_CIPHER_H 57 | -------------------------------------------------------------------------------- /test/integration/meson.build: -------------------------------------------------------------------------------- 1 | tests = [ 2 | 'address_cache.py', 3 | 'basic.py', 4 | 'bind_port.py', 5 | 'cmd_dump.py', 6 | 'cmd_fsck.py', 7 | 'cmd_import.py', 8 | 'cmd_join.py', 9 | 'cmd_keys.py', 10 | 'cmd_misc.py', 11 | 'cmd_net.py', 12 | 'cmd_sign_verify.py', 13 | 'commandline.py', 14 | 'device.py', 15 | 'device_multicast.py', 16 | 'executables.py', 17 | 'import_export.py', 18 | 'invite.py', 19 | 'invite_tinc_up.py', 20 | 'net.py', 21 | 'proxy.py', 22 | 'sandbox.py', 23 | 'scripts.py', 24 | 'security.py', 25 | 'splice.py', 26 | 'sptps_basic.py', 27 | 'variables.py', 28 | ] 29 | 30 | if opt_crypto != 'nolegacy' 31 | tests += [ 32 | 'algorithms.py', 33 | 'legacy_protocol.py', 34 | ] 35 | endif 36 | 37 | if os_name == 'linux' 38 | tests += [ 39 | 'bind_address.py', 40 | 'compression.py', 41 | 'device_raw_socket.py', 42 | 'device_tap.py', 43 | 'ns_ping.py', 44 | ] 45 | if not opt_systemd.disabled() 46 | tests += 'systemd.py' 47 | endif 48 | endif 49 | 50 | if cdata.has('HAVE_FD_DEVICE') 51 | tests += 'device_fd.py' 52 | endif 53 | 54 | exe_splice = executable( 55 | 'splice', 56 | sources: 'splice.c', 57 | dependencies: deps_common, 58 | implicit_include_directories: false, 59 | include_directories: inc_conf, 60 | build_by_default: false, 61 | ) 62 | 63 | env_vars = { 64 | 'TINC_PATH': exe_tinc.full_path(), 65 | 'TINCD_PATH': exe_tincd.full_path(), 66 | 'PYTHON_PATH': python_path, 67 | 'SPLICE_PATH': exe_splice.full_path(), 68 | 'SPTPS_TEST_PATH': exe_sptps_test.full_path(), 69 | 'SPTPS_KEYPAIR_PATH': exe_sptps_keypair.full_path(), 70 | } 71 | 72 | deps_test = [ 73 | exe_tinc, 74 | exe_tincd, 75 | exe_splice, 76 | exe_sptps_test, 77 | exe_sptps_keypair, 78 | ] 79 | 80 | test_wd = meson.current_build_dir() 81 | test_src = meson.current_source_dir() 82 | 83 | foreach test_name : tests 84 | if meson_version.version_compare('>=0.52') 85 | env = environment(env_vars) 86 | else 87 | env = environment() 88 | foreach k, v : env_vars 89 | env.set(k, v) 90 | endforeach 91 | endif 92 | env.set('TEST_NAME', test_name) 93 | 94 | test(test_name, 95 | python, 96 | args: test_src / test_name, 97 | suite: 'integration', 98 | timeout: 60, 99 | env: env, 100 | depends: deps_test, 101 | workdir: test_wd) 102 | endforeach 103 | 104 | -------------------------------------------------------------------------------- /test/unit/test_utils.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/utils.h" 3 | 4 | static void test_int_to_str(const char *ref, int num) { 5 | char *result = int_to_str(num); 6 | assert_string_equal(ref, result); 7 | free(result); 8 | } 9 | 10 | static void test_int_to_str_return_expected(void **state) { 11 | (void)state; 12 | 13 | test_int_to_str("0", 0); 14 | test_int_to_str("-1337", -1337); 15 | test_int_to_str("65535", 65535); 16 | } 17 | 18 | static void test_is_decimal_fail_empty(void **state) { 19 | (void)state; 20 | 21 | assert_false(is_decimal(NULL)); 22 | assert_false(is_decimal("")); 23 | } 24 | 25 | static void test_is_decimal_fail_hex(void **state) { 26 | (void)state; 27 | 28 | assert_false(is_decimal("DEADBEEF")); 29 | assert_false(is_decimal("0xCAFE")); 30 | } 31 | 32 | static void test_is_decimal_fail_junk_suffix(void **state) { 33 | (void)state; 34 | 35 | assert_false(is_decimal("123foobar")); 36 | assert_false(is_decimal("777 ")); 37 | } 38 | 39 | static void test_is_decimal_pass_simple(void **state) { 40 | (void)state; 41 | 42 | assert_true(is_decimal("0")); 43 | assert_true(is_decimal("123")); 44 | } 45 | 46 | static void test_is_decimal_pass_signs(void **state) { 47 | (void)state; 48 | 49 | assert_true(is_decimal("-123")); 50 | assert_true(is_decimal("+123")); 51 | } 52 | 53 | static void test_is_decimal_pass_whitespace_prefix(void **state) { 54 | (void)state; 55 | 56 | assert_true(is_decimal(" \r\n\t 777")); 57 | } 58 | 59 | static void test_string_eq(void **state) { 60 | (void)state; 61 | 62 | assert_true(string_eq(NULL, NULL)); 63 | assert_true(string_eq("", "")); 64 | assert_true(string_eq("\tfoo 123", "\tfoo 123")); 65 | 66 | assert_false(string_eq(NULL, "")); 67 | assert_false(string_eq("", NULL)); 68 | assert_false(string_eq("foo", "FOO")); 69 | assert_false(string_eq("foo", " foo")); 70 | } 71 | 72 | int main(void) { 73 | const struct CMUnitTest tests[] = { 74 | cmocka_unit_test(test_int_to_str_return_expected), 75 | cmocka_unit_test(test_is_decimal_fail_empty), 76 | cmocka_unit_test(test_is_decimal_fail_hex), 77 | cmocka_unit_test(test_is_decimal_fail_junk_suffix), 78 | cmocka_unit_test(test_is_decimal_pass_simple), 79 | cmocka_unit_test(test_is_decimal_pass_signs), 80 | cmocka_unit_test(test_is_decimal_pass_whitespace_prefix), 81 | cmocka_unit_test(test_string_eq), 82 | }; 83 | 84 | #ifdef HAVE_WINDOWS 85 | cmocka_set_skip_filter("test_unix_*"); 86 | #endif 87 | 88 | return cmocka_run_group_tests(tests, NULL, NULL); 89 | } 90 | -------------------------------------------------------------------------------- /test/unit/test_netutl.c: -------------------------------------------------------------------------------- 1 | #include "unittest.h" 2 | #include "../../src/netutl.h" 3 | 4 | static void test_service_to_port_invalid(void **state) { 5 | (void)state; 6 | 7 | assert_int_equal(0, service_to_port(NULL)); 8 | assert_int_equal(0, service_to_port("")); 9 | assert_int_equal(0, service_to_port("-1")); 10 | assert_int_equal(0, service_to_port("foobar")); 11 | } 12 | 13 | static void test_service_to_port_valid(void **state) { 14 | (void)state; 15 | 16 | assert_int_equal(22, service_to_port("ssh")); 17 | assert_int_equal(80, service_to_port("http")); 18 | assert_int_equal(443, service_to_port("https")); 19 | assert_int_equal(1234, service_to_port("1234")); 20 | } 21 | 22 | static void test_is_local_connection_ipv4(void **state) { 23 | (void)state; 24 | 25 | sockaddr_t sa; 26 | 27 | assert_true(inet_pton(AF_INET, "127.0.0.0", &sa.in.sin_addr)); 28 | sa.sa.sa_family = AF_INET; 29 | assert_true(is_local_connection(&sa)); 30 | 31 | assert_true(inet_pton(AF_INET, "127.42.13.5", &sa.in.sin_addr)); 32 | sa.sa.sa_family = AF_INET; 33 | assert_true(is_local_connection(&sa)); 34 | 35 | assert_true(inet_pton(AF_INET, "127.255.255.255", &sa.in.sin_addr)); 36 | sa.sa.sa_family = AF_INET; 37 | assert_true(is_local_connection(&sa)); 38 | 39 | assert_true(inet_pton(AF_INET, "128.0.0.1", &sa.in.sin_addr)); 40 | sa.sa.sa_family = AF_INET; 41 | assert_false(is_local_connection(&sa)); 42 | } 43 | 44 | static void test_is_local_connection_ipv6(void **state) { 45 | (void)state; 46 | 47 | sockaddr_t sa; 48 | 49 | assert_true(inet_pton(AF_INET6, "::1", &sa.in6.sin6_addr)); 50 | sa.sa.sa_family = AF_INET6; 51 | assert_true(is_local_connection(&sa)); 52 | 53 | assert_true(inet_pton(AF_INET6, "::1:1", &sa.in6.sin6_addr)); 54 | sa.sa.sa_family = AF_INET6; 55 | assert_false(is_local_connection(&sa)); 56 | 57 | assert_true(inet_pton(AF_INET6, "fe80::", &sa.in6.sin6_addr)); 58 | sa.sa.sa_family = AF_INET6; 59 | assert_false(is_local_connection(&sa)); 60 | } 61 | 62 | static void test_is_local_connection_unix(void **state) { 63 | (void)state; 64 | 65 | sockaddr_t sa = {.sa.sa_family = AF_UNIX}; 66 | assert_true(is_local_connection(&sa)); 67 | } 68 | 69 | int main(void) { 70 | const struct CMUnitTest tests[] = { 71 | cmocka_unit_test(test_service_to_port_invalid), 72 | cmocka_unit_test(test_service_to_port_valid), 73 | cmocka_unit_test(test_is_local_connection_ipv4), 74 | cmocka_unit_test(test_is_local_connection_ipv6), 75 | cmocka_unit_test(test_is_local_connection_unix), 76 | }; 77 | return cmocka_run_group_tests(tests, NULL, NULL); 78 | } 79 | -------------------------------------------------------------------------------- /src/event.h: -------------------------------------------------------------------------------- 1 | #ifndef TINC_EVENT_H 2 | #define TINC_EVENT_H 3 | 4 | /* 5 | event.h -- I/O, timeout and signal event handling 6 | Copyright (C) 2012-2013 Guus Sliepen 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "system.h" 24 | #include "splay_tree.h" 25 | 26 | #define IO_READ 1 27 | #define IO_WRITE 2 28 | 29 | typedef void (*io_cb_t)(void *data, int flags); 30 | typedef void (*timeout_cb_t)(void *data); 31 | typedef void (*signal_cb_t)(void *data); 32 | 33 | typedef struct io_t { 34 | int fd; 35 | int flags; 36 | #ifdef HAVE_WINDOWS 37 | WSAEVENT event; 38 | #endif 39 | io_cb_t cb; 40 | void *data; 41 | splay_node_t node; 42 | } io_t; 43 | 44 | typedef struct timeout_t { 45 | struct timeval tv; 46 | timeout_cb_t cb; 47 | void *data; 48 | splay_node_t node; 49 | } timeout_t; 50 | 51 | typedef struct signal_t { 52 | int signum; 53 | signal_cb_t cb; 54 | void *data; 55 | } signal_t; 56 | 57 | extern struct timeval now; 58 | 59 | extern splay_tree_t io_tree; 60 | extern splay_tree_t timeout_tree; 61 | 62 | extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags); 63 | #ifdef HAVE_WINDOWS 64 | extern void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event); 65 | #endif 66 | extern void io_del(io_t *io); 67 | extern void io_set(io_t *io, int flags); 68 | 69 | extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, const struct timeval *tv); 70 | extern void timeout_del(timeout_t *timeout); 71 | extern void timeout_set(timeout_t *timeout, const struct timeval *tv); 72 | extern struct timeval *timeout_execute(struct timeval *diff); 73 | 74 | extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum); 75 | extern void signal_del(signal_t *sig); 76 | 77 | extern bool event_loop(void); 78 | extern void event_exit(void); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /test/integration/splice.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test splicing connection between tinc peers.""" 4 | 5 | import os 6 | import subprocess as subp 7 | import typing as T 8 | 9 | from testlib import check, cmd, path 10 | from testlib.log import log 11 | from testlib.proc import Tinc, Script 12 | from testlib.test import Test 13 | from testlib.feature import SANDBOX_LEVEL 14 | 15 | 16 | def init(ctx: Test, *options: str) -> T.Tuple[Tinc, Tinc]: 17 | """Initialize new test nodes.""" 18 | custom = os.linesep.join(options) 19 | log.info('init two nodes with options "%s"', custom) 20 | 21 | foo, bar = ctx.node(), ctx.node() 22 | 23 | stdin = f""" 24 | init {foo} 25 | set Port 0 26 | set DeviceType dummy 27 | set Address localhost 28 | set AutoConnect no 29 | set Subnet 10.96.96.1 30 | set Sandbox {SANDBOX_LEVEL} 31 | {custom} 32 | """ 33 | foo.cmd(stdin=stdin) 34 | 35 | stdin = f""" 36 | init {bar} 37 | set Port 0 38 | set Address localhost 39 | set DeviceType dummy 40 | set AutoConnect no 41 | set Subnet 10.96.96.2 42 | set Sandbox {SANDBOX_LEVEL} 43 | {custom} 44 | """ 45 | bar.cmd(stdin=stdin) 46 | 47 | foo.add_script(Script.SUBNET_UP) 48 | bar.add_script(Script.SUBNET_UP) 49 | 50 | foo.start() 51 | bar.start() 52 | 53 | log.info("exchange host configs") 54 | cmd.exchange(foo, bar) 55 | 56 | return foo, bar 57 | 58 | 59 | def splice(foo: Tinc, bar: Tinc, protocol: str) -> subp.Popen: 60 | """Start splice between nodes.""" 61 | args = [ 62 | path.SPLICE_PATH, 63 | foo.name, 64 | "localhost", 65 | str(foo.port), 66 | bar.name, 67 | "localhost", 68 | str(bar.port), 69 | protocol, 70 | ] 71 | log.info("splice with args %s", args) 72 | return subp.Popen(args) 73 | 74 | 75 | def test_splice(ctx: Test, protocol: str, *options: str) -> None: 76 | """Splice connection and check that it fails.""" 77 | log.info("no splicing allowed (%s)", protocol) 78 | foo, bar = init(ctx, *options) 79 | 80 | log.info("waiting for subnets to come up") 81 | foo[Script.SUBNET_UP].wait() 82 | bar[Script.SUBNET_UP].wait() 83 | 84 | splice_proc = splice(foo, bar, protocol) 85 | try: 86 | check.nodes(foo, 1) 87 | check.nodes(bar, 1) 88 | finally: 89 | splice_proc.kill() 90 | 91 | 92 | with Test("sptps") as context: 93 | test_splice(context, "17.7") 94 | 95 | with Test("legacy") as context: 96 | test_splice(context, "17.0", "set ExperimentalProtocol no") 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About tinc 2 | 3 | Tinc is a peer-to-peer VPN daemon that supports VPNs with an arbitrary number of 4 | nodes. Instead of configuring tunnels, you give tinc the location and public key 5 | of a few nodes in the VPN. After making the initial connections to those nodes, 6 | tinc will learn about all other nodes on the VPN, and will make connections 7 | automatically. When direct connections are not possible, data will be forwarded 8 | by intermediate nodes. 9 | 10 | Tinc can operate in several routing modes. In the default mode, "router", every 11 | node is associated with one or more IPv4 and/or IPv6 Subnets. The other two 12 | modes, "switch" and "hub", let the tinc daemons work together to form a virtual 13 | Ethernet network switch or hub. 14 | 15 | ## This is a pre-release 16 | 17 | Please note that this is NOT a stable release. Until version 1.1.0 is released, 18 | please use one of the 1.0.x versions if you need a stable version of tinc. 19 | 20 | Although tinc 1.1 will be protocol compatible with tinc 1.0.x, the functionality 21 | of the tinc program may still change, and the control socket protocol is not 22 | fixed yet. 23 | 24 | # Documentation 25 | 26 | See [QUICKSTART.md](QUICKSTART.md) for a quick guide to get tinc up and running. 27 | Read the [manual](https://www.tinc-vpn.org/documentation-1.1/) for more detailed 28 | information. 29 | 30 | # Getting tinc 31 | 32 | ## From your distribution 33 | 34 | Many operating system distributions have packaged tinc. Check your package 35 | manager first. 36 | 37 | ## Nightly builds 38 | 39 | You can download pre-built binary packages for multiple Linux distributions and 40 | Windows here: 41 | 42 | - [development version](https://github.com/gsliepen/tinc/releases/tag/latest) 43 | - [latest release](https://github.com/gsliepen/tinc/releases/latest) 44 | 45 | Note that these packages have not been heavily tested and are not officially 46 | supported by the project. Use them at your own risk. You are advised to use tinc 47 | shipped by your distribution, or build from source. 48 | 49 | ## Build it from source 50 | 51 | See the file [INSTALL.md](INSTALL.md) for instructions of how to build and 52 | install tinc from source. 53 | 54 | # Copyright 55 | 56 | tinc is Copyright © 1998-2022 Ivo Timmermans, Guus Sliepen , 57 | and others. 58 | 59 | For a complete list of authors see the [AUTHORS](AUTHORS) file. 60 | 61 | This program is free software; you can redistribute it and/or modify it under 62 | the terms of the GNU General Public License as published by the Free Software 63 | Foundation; either version 2 of the License, or (at your option) any later 64 | version. See the file COPYING for more details. 65 | -------------------------------------------------------------------------------- /test/integration/cmd_net.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test network control commands.""" 4 | 5 | from testlib import check, cmd 6 | from testlib.log import log 7 | from testlib.proc import Tinc 8 | from testlib.test import Test 9 | 10 | 11 | def init(ctx: Test) -> Tinc: 12 | """Initialize a node.""" 13 | return ctx.node(init="set AutoConnect no") 14 | 15 | 16 | def test_network(foo: Tinc) -> None: 17 | """Test command 'network'.""" 18 | 19 | _, err = foo.cmd("network", "foo", "bar", code=1) 20 | check.is_in("Too many arguments", err) 21 | 22 | _, err = foo.cmd("network", "foo./", code=1) 23 | check.is_in("Invalid character in netname", err) 24 | 25 | _, err = foo.cmd("network", "foo.<") 26 | check.is_in("unsafe character in netname", err) 27 | 28 | 29 | def run_tests(foo: Tinc, bar: Tinc) -> None: 30 | """Run tests.""" 31 | 32 | log.info("start nodes") 33 | foo.start() 34 | bar.start() 35 | check.nodes(foo, 1) 36 | 37 | log.info("test failing commands") 38 | _, err = foo.cmd("connect", code=1) 39 | check.is_in("Invalid number of arguments", err) 40 | 41 | _, err = foo.cmd("connect", "foo", "bar", code=1) 42 | check.is_in("Invalid number of arguments", err) 43 | 44 | _, err = foo.cmd("connect", f"{bar}@", code=1) 45 | check.is_in("Invalid name for node", err) 46 | 47 | log.info("connect nodes") 48 | foo.add_script(bar.script_up) 49 | cmd.exchange(foo, bar) 50 | 51 | # Implement REQ_CONNECT and update this 52 | log.info("test connect") 53 | _, err = foo.cmd("connect", bar.name, code=1) 54 | check.is_in("Could not connect to", err) 55 | 56 | log.info("connect nodes") 57 | foo.cmd("add", "ConnectTo", bar.name) 58 | foo.cmd("retry") 59 | foo[bar.script_up].wait() 60 | check.nodes(foo, 2) 61 | 62 | log.info("disconnect nodes") 63 | foo.add_script(bar.script_down) 64 | foo.cmd("disconnect", bar.name) 65 | foo[bar.script_down].wait() 66 | check.nodes(foo, 1) 67 | 68 | log.info("second disconnect must fail") 69 | _, err = foo.cmd("disconnect", bar.name, code=1) 70 | check.is_in("Could not disconnect", err) 71 | 72 | log.info("retry connections") 73 | foo.cmd("retry") 74 | foo[bar.script_up].wait() 75 | check.nodes(foo, 2) 76 | 77 | log.info("purge old connections") 78 | bar.cmd("stop") 79 | foo[bar.script_down].wait() 80 | foo.cmd("purge") 81 | 82 | for command, result in ("nodes", 1), ("edges", 0), ("subnets", 4): 83 | out, _ = foo.cmd("dump", command) 84 | check.lines(out, result) 85 | 86 | test_network(foo) 87 | 88 | 89 | with Test("run network tests") as context: 90 | run_tests(init(context), init(context)) 91 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('runstatedir', 2 | type: 'string', 3 | value: '', 4 | description: 'state directory for sockets, PID files') 5 | 6 | option('docs', 7 | type: 'feature', 8 | value: 'auto', 9 | description: 'generate documentation') 10 | 11 | option('tests', 12 | type: 'feature', 13 | value: 'auto', 14 | description: 'enable tests') 15 | 16 | option('hardening', 17 | type: 'boolean', 18 | value: true, 19 | description: 'add compiler and linker hardening flags') 20 | 21 | option('static', 22 | type: 'feature', 23 | value: 'auto', 24 | description: 'statically link dependencies (auto: YES on Windows, NO everywhere else)') 25 | 26 | option('systemd', 27 | type: 'feature', 28 | value: 'auto', 29 | description: 'install systemd service files') 30 | 31 | option('systemd_dir', 32 | type: 'string', 33 | value: '', 34 | description: 'systemd service directory (defaults to $prefix/lib/systemd/system)') 35 | 36 | option('crypto', 37 | type: 'combo', 38 | choices: ['openssl', 'gcrypt', 'nolegacy'], 39 | value: 'openssl', 40 | description: 'which cryptographic library to use') 41 | 42 | option('miniupnpc', 43 | type: 'feature', 44 | value: 'disabled', 45 | description: 'miniupnpc support') 46 | 47 | option('lzo', 48 | type: 'feature', 49 | value: 'auto', 50 | description: 'lzo compression support') 51 | 52 | option('lz4', 53 | type: 'feature', 54 | value: 'auto', 55 | description: 'lz4 compression support') 56 | 57 | option('curses', 58 | type: 'feature', 59 | value: 'auto', 60 | description: 'curses support') 61 | 62 | option('readline', 63 | type: 'feature', 64 | value: 'auto', 65 | description: 'readline support') 66 | 67 | option('zlib', 68 | type: 'feature', 69 | value: 'auto', 70 | description: 'zlib compression support') 71 | 72 | option('uml', 73 | type: 'boolean', 74 | value: false, 75 | description: 'User Mode Linux support') 76 | 77 | option('tunemu', 78 | type: 'feature', 79 | value: 'auto', 80 | description: 'support for the tunemu driver') 81 | 82 | option('vde', 83 | type: 'feature', 84 | value: 'auto', 85 | description: 'support for Virtual Distributed Ethernet') 86 | 87 | option('jumbograms', 88 | type: 'boolean', 89 | value: false, 90 | description: 'support for jumbograms (packets up to 9000 bytes)') 91 | 92 | option('sandbox', 93 | type: 'feature', 94 | value: 'auto', 95 | description: 'use sandboxing on platforms that support it') 96 | 97 | -------------------------------------------------------------------------------- /test/integration/legacy_protocol.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Test legacy protocol support (tinc 1.0).""" 4 | 5 | import typing as T 6 | 7 | from testlib import check, cmd 8 | from testlib.log import log 9 | from testlib.proc import Tinc, Script 10 | from testlib.test import Test 11 | 12 | TIMEOUT = 2 13 | 14 | 15 | def init(ctx: Test) -> T.Tuple[Tinc, Tinc]: 16 | """Initialize new test nodes.""" 17 | foo, bar = ctx.node(), ctx.node() 18 | 19 | stdin = f""" 20 | init {foo} 21 | set Port 0 22 | set DeviceType dummy 23 | set Address localhost 24 | add Subnet 10.98.98.1 25 | set PingTimeout {TIMEOUT} 26 | """ 27 | foo.cmd(stdin=stdin) 28 | foo.start() 29 | 30 | stdin = f""" 31 | init {bar} 32 | set Port 0 33 | set Address localhost 34 | set DeviceType dummy 35 | add Subnet 10.98.98.2 36 | set PingTimeout {TIMEOUT} 37 | set MaxTimeout {TIMEOUT} 38 | """ 39 | bar.cmd(stdin=stdin) 40 | 41 | cmd.exchange(foo, bar) 42 | bar.cmd("add", "ConnectTo", foo.name) 43 | 44 | foo.add_script(bar.script_up) 45 | bar.add_script(foo.script_up) 46 | 47 | return foo, bar 48 | 49 | 50 | def run_keys_test(foo: Tinc, bar: Tinc, empty: bool) -> None: 51 | """Check that EC public keys match the expected values.""" 52 | bar.cmd("start") 53 | 54 | foo[bar.script_up].wait() 55 | bar[foo.script_up].wait() 56 | 57 | check.nodes(foo, 2) 58 | check.nodes(bar, 2) 59 | 60 | foo_bar, _ = foo.cmd("get", f"{bar.name}.Ed25519PublicKey", code=None) 61 | log.info('got key foo/bar "%s"', foo_bar) 62 | 63 | bar_foo, _ = bar.cmd("get", f"{foo.name}.Ed25519PublicKey", code=None) 64 | log.info('got key bar/foo "%s"', bar_foo) 65 | 66 | assert not foo_bar == empty 67 | assert not bar_foo == empty 68 | 69 | 70 | with Test("foo 1.1, bar 1.1") as context: 71 | foo_node, bar_node = init(context) 72 | run_keys_test(foo_node, bar_node, empty=False) 73 | 74 | with Test("foo 1.1, bar 1.0") as context: 75 | foo_node, bar_node = init(context) 76 | bar_node.cmd("set", "ExperimentalProtocol", "no") 77 | foo_node.cmd("del", f"{bar_node}.Ed25519PublicKey") 78 | bar_node.cmd("del", f"{foo_node}.Ed25519PublicKey") 79 | run_keys_test(foo_node, bar_node, empty=True) 80 | 81 | with Test("bar 1.0 must not be allowed to connect") as context: 82 | foo_node, bar_node = init(context) 83 | bar_node.cmd("set", "ExperimentalProtocol", "no") 84 | 85 | bar_up = bar_node.add_script(Script.SUBNET_UP) 86 | bar_node.cmd("start") 87 | bar_up.wait() 88 | 89 | assert not foo_node[bar_node.script_up].wait(TIMEOUT * 2) 90 | check.nodes(foo_node, 1) 91 | check.nodes(bar_node, 1) 92 | --------------------------------------------------------------------------------