Merge remote-tracking branch 'guus/1.1' into thkr-foor2Vup
This commit is contained in:
commit
4be26caf4e
64 changed files with 3013 additions and 2400 deletions
242
src/Makefile.am
242
src/Makefile.am
|
|
@ -2,25 +2,26 @@
|
|||
|
||||
sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
|
||||
|
||||
## Make sure version.c is always rebuilt with the latest git information
|
||||
.PHONY: ${srcdir}/version.c version_git.h
|
||||
version_git.h:
|
||||
echo >$@
|
||||
-(cd $(srcdir) && git describe) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@
|
||||
CLEANFILES = version_git.h
|
||||
|
||||
.PHONY: version-stamp
|
||||
version-stamp:
|
||||
|
||||
version_git.h: version-stamp
|
||||
$(AM_V_GEN)echo >$@
|
||||
@-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||:
|
||||
${srcdir}/version.c: version_git.h
|
||||
|
||||
## Now a hack to appease some versions of BSD make that don't understand that "./foo" is the same as "foo".
|
||||
if BSD
|
||||
version.c: ${srcdir}/version.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
sbin_PROGRAMS += sptps_speed
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = libtincd.la libed25519.la libchacha_poly1305.la libtincconf.la
|
||||
|
||||
libchacha_poly1305_la_SOURCES = \
|
||||
chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
|
||||
chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
|
||||
chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
|
||||
|
||||
libed25519_la_SOURCES = \
|
||||
ed25519_SOURCES = \
|
||||
ed25519/add_scalar.c \
|
||||
ed25519/ed25519.h \
|
||||
ed25519/fe.c ed25519/fe.h \
|
||||
|
|
@ -31,26 +32,25 @@ libed25519_la_SOURCES = \
|
|||
ed25519/precomp_data.h \
|
||||
ed25519/sc.c ed25519/sc.h \
|
||||
ed25519/sha512.c ed25519/sha512.h \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/sign.c \
|
||||
ed25519/verify.c
|
||||
|
||||
libtincconf_la_SOURCES = \
|
||||
conf.h\
|
||||
conf.c
|
||||
chacha_poly1305_SOURCES = \
|
||||
chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
|
||||
chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
|
||||
chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
|
||||
|
||||
libtincd_la_SOURCES = \
|
||||
conf.h \
|
||||
conf.c \
|
||||
tincd_SOURCES = \
|
||||
buffer.c buffer.h \
|
||||
cipher.h \
|
||||
conf.c conf.h \
|
||||
connection.c connection.h \
|
||||
control.c control.h \
|
||||
control_common.h \
|
||||
crypto.h \
|
||||
device.h \
|
||||
digest.h \
|
||||
dropin.c \
|
||||
dropin.c dropin.h \
|
||||
dummy_device.c \
|
||||
ecdh.h \
|
||||
ecdsa.h \
|
||||
|
|
@ -58,9 +58,6 @@ libtincd_la_SOURCES = \
|
|||
edge.c edge.h \
|
||||
ethernet.h \
|
||||
event.c event.h \
|
||||
fake-gai-errnos.h \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h \
|
||||
graph.c graph.h \
|
||||
hash.c hash.h \
|
||||
have.h \
|
||||
|
|
@ -78,6 +75,7 @@ libtincd_la_SOURCES = \
|
|||
netutl.c netutl.h \
|
||||
node.c node.h \
|
||||
prf.h \
|
||||
process.c process.h \
|
||||
protocol.c protocol.h \
|
||||
protocol_auth.c \
|
||||
protocol_edge.c \
|
||||
|
|
@ -94,117 +92,189 @@ libtincd_la_SOURCES = \
|
|||
subnet.c subnet.h \
|
||||
subnet_parse.c \
|
||||
system.h \
|
||||
tincd.c \
|
||||
utils.c utils.h \
|
||||
xalloc.h \
|
||||
version.c version.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
getopt.c getopt.h \
|
||||
process.h process.c \
|
||||
getopt1.c
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
tinc_SOURCES = \
|
||||
dropin.c dropin.h \
|
||||
fsck.c fsck.h \
|
||||
ifconfig.c ifconfig.h \
|
||||
info.c info.h \
|
||||
invitation.c invitation.h \
|
||||
list.c list.h \
|
||||
names.c names.h \
|
||||
netutl.c netutl.h \
|
||||
script.c script.h \
|
||||
sptps.c sptps.h \
|
||||
subnet_parse.c subnet.h \
|
||||
tincctl.c tincctl.h \
|
||||
top.c top.h \
|
||||
utils.c utils.h \
|
||||
version.c version.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_test_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_test.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_keypair_SOURCES = \
|
||||
sptps_keypair.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES)
|
||||
|
||||
sptps_speed_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_speed.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
## Conditionally compile device drivers
|
||||
|
||||
if !GETOPT
|
||||
tincd_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
tinc_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
sptps_test_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
sptps_keypair_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
libtincd_la_SOURCES += linux/device.c
|
||||
tincd_SOURCES += linux/device.c
|
||||
endif
|
||||
|
||||
if BSD
|
||||
libtincd_la_SOURCES += bsd/device.c
|
||||
tincd_SOURCES += bsd/device.c
|
||||
if TUNEMU
|
||||
libtincd_la_SOURCES += bsd/tunemu.c bsd/tunemu.h
|
||||
tincd_SOURCES += bsd/tunemu.c bsd/tunemu.h
|
||||
endif
|
||||
endif
|
||||
|
||||
if SOLARIS
|
||||
libtincd_la_SOURCES += solaris/device.c
|
||||
tincd_SOURCES += solaris/device.c
|
||||
endif
|
||||
|
||||
if MINGW
|
||||
libtincd_la_SOURCES += mingw/device.c mingw/common.h
|
||||
tincd_SOURCES += mingw/device.c mingw/common.h
|
||||
endif
|
||||
|
||||
if CYGWIN
|
||||
libtincd_la_SOURCES += cygwin/device.c
|
||||
tincd_SOURCES += cygwin/device.c
|
||||
endif
|
||||
|
||||
if UML
|
||||
libtincd_la_SOURCES += uml_device.c
|
||||
tincd_SOURCES += uml_device.c
|
||||
endif
|
||||
|
||||
if VDE
|
||||
libtincd_la_SOURCES += vde_device.c
|
||||
tincd_SOURCES += vde_device.c
|
||||
endif
|
||||
|
||||
if OPENSSL
|
||||
libtincd_la_SOURCES += \
|
||||
tincd_SOURCES += \
|
||||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c \
|
||||
openssl/rsa.c
|
||||
tinc_SOURCES += \
|
||||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c \
|
||||
openssl/rsa.c \
|
||||
openssl/rsagen.c
|
||||
sptps_test_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
openssl/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
else
|
||||
if GCRYPT
|
||||
libtincd_la_SOURCES += \
|
||||
tincd_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c \
|
||||
gcrypt/rsa.c
|
||||
tinc_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c \
|
||||
gcrypt/rsa.c \
|
||||
gcrypt/rsagen.c
|
||||
sptps_test_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
openssl/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
else
|
||||
libtincd_la_SOURCES += \
|
||||
tincd_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
tinc_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
sptps_test_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
nolegacy/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
endif
|
||||
endif
|
||||
|
||||
tincd_SOURCES = \
|
||||
conf.h \
|
||||
tincd.c
|
||||
|
||||
tinc_SOURCES = \
|
||||
invitation.c invitation.h \
|
||||
top.c top.h \
|
||||
fsck.c fsck.h \
|
||||
info.c info.h \
|
||||
ed25519/ecdsagen.c \
|
||||
tincctl.c tincctl.h
|
||||
|
||||
sptps_test_SOURCES = \
|
||||
sptps_test.c
|
||||
|
||||
sptps_keypair_SOURCES = \
|
||||
ed25519/ecdsagen.c \
|
||||
sptps_keypair.c
|
||||
|
||||
sptps_speed_SOURCES = \
|
||||
ed25519/ecdsagen.c \
|
||||
sptps_speed.c
|
||||
|
||||
|
||||
tincd_LDADD = libtincd.la libed25519.la libchacha_poly1305.la libtincconf.la
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) libtincd.la libtincconf.la libed25519.la libchacha_poly1305.la
|
||||
|
||||
sptps_speed_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
|
||||
sptps_test_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
|
||||
sptps_keypair_LDADD = libed25519.la libtincconf.la libchacha_poly1305.la libtincd.la libchacha_poly1305.la
|
||||
|
||||
if !DARWIN
|
||||
if !OPENBSD
|
||||
sptps_speed_LDADD += -lrt
|
||||
sptps_test_LDADD += -lrt
|
||||
sptps_keypair_LDADD += -lrt
|
||||
endif
|
||||
endif
|
||||
|
||||
if MINIUPNPC
|
||||
tincd_SOURCES += upnp.h upnp.c
|
||||
tincd_LDADD += $(MINIUPNPC_LIBS)
|
||||
tincd_LDFLAGS = ${tincd_LDFLAGS} -pthread
|
||||
tincd_LDADD = $(MINIUPNPC_LIBS)
|
||||
tincd_LDFLAGS = -pthread
|
||||
endif
|
||||
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
sptps_speed_LDADD = -lrt
|
||||
|
||||
LIBS = @LIBS@ -lm
|
||||
|
||||
if TUNEMU
|
||||
|
|
@ -212,17 +282,3 @@ LIBS += -lpcap
|
|||
endif
|
||||
|
||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote.
|
||||
if OPENBSD
|
||||
AM_CFLAGS += -fstack-protector-all
|
||||
endif
|
||||
|
||||
if BSD
|
||||
tincd_LDADD += -lexecinfo
|
||||
tinc_LDADD += -lexecinfo
|
||||
sptps_test_LDADD += -lexecinfo
|
||||
sptps_keypair_LDADD += -lexecinfo
|
||||
sptps_speed_LDADD += -lexecinfo
|
||||
endif
|
||||
|
||||
|
||||
#-fsanitize=address
|
||||
|
|
|
|||
156
src/bsd/device.c
156
src/bsd/device.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -34,13 +34,15 @@
|
|||
#include "bsd/tunemu.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#if defined(HAVE_DARWIN) || defined(HAVE_FREEBSD) || defined(HAVE_NETBSD)
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap0"
|
||||
#else
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tun0"
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
#include <sys/sys_domain.h>
|
||||
#include <sys/kern_control.h>
|
||||
#include <net/if_utun.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap0"
|
||||
|
||||
typedef enum device_type {
|
||||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TUNIFHEAD,
|
||||
|
|
@ -48,6 +50,7 @@ typedef enum device_type {
|
|||
#ifdef ENABLE_TUNEMU
|
||||
DEVICE_TYPE_TUNEMU,
|
||||
#endif
|
||||
DEVICE_TYPE_UTUN,
|
||||
} device_type_t;
|
||||
|
||||
int device_fd = -1;
|
||||
|
|
@ -62,9 +65,64 @@ static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
|
|||
static device_type_t device_type = DEVICE_TYPE_TUN;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
static bool setup_utun(void) {
|
||||
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||
if(device_fd == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ctl_info info = {};
|
||||
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof info.ctl_name);
|
||||
|
||||
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
int unit = -1;
|
||||
char *p = strstr(device, "utun"), *e = NULL;
|
||||
if(p) {
|
||||
unit = strtol(p + 4, &e, 10);
|
||||
if(!e)
|
||||
unit = -1;
|
||||
}
|
||||
|
||||
struct sockaddr_ctl sc = {
|
||||
.sc_id = info.ctl_id,
|
||||
.sc_len = sizeof sc,
|
||||
.sc_family = AF_SYSTEM,
|
||||
.ss_sysaddr = AF_SYS_CONTROL,
|
||||
.sc_unit = unit + 1,
|
||||
};
|
||||
|
||||
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
char name[64] = "";
|
||||
socklen_t len = sizeof name;
|
||||
if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) {
|
||||
iface = xstrdup(device);
|
||||
} else {
|
||||
iface = xstrdup(name);
|
||||
}
|
||||
|
||||
device_info = "OS X utun device";
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool setup_device(void) {
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
|
||||
// Find out if it's supposed to be a tun or a tap device
|
||||
|
||||
char *type;
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "tun"))
|
||||
|
|
@ -72,6 +130,10 @@ static bool setup_device(void) {
|
|||
#ifdef ENABLE_TUNEMU
|
||||
else if(!strcasecmp(type, "tunemu"))
|
||||
device_type = DEVICE_TYPE_TUNEMU;
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
else if(!strcasecmp(type, "utun"))
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
#endif
|
||||
else if(!strcasecmp(type, "tunnohead"))
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
|
|
@ -84,10 +146,22 @@ static bool setup_device(void) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0))
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
else
|
||||
#endif
|
||||
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER)
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Only tap devices support switch mode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find out which device file to open
|
||||
|
||||
if(!device) {
|
||||
if(device_type == DEVICE_TYPE_TAP)
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
|
|
@ -95,17 +169,7 @@ static bool setup_device(void) {
|
|||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = NULL;
|
||||
#ifndef TAPGIFNAME
|
||||
if (iface) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Ignoring specified interface name '%s' as device rename is not supported on this platform", iface);
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
}
|
||||
#endif
|
||||
if (!iface)
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
// Open the device
|
||||
|
||||
switch(device_type) {
|
||||
#ifdef ENABLE_TUNEMU
|
||||
|
|
@ -114,6 +178,10 @@ static bool setup_device(void) {
|
|||
device_fd = tunemu_open(dynamic_name);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
case DEVICE_TYPE_UTUN:
|
||||
return setup_utun();
|
||||
#endif
|
||||
default:
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
|
|
@ -128,6 +196,27 @@ static bool setup_device(void) {
|
|||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
// Guess what the corresponding interface is called
|
||||
|
||||
char *realname;
|
||||
|
||||
#if defined(HAVE_FDEVNAME)
|
||||
realname = fdevname(device_fd) ? : device;
|
||||
#elif defined(HAVE_DEVNAME)
|
||||
struct stat buf;
|
||||
if(!fstat(device_fd, &buf))
|
||||
realname = devname(buf.st_rdev, S_IFCHR) ? : device;
|
||||
#else
|
||||
realname = device;
|
||||
#endif
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
|
||||
else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname))
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
|
||||
|
||||
// Configure the device as best as we can
|
||||
|
||||
switch(device_type) {
|
||||
default:
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
|
|
@ -192,6 +281,11 @@ static bool setup_device(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFADDR
|
||||
if(overwrite_mac)
|
||||
ioctl(device_fd, SIOCGIFADDR, mymac.x);
|
||||
#endif
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
|
|
@ -253,31 +347,29 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
packet->len = inlen + 14;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
u_int32_t type;
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, MTU - 14}};
|
||||
|
||||
if((inlen = readv(device_fd, vector, 2)) <= 0) {
|
||||
if((inlen = read(device_fd, DATA(packet) + 10, MTU - 10)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ntohl(type)) {
|
||||
case AF_INET:
|
||||
switch (DATA(packet)[14] >> 4) {
|
||||
case 4:
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
case 6:
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown address family %x while reading packet from %s %s",
|
||||
ntohl(type), device_info, device);
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
DATA(packet)[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -319,12 +411,10 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
u_int32_t type;
|
||||
struct iovec vector[2] = {{&type, sizeof type}, {DATA(packet) + 14, packet->len - 14}};
|
||||
int af;
|
||||
|
||||
af = (DATA(packet)[12] << 8) + DATA(packet)[13];
|
||||
int af = (DATA(packet)[12] << 8) + DATA(packet)[13];
|
||||
uint32_t type;
|
||||
|
||||
switch (af) {
|
||||
case 0x0800:
|
||||
|
|
@ -340,7 +430,9 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(writev(device_fd, vector, 2) < 0) {
|
||||
memcpy(DATA(packet) + 10, &type, sizeof type);
|
||||
|
||||
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
#ifndef __TINC_CONF_H__
|
||||
#define __TINC_CONF_H__
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "list.h"
|
||||
#include "splay_tree.h"
|
||||
#include "subnet.h"
|
||||
|
||||
typedef struct config_t {
|
||||
char *variable;
|
||||
|
|
@ -31,7 +32,6 @@ typedef struct config_t {
|
|||
int line;
|
||||
} config_t;
|
||||
|
||||
#include "subnet.h"
|
||||
|
||||
extern splay_tree_t *config_tree;
|
||||
extern bool use_logfile;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "../system.h"
|
||||
#include "../net.h"
|
||||
|
||||
#include <w32api/windows.h>
|
||||
#include <w32api/winioctl.h>
|
||||
|
|
@ -27,7 +28,6 @@
|
|||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
|
@ -59,6 +59,9 @@ static bool setup_device(void) {
|
|||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(device && iface)
|
||||
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
|
||||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
|
|
|
|||
45
src/dropin.c
45
src/dropin.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
dropin.c -- a set of drop-in replacements for libc functions
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -86,40 +86,6 @@ int daemon(int nochdir, int noclose) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
/*
|
||||
Replacement for the GNU get_current_dir_name function:
|
||||
|
||||
get_current_dir_name will malloc(3) an array big enough to hold the
|
||||
current directory name. If the environment variable PWD is set, and
|
||||
its value is correct, then that value will be returned.
|
||||
*/
|
||||
char *get_current_dir_name(void) {
|
||||
size_t size;
|
||||
char *buf;
|
||||
char *r;
|
||||
|
||||
/* Start with 100 bytes. If this turns out to be insufficient to
|
||||
contain the working directory, double the size. */
|
||||
size = 100;
|
||||
buf = xmalloc(size);
|
||||
|
||||
errno = 0; /* Success */
|
||||
r = getcwd(buf, size);
|
||||
|
||||
/* getcwd returns NULL and sets errno to ERANGE if the bufferspace
|
||||
is insufficient to contain the entire working directory. */
|
||||
while(r == NULL && errno == ERANGE) {
|
||||
free(buf);
|
||||
size <<= 1; /* double the size */
|
||||
buf = xmalloc(size);
|
||||
r = getcwd(buf, size);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **buf, const char *fmt, ...) {
|
||||
int result;
|
||||
|
|
@ -174,10 +140,9 @@ int gettimeofday(struct timeval *tv, void *tz) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
int usleep(long long usec) {
|
||||
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
return 0;
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
|
||||
return select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
17
src/dropin.h
17
src/dropin.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
dropin.h -- header file for dropin.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -21,17 +21,10 @@
|
|||
#ifndef __DROPIN_H__
|
||||
#define __DROPIN_H__
|
||||
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "fake-getnameinfo.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon(int, int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
extern char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
extern int asprintf(char **, const char *, ...);
|
||||
extern int vasprintf(char **, const char *, va_list ap);
|
||||
|
|
@ -41,8 +34,8 @@ extern int vasprintf(char **, const char *, va_list ap);
|
|||
extern int gettimeofday(struct timeval *, void *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
extern int usleep(long long usec);
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
extern int nanosleep(const struct timespec *req, struct timespec *rem);
|
||||
#endif
|
||||
|
||||
#ifndef timeradd
|
||||
|
|
@ -70,4 +63,8 @@ extern int usleep(long long usec);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EAI_SYSTEM
|
||||
#define EAI_SYSTEM 0
|
||||
#endif
|
||||
|
||||
#endif /* __DROPIN_H__ */
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file is included in getaddrinfo.c and getnameinfo.c.
|
||||
* See getaddrinfo.c and getnameinfo.c.
|
||||
*/
|
||||
|
||||
/* for old netdb.h */
|
||||
#ifndef EAI_NODATA
|
||||
#define EAI_NODATA 1
|
||||
#endif
|
||||
|
||||
#ifndef EAI_MEMORY
|
||||
#define EAI_MEMORY 2
|
||||
#endif
|
||||
|
||||
#ifndef EAI_FAMILY
|
||||
#define EAI_FAMILY 3
|
||||
#endif
|
||||
|
||||
#ifndef EAI_SYSTEM
|
||||
#define EAI_SYSTEM 4
|
||||
#endif
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
|
||||
* These funtions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For exapmle, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode) {
|
||||
switch (ecode) {
|
||||
case EAI_NODATA:
|
||||
return "No address associated with hostname";
|
||||
case EAI_MEMORY:
|
||||
return "Memory allocation failure";
|
||||
case EAI_FAMILY:
|
||||
return "Address family not supported";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai) {
|
||||
struct addrinfo *next;
|
||||
|
||||
while(ai) {
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = xzalloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
|
||||
ai->ai_addr = (struct sockaddr *)(ai + 1);
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
struct addrinfo *prev = NULL;
|
||||
struct hostent *hp;
|
||||
struct in_addr in = {0};
|
||||
int i;
|
||||
uint16_t port = 0;
|
||||
|
||||
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC)
|
||||
return EAI_FAMILY;
|
||||
|
||||
if (servname)
|
||||
port = htons(atoi(servname));
|
||||
|
||||
if (hints && hints->ai_flags & AI_PASSIVE) {
|
||||
*res = malloc_ai(port, htonl(0x00000000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hostname) {
|
||||
*res = malloc_ai(port, htonl(0x7f000001));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0])
|
||||
return EAI_NODATA;
|
||||
|
||||
for (i = 0; hp->h_addr_list[i]; i++) {
|
||||
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
|
||||
|
||||
if(prev)
|
||||
prev->ai_next = *res;
|
||||
|
||||
prev = *res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef _FAKE_GETADDRINFO_H
|
||||
#define _FAKE_GETADDRINFO_H
|
||||
|
||||
#include "fake-gai-errnos.h"
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE 1
|
||||
# define AI_CANONNAME 2
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST 2
|
||||
# define NI_NAMEREQD 4
|
||||
# define NI_NUMERICSERV 8
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
#define AI_NUMERICHOST 4
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#endif /* _FAKE_GETADDRINFO_H */
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getnameinfo().
|
||||
* These funtions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For exapmle, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "fake-getnameinfo.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
struct hostent *hp;
|
||||
int len;
|
||||
|
||||
if(sa->sa_family != AF_INET)
|
||||
return EAI_FAMILY;
|
||||
|
||||
if(serv && servlen) {
|
||||
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
||||
if(len < 0 || len >= servlen)
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
if(!host || !hostlen)
|
||||
return 0;
|
||||
|
||||
if(flags & NI_NUMERICHOST) {
|
||||
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
|
||||
if(len < 0 || len >= hostlen)
|
||||
return EAI_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
|
||||
|
||||
if(!hp || !hp->h_name || !hp->h_name[0])
|
||||
return EAI_NODATA;
|
||||
|
||||
len = snprintf(host, hostlen, "%s", hp->h_name);
|
||||
if(len < 0 || len >= hostlen)
|
||||
return EAI_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef _FAKE_GETNAMEINFO_H
|
||||
#define _FAKE_GETNAMEINFO_H
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#endif /* _FAKE_GETNAMEINFO_H */
|
||||
18
src/fsck.c
18
src/fsck.c
|
|
@ -217,6 +217,7 @@ int fsck(const char *argv0) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
|
||||
if(st.st_mode & 077) {
|
||||
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
|
||||
if(st.st_uid != uid) {
|
||||
|
|
@ -228,6 +229,7 @@ int fsck(const char *argv0) {
|
|||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -256,6 +258,7 @@ int fsck(const char *argv0) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
|
||||
if(st.st_mode & 077) {
|
||||
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
|
||||
if(st.st_uid != uid) {
|
||||
|
|
@ -267,6 +270,7 @@ int fsck(const char *argv0) {
|
|||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DISABLE_LEGACY
|
||||
|
|
@ -282,7 +286,7 @@ int fsck(const char *argv0) {
|
|||
}
|
||||
|
||||
// Check for public keys.
|
||||
// TODO: use RSAPublicKeyFile and Ed25519PublicKeyFile variables if present.
|
||||
// TODO: use RSAPublicKeyFile variable if present.
|
||||
|
||||
snprintf(fname, sizeof fname, "%s/hosts/%s", confbase, name);
|
||||
if(access(fname, R_OK))
|
||||
|
|
@ -343,13 +347,17 @@ int fsck(const char *argv0) {
|
|||
fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// TODO: this should read the Ed25519PublicKey config variable instead.
|
||||
|
||||
ecdsa_t *ecdsa_pub = NULL;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if(f)
|
||||
ecdsa_pub = ecdsa_read_pem_public_key(f);
|
||||
if(f) {
|
||||
ecdsa_pub = get_pubkey(f);
|
||||
if(!f) {
|
||||
rewind(f);
|
||||
ecdsa_pub = ecdsa_read_pem_public_key(f);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if(ecdsa_priv) {
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
ecdsa.c -- ECDSA key handling
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "../logger.h"
|
||||
#include "../ecdsa.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
// Get and set ECDSA keys
|
||||
//
|
||||
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read PEM ECDSA keys
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
ecdsagen.c -- ECDSA key generation and export
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "../ecdsagen.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
// Generate ECDSA key
|
||||
|
||||
ecdsa_t *ecdsa_generate(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Write PEM ECDSA keys
|
||||
|
||||
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -19,11 +19,88 @@
|
|||
|
||||
#include "../system.h"
|
||||
|
||||
#include "digest.h"
|
||||
#include "../digest.h"
|
||||
#include "../prf.h"
|
||||
#include "../ed25519/sha512.h"
|
||||
|
||||
static void memxor(char *buf, char c, size_t len) {
|
||||
for(size_t i = 0; i < len; i++)
|
||||
buf[i] ^= c;
|
||||
}
|
||||
|
||||
static const size_t mdlen = 64;
|
||||
static const size_t blklen = 128;
|
||||
|
||||
static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) {
|
||||
char tmp[blklen + mdlen];
|
||||
sha512_context md;
|
||||
|
||||
if(keylen <= blklen) {
|
||||
memcpy(tmp, key, keylen);
|
||||
memset(tmp + keylen, 0, blklen - keylen);
|
||||
} else {
|
||||
if(sha512(key, keylen, tmp) != 0)
|
||||
return false;
|
||||
memset(tmp + mdlen, 0, blklen - mdlen);
|
||||
}
|
||||
|
||||
if(sha512_init(&md) != 0)
|
||||
return false;
|
||||
|
||||
// ipad
|
||||
memxor(tmp, 0x36, blklen);
|
||||
if(sha512_update(&md, tmp, blklen) != 0)
|
||||
return false;
|
||||
|
||||
// message
|
||||
if(sha512_update(&md, msg, msglen) != 0)
|
||||
return false;
|
||||
|
||||
if(sha512_final(&md, tmp + blklen) != 0)
|
||||
return false;
|
||||
|
||||
// opad
|
||||
memxor(tmp, 0x36 ^ 0x5c, blklen);
|
||||
if(sha512(tmp, sizeof tmp, out) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
|
||||
We use SHA512 instead of MD5 and SHA1.
|
||||
*/
|
||||
|
||||
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "PRF support using libgcrypt not implemented");
|
||||
return false;
|
||||
/* Data is what the "inner" HMAC function processes.
|
||||
It consists of the previous HMAC result plus the seed.
|
||||
*/
|
||||
|
||||
char data[mdlen + seedlen];
|
||||
memset(data, 0, mdlen);
|
||||
memcpy(data + mdlen, seed, seedlen);
|
||||
|
||||
char hash[mdlen];
|
||||
|
||||
while(outlen > 0) {
|
||||
/* Inner HMAC */
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof data, data))
|
||||
return false;
|
||||
|
||||
/* Outer HMAC */
|
||||
if(outlen >= mdlen) {
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof data, out))
|
||||
return false;
|
||||
out += mdlen;
|
||||
outlen -= mdlen;
|
||||
} else {
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof data, hash))
|
||||
return false;
|
||||
memcpy(out, hash, outlen);
|
||||
out += outlen;
|
||||
outlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
25
src/have.h
25
src/have.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
have.h -- include headers which are known to exist
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -22,17 +22,14 @@
|
|||
#define __TINC_HAVE_H__
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#ifdef WITH_WINDOWS2000
|
||||
#define WINVER Windows2000
|
||||
#else
|
||||
#define WINVER WindowsXP
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -41,6 +38,7 @@
|
|||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
|
|
@ -49,10 +47,6 @@
|
|||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
|
@ -71,9 +65,6 @@
|
|||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
|
|
@ -103,10 +94,6 @@
|
|||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
|
@ -210,6 +197,12 @@
|
|||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include "getopt.h"
|
||||
#endif
|
||||
|
||||
#ifdef STATUS
|
||||
#undef STATUS
|
||||
#endif
|
||||
|
|
|
|||
198
src/ifconfig.c
Normal file
198
src/ifconfig.c
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
ifconfig.c -- Generate platform specific interface configuration commands
|
||||
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "ifconfig.h"
|
||||
#include "subnet.h"
|
||||
|
||||
static long start;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
void ifconfig_header(FILE *out) {
|
||||
fprintf(out, "#!/bin/sh\n");
|
||||
start = ftell(out);
|
||||
}
|
||||
|
||||
void ifconfig_dhcp(FILE *out) {
|
||||
fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
|
||||
}
|
||||
|
||||
void ifconfig_dhcp6(FILE *out) {
|
||||
fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
|
||||
}
|
||||
|
||||
void ifconfig_slaac(FILE *out) {
|
||||
#ifdef HAVE_LINUX
|
||||
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
|
||||
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
|
||||
#else
|
||||
fprintf(out, "rtsol \"$INTERFACE\" &\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ifconfig_footer(FILE *out) {
|
||||
if(ftell(out) == start) {
|
||||
fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
|
||||
return false;
|
||||
} else {
|
||||
#ifdef HAVE_LINUX
|
||||
fprintf(out, "ip link set \"$INTERFACE\" up\n");
|
||||
#else
|
||||
fprintf(out, "ifconfig \"$INTERFACE\" up\n");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void ifconfig_header(FILE *out) {
|
||||
start = ftell(out);
|
||||
}
|
||||
|
||||
void ifconfig_dhcp(FILE *out) {
|
||||
fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n");
|
||||
}
|
||||
|
||||
void ifconfig_dhcp6(FILE *out) {
|
||||
fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
|
||||
}
|
||||
|
||||
void ifconfig_slaac(FILE *out) {
|
||||
// It's the default?
|
||||
}
|
||||
|
||||
bool ifconfig_footer(FILE *out) {
|
||||
return ftell(out) != start;
|
||||
}
|
||||
#endif
|
||||
|
||||
static subnet_t ipv4, ipv6;
|
||||
|
||||
void ifconfig_address(FILE *out, const char *value) {
|
||||
subnet_t address = {};
|
||||
char address_str[MAXNETSTR];
|
||||
if(!str2net(&address, value) || !net2str(address_str, sizeof address_str, &address)) {
|
||||
fprintf(stderr, "Could not parse address in Ifconfig statement\n");
|
||||
return;
|
||||
}
|
||||
switch(address.type) {
|
||||
case SUBNET_IPV4: ipv4 = address; break;
|
||||
case SUBNET_IPV6: ipv6 = address; break;
|
||||
default: return;
|
||||
}
|
||||
#if defined(HAVE_LINUX)
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
|
||||
case SUBNET_IPV4: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str); break;
|
||||
default: return;
|
||||
}
|
||||
#elif defined(HAVE_BSD)
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC: fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str); break;
|
||||
case SUBNET_IPV4: fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str); break;
|
||||
default: return;
|
||||
}
|
||||
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC: fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str); break;
|
||||
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", address_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", address_str); break;
|
||||
default: return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ifconfig_route(FILE *out, const char *value) {
|
||||
subnet_t subnet = {}, gateway = {};
|
||||
char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
|
||||
char *sep = strchr(value, ' ');
|
||||
if(sep)
|
||||
*sep++ = 0;
|
||||
if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof subnet_str, &subnet) || subnet.type == SUBNET_MAC) {
|
||||
fprintf(stderr, "Could not parse subnet in Route statement\n");
|
||||
return;
|
||||
}
|
||||
if(sep) {
|
||||
if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof gateway_str, &gateway) || gateway.type != subnet.type) {
|
||||
fprintf(stderr, "Could not parse gateway in Route statement\n");
|
||||
return;
|
||||
}
|
||||
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
|
||||
}
|
||||
#if defined(HAVE_LINUX)
|
||||
if(*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str); break;
|
||||
default: return;
|
||||
}
|
||||
} else {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_BSD)
|
||||
// BSD route command is silly and doesn't accept an interface name as a destination.
|
||||
if(!*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
if(!ipv4.type) {
|
||||
fprintf(stderr, "Route requested but no Ifconfig\n");
|
||||
return;
|
||||
}
|
||||
net2str(gateway_str, sizeof gateway_str, &ipv4);
|
||||
break;
|
||||
case SUBNET_IPV6:
|
||||
if(!ipv6.type) {
|
||||
fprintf(stderr, "Route requested but no Ifconfig\n");
|
||||
return;
|
||||
}
|
||||
net2str(gateway_str, sizeof gateway_str, &ipv6);
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
char *slash = strchr(gateway_str, '/'); if(slash) *slash = 0;
|
||||
}
|
||||
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4: fprintf(out, "route add %s %s\n", subnet_str, gateway_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str); break;
|
||||
default: return;
|
||||
}
|
||||
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
|
||||
if(*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str); break;
|
||||
default: return;
|
||||
}
|
||||
} else {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4: fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
|
||||
case SUBNET_IPV6: fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange handling
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
ifconfig.h -- header for ifconfig.c.
|
||||
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -17,21 +17,15 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
#ifndef __TINC_IFCONFIG_H__
|
||||
#define __TINC_IFCONFIG_H__
|
||||
|
||||
#include "../ecdh.h"
|
||||
#include "../logger.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
extern void ifconfig_dhcp(FILE *out);
|
||||
extern void ifconfig_dhcp6(FILE *out);
|
||||
extern void ifconfig_slaac(FILE *out);
|
||||
extern void ifconfig_address(FILE *out, const char *value);
|
||||
extern void ifconfig_route(FILE *out, const char *value);
|
||||
extern void ifconfig_header(FILE *out);
|
||||
extern bool ifconfig_footer(FILE *out);
|
||||
|
||||
ecdh_t *ecdh_generate_public(void *pubkey) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "EC support using libgcrypt not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
return false
|
||||
}
|
||||
|
||||
void ecdh_free(ecdh_t *ecdh) {
|
||||
}
|
||||
#endif
|
||||
|
|
@ -23,12 +23,14 @@
|
|||
#include "crypto.h"
|
||||
#include "ecdsa.h"
|
||||
#include "ecdsagen.h"
|
||||
#include "ifconfig.h"
|
||||
#include "invitation.h"
|
||||
#include "names.h"
|
||||
#include "netutl.h"
|
||||
#include "rsagen.h"
|
||||
#include "script.h"
|
||||
#include "sptps.h"
|
||||
#include "subnet.h"
|
||||
#include "tincctl.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
|
@ -390,7 +392,7 @@ int cmd_invite(int argc, char *argv[]) {
|
|||
|
||||
// Fill in the details.
|
||||
fprintf(f, "Name = %s\n", argv[1]);
|
||||
if(netname)
|
||||
if(check_netname(netname, true))
|
||||
fprintf(f, "NetName = %s\n", netname);
|
||||
fprintf(f, "ConnectTo = %s\n", myname);
|
||||
|
||||
|
|
@ -539,12 +541,17 @@ static bool finalize_join(void) {
|
|||
}
|
||||
|
||||
if(!check_id(name)) {
|
||||
fprintf(stderr, "Invalid Name found in invitation: %s!\n", name);
|
||||
fprintf(stderr, "Invalid Name found in invitation!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!netname)
|
||||
if(!netname) {
|
||||
netname = grep(data, "NetName");
|
||||
if(netname && !check_netname(netname, true)) {
|
||||
fprintf(stderr, "Unsafe NetName found in invitation!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ask_netname = false;
|
||||
char temp_netname[32];
|
||||
|
|
@ -602,7 +609,19 @@ make_names:
|
|||
return false;
|
||||
}
|
||||
|
||||
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
|
||||
FILE *fup = fopen(filename, "w");
|
||||
if(!fup) {
|
||||
fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
|
||||
fclose(f);
|
||||
fclose(fh);
|
||||
return false;
|
||||
}
|
||||
|
||||
ifconfig_header(fup);
|
||||
|
||||
// Filter first chunk on approved keywords, split between tinc.conf and hosts/Name
|
||||
// Generate a tinc-up script from Ifconfig and Route keywords.
|
||||
// Other chunks go unfiltered to their respective host config files
|
||||
const char *p = data;
|
||||
char *l, *value = NULL;
|
||||
|
|
@ -641,6 +660,24 @@ make_names:
|
|||
break;
|
||||
}
|
||||
|
||||
// Handle Ifconfig and Route statements
|
||||
if(!found) {
|
||||
if(!strcasecmp(l, "Ifconfig")) {
|
||||
if(!strcasecmp(value, "dhcp"))
|
||||
ifconfig_dhcp(fup);
|
||||
else if(!strcasecmp(value, "dhcp6"))
|
||||
ifconfig_dhcp6(fup);
|
||||
else if(!strcasecmp(value, "slaac"))
|
||||
ifconfig_slaac(fup);
|
||||
else
|
||||
ifconfig_address(fup, value);
|
||||
continue;
|
||||
} else if(!strcasecmp(l, "Route")) {
|
||||
ifconfig_route(fup, value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore unknown and unsafe variables
|
||||
if(!found) {
|
||||
fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l);
|
||||
|
|
@ -655,6 +692,8 @@ make_names:
|
|||
}
|
||||
|
||||
fclose(f);
|
||||
bool valid_tinc_up = ifconfig_footer(fup);
|
||||
fclose(fup);
|
||||
|
||||
while(l && !strcasecmp(l, "Name")) {
|
||||
if(!check_id(value)) {
|
||||
|
|
@ -769,6 +808,60 @@ ask_netname:
|
|||
make_names(false);
|
||||
}
|
||||
|
||||
char filename2[PATH_MAX];
|
||||
snprintf(filename, sizeof filename, "%s" SLASH "tinc-up.invitation", confbase);
|
||||
snprintf(filename2, sizeof filename2, "%s" SLASH "tinc-up", confbase);
|
||||
|
||||
if(valid_tinc_up) {
|
||||
if(tty) {
|
||||
FILE *fup = fopen(filename, "r");
|
||||
if(fup) {
|
||||
fprintf(stderr, "\nPlease review the following tinc-up script:\n\n");
|
||||
|
||||
char buf[MAXSIZE];
|
||||
while(fgets(buf, sizeof buf, fup))
|
||||
fputs(buf, stderr);
|
||||
fclose(fup);
|
||||
|
||||
int response = 0;
|
||||
do {
|
||||
fprintf(stderr, "\nDo you want to use this script [y]es/[n]o/[e]dit? ");
|
||||
response = tolower(getchar());
|
||||
} while(!strchr("yne", response));
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if(response == 'e') {
|
||||
char *command;
|
||||
#ifndef HAVE_MINGW
|
||||
xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
|
||||
#else
|
||||
xasprintf(&command, "edit \"%s\"", filename);
|
||||
#endif
|
||||
if(system(command))
|
||||
response = 'n';
|
||||
else
|
||||
response = 'y';
|
||||
free(command);
|
||||
}
|
||||
|
||||
if(response == 'y') {
|
||||
rename(filename, filename2);
|
||||
chmod(filename2, 0755);
|
||||
fprintf(stderr, "tinc-up enabled.\n");
|
||||
} else {
|
||||
fprintf(stderr, "tinc-up has been left disabled.\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "A tinc-up script was generated, but has been left disabled.\n");
|
||||
}
|
||||
} else {
|
||||
// A placeholder was generated.
|
||||
rename(filename, filename2);
|
||||
chmod(filename2, 0755);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Configuration stored in: %s\n", confbase);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
25
src/ipv6.h
25
src/ipv6.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
ipv6.h -- missing IPv6 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -29,29 +29,6 @@
|
|||
#define IPPROTO_ICMPV6 58
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t u6_addr8[16];
|
||||
uint16_t u6_addr16[8];
|
||||
uint32_t u6_addr32[4];
|
||||
} in6_u;
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define s6_addr in6_u.u6_addr8
|
||||
#define s6_addr16 in6_u.u6_addr16
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
uint16_t sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((((__const uint32_t *) (a))[0] == 0) \
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ static bool setup_device(void) {
|
|||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(device && iface)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
|
||||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ static void close_device(void) {
|
|||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = recv(device_fd, DATA(packet), MTU, 0)) <= 0) {
|
||||
if((lenin = recv(device_fd, (void *)DATA(packet), MTU, 0)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, sockstrerror(sockerrno));
|
||||
return false;
|
||||
|
|
@ -185,7 +185,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(sendto(device_fd, DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
if(sendto(device_fd, (void *)DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
sockstrerror(sockerrno));
|
||||
return false;
|
||||
|
|
|
|||
18
src/names.c
18
src/names.c
|
|
@ -57,14 +57,14 @@ void make_names(bool daemon) {
|
|||
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
|
||||
if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) {
|
||||
confdir = xstrdup(installdir);
|
||||
if(!logfilename)
|
||||
xasprintf(&logfilename, "%s" SLASH "log" SLASH "%s.log", installdir, identname);
|
||||
if(!confbase) {
|
||||
if(netname)
|
||||
xasprintf(&confbase, "%s" SLASH "%s", installdir, netname);
|
||||
else
|
||||
xasprintf(&confbase, "%s", installdir);
|
||||
}
|
||||
if(!logfilename)
|
||||
xasprintf(&logfilename, "%s" SLASH "tinc.log", confbase);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
|
@ -121,11 +121,11 @@ void make_names(bool daemon) {
|
|||
if(!unixsocketname) {
|
||||
int len = strlen(pidfilename);
|
||||
unixsocketname = xmalloc(len + 8);
|
||||
strcpy(unixsocketname, pidfilename);
|
||||
memcpy(unixsocketname, pidfilename, len);
|
||||
if(len > 4 && !strcmp(pidfilename + len - 4, ".pid"))
|
||||
strcpy(unixsocketname + len - 4, ".socket");
|
||||
strncpy(unixsocketname + len - 4, ".socket", 8);
|
||||
else
|
||||
strcpy(unixsocketname + len, ".socket");
|
||||
strncpy(unixsocketname + len, ".socket", 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,4 +137,12 @@ void free_names(void) {
|
|||
free(logfilename);
|
||||
free(confbase);
|
||||
free(confdir);
|
||||
|
||||
identname = NULL;
|
||||
netname = NULL;
|
||||
unixsocketname = NULL;
|
||||
pidfilename = NULL;
|
||||
logfilename = NULL;
|
||||
confbase = NULL;
|
||||
confdir = NULL;
|
||||
}
|
||||
|
|
|
|||
53
src/net.c
53
src/net.c
|
|
@ -180,7 +180,7 @@ static void periodic_handler(void *data) {
|
|||
|
||||
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
|
||||
usleep(sleeptime * 1000000LL);
|
||||
nanosleep(&(struct timespec){sleeptime, 0}, NULL);
|
||||
sleeptime *= 2;
|
||||
if(sleeptime < 0)
|
||||
sleeptime = 3600;
|
||||
|
|
@ -209,13 +209,25 @@ static void periodic_handler(void *data) {
|
|||
and we are not already trying to make one, create an
|
||||
outgoing connection to this node.
|
||||
*/
|
||||
splay_tree_t *tmp_node_tree;
|
||||
int count = 0;
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable))
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
|
||||
tmp_node_tree = splay_alloc_tree((splay_compare_t) node_compare, NULL);
|
||||
if(!count) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "No more nodes available for autoconnect!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
int r = rand() % count;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable))
|
||||
continue;
|
||||
|
||||
if ((!n->status.has_known_address && !n->status.has_cfg_address) || n->connection)
|
||||
if(r--)
|
||||
continue;
|
||||
|
||||
bool found = false;
|
||||
|
|
@ -226,29 +238,8 @@ static void periodic_handler(void *data) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
splay_insert(tmp_node_tree, n);
|
||||
}
|
||||
|
||||
if (tmp_node_tree->count) {
|
||||
int r = rand() % tmp_node_tree->count;
|
||||
int i = 0;
|
||||
|
||||
for splay_each(node_t, n, tmp_node_tree) {
|
||||
|
||||
if(i++ != r)
|
||||
continue;
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
||||
outgoing_t *outgoing = xzalloc(sizeof *outgoing);
|
||||
outgoing->name = xstrdup(n->name);
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing);
|
||||
}
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "No more nodes available for autoconnect!");
|
||||
break;
|
||||
}
|
||||
splay_delete_tree(tmp_node_tree);
|
||||
} else if(nc > 3) {
|
||||
/* Too many active connections, try to remove one.
|
||||
Choose a random outgoing connection to a node
|
||||
|
|
@ -295,6 +286,7 @@ static void periodic_handler(void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
end:
|
||||
timeout_set(data, &(struct timeval){5, rand() % 100000});
|
||||
}
|
||||
|
||||
|
|
@ -352,9 +344,14 @@ int reload_configuration(void) {
|
|||
for splay_each(subnet_t, subnet, subnet_tree)
|
||||
if (subnet->owner)
|
||||
subnet->expires = 1;
|
||||
}
|
||||
|
||||
load_all_nodes();
|
||||
for splay_each(node_t, n, node_tree)
|
||||
n->status.has_address = false;
|
||||
|
||||
load_all_nodes();
|
||||
|
||||
if(strictsubnets) {
|
||||
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||
if (!subnet->owner)
|
||||
continue;
|
||||
|
|
@ -455,7 +452,7 @@ void retry(void) {
|
|||
*/
|
||||
int main_loop(void) {
|
||||
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){0, 0});
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
signal_t sighup;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -115,6 +115,7 @@ typedef struct listen_socket_t {
|
|||
io_t udp;
|
||||
sockaddr_t sa;
|
||||
bool bindto;
|
||||
int priority;
|
||||
} listen_socket_t;
|
||||
|
||||
#include "conf.h"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_packet.c -- Handles in- and outgoing VPN packets
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010 Timothy Redaelli <timothy@redaelli.eu>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
|
@ -622,10 +622,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
vpn_packet_t *outpkt;
|
||||
int origlen = origpkt->len;
|
||||
size_t outlen;
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
static int priority = 0;
|
||||
int origpriority = origpkt->priority;
|
||||
#endif
|
||||
|
||||
pkt1.offset = DEFAULT_PACKET_OFFSET;
|
||||
pkt2.offset = DEFAULT_PACKET_OFFSET;
|
||||
|
|
@ -720,17 +717,29 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
if(!sa)
|
||||
choose_udp_address(n, &sa, &sock);
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
if(priorityinheritance && origpriority != priority
|
||||
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
|
||||
priority = origpriority;
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
|
||||
if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
|
||||
}
|
||||
if(priorityinheritance && origpriority != listen_socket[sock].priority) {
|
||||
listen_socket[sock].priority = origpriority;
|
||||
switch(sa->sa.sa_family) {
|
||||
#if defined(IPPROTO_IP) && defined(IP_TOS)
|
||||
case AF_INET:
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
|
||||
if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
|
||||
break;
|
||||
#endif
|
||||
#if defined(IPPROTO_IPV6) & defined(IPV6_TCLASS)
|
||||
case AF_INET6:
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
|
||||
if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sendto(listen_socket[sock].udp.fd, (void *)SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen)
|
||||
n->maxmtu = origlen - 1;
|
||||
|
|
@ -1557,7 +1566,7 @@ void handle_incoming_vpn_data(void *data, int flags) {
|
|||
socklen_t addrlen = sizeof addr;
|
||||
|
||||
pkt.offset = 0;
|
||||
int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
|
||||
int len = recvfrom(ls->udp.fd, (void *)DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
|
||||
|
||||
if(len <= 0 || len > MAXSIZE) {
|
||||
if(!sockwouldblock(sockerrno))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_setup.c -- Setup.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
|
@ -370,18 +370,18 @@ void load_all_nodes(void) {
|
|||
continue;
|
||||
|
||||
node_t *n = lookup_node(ent->d_name);
|
||||
splay_tree_t *config_tree;
|
||||
init_configuration(&config_tree);
|
||||
read_config_options(config_tree, ent->d_name);
|
||||
read_host_config(config_tree, ent->d_name);
|
||||
|
||||
if(!n) {
|
||||
n = new_node();
|
||||
n->name = xstrdup(ent->d_name);
|
||||
node_add(n);
|
||||
}
|
||||
|
||||
splay_tree_t *config_tree;
|
||||
init_configuration(&config_tree);
|
||||
read_config_options(config_tree, ent->d_name);
|
||||
read_host_config(config_tree, ent->d_name);
|
||||
|
||||
if (strictsubnets) {
|
||||
if(strictsubnets) {
|
||||
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s, *s2;
|
||||
|
||||
|
|
@ -397,10 +397,8 @@ void load_all_nodes(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (lookup_config(config_tree, "Address")) {
|
||||
n->status.has_known_address = true;
|
||||
n->status.has_cfg_address = true;
|
||||
}
|
||||
if(lookup_config(config_tree, "Address"))
|
||||
n->status.has_address = true;
|
||||
|
||||
exit_configuration(&config_tree);
|
||||
}
|
||||
|
|
@ -601,16 +599,14 @@ bool setup_myself_reloadable(void) {
|
|||
subnet_add(NULL, s);
|
||||
}
|
||||
|
||||
for (config_t* cfg = lookup_config(config_tree, "MulticastSubnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s;
|
||||
if (!get_config_subnet(cfg, &s))
|
||||
continue;
|
||||
subnet_add(NULL, s);
|
||||
}
|
||||
|
||||
#if !defined(SOL_IP) || !defined(IP_TOS)
|
||||
#if !defined(IPPROTO_IP) || !defined(IP_TOS)
|
||||
if(priorityinheritance)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv4 connections", "PriorityInheritance");
|
||||
#endif
|
||||
|
||||
#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS)
|
||||
if(priorityinheritance)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "%s not supported on this platform for IPv6 connections", "PriorityInheritance");
|
||||
#endif
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
|
||||
|
|
@ -1172,8 +1168,7 @@ void close_network_connections(void) {
|
|||
|
||||
if(myself && myself->connection) {
|
||||
subnet_update(myself, NULL, false);
|
||||
terminate_connection(myself->connection, false);
|
||||
free_connection(myself->connection);
|
||||
connection_del(myself->connection);
|
||||
}
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net_socket.c -- Handle various kinds of sockets.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2009 Florian Forster <octo@verplant.org>
|
||||
|
||||
|
|
@ -35,11 +35,6 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Needed on Mac OS/X */
|
||||
#ifndef SOL_TCP
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
#endif
|
||||
|
||||
int addressfamily = AF_UNSPEC;
|
||||
int maxtimeout = 900;
|
||||
int seconds_till_retry = 5;
|
||||
|
|
@ -73,14 +68,19 @@ static void configure_tcp(connection_t *c) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SOL_TCP) && defined(TCP_NODELAY)
|
||||
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
|
||||
option = 1;
|
||||
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option);
|
||||
setsockopt(c->socket, IPPROTO_TCP, TCP_NODELAY, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
|
||||
#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
|
||||
option = IPTOS_LOWDELAY;
|
||||
setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option);
|
||||
setsockopt(c->socket, IPPROTO_IP, IP_TOS, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY)
|
||||
option = IPTOS_LOWDELAY;
|
||||
setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof option);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +163,9 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
option = 1;
|
||||
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
if(sa->sa.sa_family == AF_INET6)
|
||||
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
if(get_config_string
|
||||
|
|
@ -261,10 +261,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
#define IP_DONTFRAGMENT IP_DONTFRAG
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
|
||||
#if defined(IPPROTO_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = IP_PMTUDISC_DO;
|
||||
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
}
|
||||
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
|
|
@ -273,10 +273,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = IPV6_PMTUDISC_DO;
|
||||
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
}
|
||||
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
|
|
@ -517,10 +517,10 @@ begin:
|
|||
#endif
|
||||
|
||||
if(proxytype != PROXY_EXEC) {
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
|
|
@ -547,6 +547,7 @@ begin:
|
|||
|
||||
/* Now that there is a working socket, fill in the rest and register this connection. */
|
||||
|
||||
c->last_ping_time = time(NULL);
|
||||
c->status.connecting = true;
|
||||
c->name = xstrdup(outgoing->name);
|
||||
#ifndef DISABLE_LEGACY
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ bool dump_nodes(connection_t *c) {
|
|||
for splay_each(node_t, n, node_tree) {
|
||||
char id[2 * sizeof n->id + 1];
|
||||
for (size_t c = 0; c < sizeof n->id; ++c)
|
||||
sprintf(id + 2 * c, "%02hhx", n->id.x[c]);
|
||||
snprintf(id + 2 * c, 3, "%02hhx", n->id.x[c]);
|
||||
id[sizeof id - 1] = 0;
|
||||
send_request(c, "%d %d %s %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
|
||||
n->name, id, n->hostname ?: "unknown port unknown",
|
||||
|
|
|
|||
|
|
@ -40,9 +40,8 @@ typedef struct node_status_t {
|
|||
unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */
|
||||
unsigned int udppacket:1; /* 1 if the most recently received packet was UDP */
|
||||
unsigned int validkey_in:1; /* 1 if we have sent a valid key to him */
|
||||
unsigned int has_known_address; /* 1 if this node has UDP Address */
|
||||
unsigned int has_cfg_address; /* 1 if this node has Address in node's config */
|
||||
unsigned int unused:21;
|
||||
unsigned int has_address:1; /* 1 if we know an external address for this node */
|
||||
unsigned int unused:20;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
|
|
|
|||
|
|
@ -62,12 +62,9 @@ static bool install_service(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!strchr(program_name, '\\')) {
|
||||
GetCurrentDirectory(sizeof command - 1, command + 1);
|
||||
strncat(command, "\\", sizeof command - strlen(command));
|
||||
}
|
||||
|
||||
strncat(command, program_name, sizeof command - strlen(command));
|
||||
HMODULE module = GetModuleHandle(NULL);
|
||||
GetModuleFileName(module, command + 1, sizeof command - 1);
|
||||
command[sizeof command - 1] = 0;
|
||||
|
||||
strncat(command, "\"", sizeof command - strlen(command));
|
||||
|
||||
|
|
@ -203,7 +200,7 @@ bool detach(void) {
|
|||
|
||||
if(do_detach) {
|
||||
#ifndef HAVE_MINGW
|
||||
if(daemon(0, 0)) {
|
||||
if(daemon(1, 0)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ static bool send_proxyrequest(connection_t *c) {
|
|||
i += 2;
|
||||
c->tcplen += 22;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
|
||||
return false;
|
||||
}
|
||||
if(i > len)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ bool add_edge_h(connection_t *c, const char *request) {
|
|||
"ADD_EDGE", c->name, c->hostname, e->from->name, e->to->name);
|
||||
e->address = address;
|
||||
}
|
||||
goto exit_with_graph;
|
||||
goto done;
|
||||
}
|
||||
} else if(sockaddrcmp(&e->local_address, &local_address)) {
|
||||
if(from == myself) {
|
||||
|
|
@ -221,8 +221,8 @@ bool add_edge_h(connection_t *c, const char *request) {
|
|||
e->avg_rtt = weight/10;
|
||||
edge_add(e);
|
||||
|
||||
done:
|
||||
/* Tell the rest about the new edge */
|
||||
exit_with_graph:
|
||||
if(!tunnelserver)
|
||||
forward_request(c, request);
|
||||
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ bool ans_key_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
|
||||
if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) {
|
||||
char *address, *port;
|
||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
|
||||
sockaddr2str(&from->address, &address, &port);
|
||||
|
|
|
|||
507
src/route.c
507
src/route.c
|
|
@ -105,6 +105,260 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void swap_mac_addresses(vpn_packet_t *packet) {
|
||||
mac_t tmp;
|
||||
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
|
||||
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
|
||||
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
/* RFC 792 */
|
||||
|
||||
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip ip = {0};
|
||||
struct icmp icmp = {0};
|
||||
|
||||
struct in_addr ip_src;
|
||||
struct in_addr ip_dst;
|
||||
uint32_t oldlen;
|
||||
|
||||
if(ratelimit(3))
|
||||
return;
|
||||
|
||||
/* Swap Ethernet source and destination addresses */
|
||||
|
||||
swap_mac_addresses(packet);
|
||||
|
||||
/* Copy headers from packet into properly aligned structs on the stack */
|
||||
|
||||
memcpy(&ip, DATA(packet) + ether_size, ip_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
ip_src = ip.ip_src;
|
||||
ip_dst = ip.ip_dst;
|
||||
|
||||
/* Try to reply with an IP address assigned to the local machine */
|
||||
|
||||
if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) {
|
||||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd != -1) {
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = ip.ip_src;
|
||||
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
|
||||
ip_dst = addr.sin_addr;
|
||||
}
|
||||
}
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
|
||||
oldlen = packet->len - ether_size;
|
||||
|
||||
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
|
||||
icmp.icmp_nextmtu = htons(packet->len - ether_size);
|
||||
|
||||
if(oldlen >= IP_MSS - ip_size - icmp_size)
|
||||
oldlen = IP_MSS - ip_size - icmp_size;
|
||||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
|
||||
|
||||
/* Fill in IPv4 header */
|
||||
|
||||
ip.ip_v = 4;
|
||||
ip.ip_hl = ip_size / 4;
|
||||
ip.ip_tos = 0;
|
||||
ip.ip_len = htons(ip_size + icmp_size + oldlen);
|
||||
ip.ip_id = 0;
|
||||
ip.ip_off = 0;
|
||||
ip.ip_ttl = 255;
|
||||
ip.ip_p = IPPROTO_ICMP;
|
||||
ip.ip_sum = 0;
|
||||
ip.ip_src = ip_dst;
|
||||
ip.ip_dst = ip_src;
|
||||
|
||||
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
|
||||
|
||||
/* Fill in ICMP header */
|
||||
|
||||
icmp.icmp_type = type;
|
||||
icmp.icmp_code = code;
|
||||
icmp.icmp_cksum = 0;
|
||||
|
||||
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
|
||||
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(DATA(packet) + ether_size, &ip, ip_size);
|
||||
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
|
||||
|
||||
packet->len = ether_size + ip_size + icmp_size + oldlen;
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
||||
/* RFC 2463 */
|
||||
|
||||
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip6_hdr ip6;
|
||||
struct icmp6_hdr icmp6 = {0};
|
||||
uint16_t checksum;
|
||||
|
||||
struct {
|
||||
struct in6_addr ip6_src; /* source address */
|
||||
struct in6_addr ip6_dst; /* destination address */
|
||||
uint32_t length;
|
||||
uint32_t next;
|
||||
} pseudo;
|
||||
|
||||
if(ratelimit(3))
|
||||
return;
|
||||
|
||||
/* Swap Ethernet source and destination addresses */
|
||||
|
||||
swap_mac_addresses(packet);
|
||||
|
||||
/* Copy headers from packet to structs on the stack */
|
||||
|
||||
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
pseudo.ip6_src = ip6.ip6_dst;
|
||||
pseudo.ip6_dst = ip6.ip6_src;
|
||||
|
||||
/* Try to reply with an IP address assigned to the local machine */
|
||||
|
||||
if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) {
|
||||
int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (sockfd != -1) {
|
||||
struct sockaddr_in6 addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_addr = ip6.ip6_src;
|
||||
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
|
||||
pseudo.ip6_src = addr.sin6_addr;
|
||||
}
|
||||
}
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
|
||||
pseudo.length = packet->len - ether_size;
|
||||
|
||||
if(type == ICMP6_PACKET_TOO_BIG)
|
||||
icmp6.icmp6_mtu = htonl(pseudo.length);
|
||||
|
||||
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
|
||||
pseudo.length = IP_MSS - ip6_size - icmp6_size;
|
||||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
|
||||
|
||||
/* Fill in IPv6 header */
|
||||
|
||||
ip6.ip6_flow = htonl(0x60000000UL);
|
||||
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
|
||||
ip6.ip6_nxt = IPPROTO_ICMPV6;
|
||||
ip6.ip6_hlim = 255;
|
||||
ip6.ip6_src = pseudo.ip6_src;
|
||||
ip6.ip6_dst = pseudo.ip6_dst;
|
||||
|
||||
/* Fill in ICMP header */
|
||||
|
||||
icmp6.icmp6_type = type;
|
||||
icmp6.icmp6_code = code;
|
||||
icmp6.icmp6_cksum = 0;
|
||||
|
||||
/* Create pseudo header */
|
||||
|
||||
pseudo.length = htonl(icmp6_size + pseudo.length);
|
||||
pseudo.next = htonl(IPPROTO_ICMPV6);
|
||||
|
||||
/* Generate checksum */
|
||||
|
||||
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
|
||||
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
|
||||
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
|
||||
|
||||
icmp6.icmp6_cksum = checksum;
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
|
||||
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
|
||||
|
||||
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
||||
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = DATA(packet)[16] << 8 | DATA(packet)[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(DATA(packet)[ethlen + 8] <= 1) {
|
||||
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
|
||||
DATA(packet)[ethlen + 8]--;
|
||||
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
|
||||
|
||||
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
DATA(packet)[ethlen + 10] = checksum >> 8;
|
||||
DATA(packet)[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
case ETH_P_IPV6:
|
||||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(DATA(packet)[ethlen + 7] <= 1) {
|
||||
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
DATA(packet)[ethlen + 7]--;
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
|
||||
if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
|
||||
return;
|
||||
|
|
@ -186,13 +440,6 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
}
|
||||
}
|
||||
|
||||
static void swap_mac_addresses(vpn_packet_t *packet) {
|
||||
mac_t tmp;
|
||||
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
|
||||
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
|
||||
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
static void age_subnets(void *data) {
|
||||
bool left = false;
|
||||
UNUSED(data);
|
||||
|
|
@ -251,80 +498,12 @@ static void learn_mac(mac_t *address) {
|
|||
}
|
||||
}
|
||||
|
||||
/* RFC 792 */
|
||||
static void route_broadcast(node_t *source, vpn_packet_t *packet) {
|
||||
if(decrement_ttl && source != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip ip;
|
||||
struct icmp icmp;
|
||||
|
||||
struct in_addr ip_src;
|
||||
struct in_addr ip_dst;
|
||||
uint32_t oldlen;
|
||||
|
||||
memset(&ip, 0x0, sizeof(ip));
|
||||
memset(&icmp, 0x0, sizeof(icmp));
|
||||
|
||||
if(ratelimit(3))
|
||||
return;
|
||||
|
||||
/* Swap Ethernet source and destination addresses */
|
||||
|
||||
swap_mac_addresses(packet);
|
||||
|
||||
/* Copy headers from packet into properly aligned structs on the stack */
|
||||
|
||||
memcpy(&ip, DATA(packet) + ether_size, ip_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
ip_src = ip.ip_src;
|
||||
ip_dst = ip.ip_dst;
|
||||
|
||||
oldlen = packet->len - ether_size;
|
||||
|
||||
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
|
||||
icmp.icmp_nextmtu = htons(packet->len - ether_size);
|
||||
|
||||
if(oldlen >= IP_MSS - ip_size - icmp_size)
|
||||
oldlen = IP_MSS - ip_size - icmp_size;
|
||||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
|
||||
|
||||
/* Fill in IPv4 header */
|
||||
|
||||
ip.ip_v = 4;
|
||||
ip.ip_hl = ip_size / 4;
|
||||
ip.ip_tos = 0;
|
||||
ip.ip_len = htons(ip_size + icmp_size + oldlen);
|
||||
ip.ip_id = 0;
|
||||
ip.ip_off = 0;
|
||||
ip.ip_ttl = 255;
|
||||
ip.ip_p = IPPROTO_ICMP;
|
||||
ip.ip_sum = 0;
|
||||
ip.ip_src = ip_dst;
|
||||
ip.ip_dst = ip_src;
|
||||
|
||||
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
|
||||
|
||||
/* Fill in ICMP header */
|
||||
|
||||
icmp.icmp_type = type;
|
||||
icmp.icmp_code = code;
|
||||
icmp.icmp_cksum = 0;
|
||||
|
||||
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
|
||||
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(DATA(packet) + ether_size, &ip, ip_size);
|
||||
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
|
||||
|
||||
packet->len = ether_size + ip_size + icmp_size + oldlen;
|
||||
|
||||
send_packet(source, packet);
|
||||
broadcast_packet(source, packet);
|
||||
}
|
||||
|
||||
/* RFC 791 */
|
||||
|
|
@ -411,7 +590,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if (!subnet->owner) {
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -426,6 +605,10 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
|
||||
if(decrement_ttl && source != myself && subnet->owner != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
if(priorityinheritance)
|
||||
packet->priority = DATA(packet)[15];
|
||||
|
||||
|
|
@ -456,90 +639,6 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
/* RFC 2463 */
|
||||
|
||||
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip6_hdr ip6;
|
||||
struct icmp6_hdr icmp6;
|
||||
uint16_t checksum;
|
||||
|
||||
struct {
|
||||
struct in6_addr ip6_src; /* source address */
|
||||
struct in6_addr ip6_dst; /* destination address */
|
||||
uint32_t length;
|
||||
uint32_t next;
|
||||
} pseudo;
|
||||
|
||||
memset(&ip6, 0x0, sizeof(struct ip6_hdr));
|
||||
memset(&icmp6, 0x0, sizeof(struct icmp6_hdr));
|
||||
memset(&pseudo, 0x0, sizeof(pseudo));
|
||||
|
||||
if(ratelimit(3))
|
||||
return;
|
||||
|
||||
/* Swap Ethernet source and destination addresses */
|
||||
|
||||
swap_mac_addresses(packet);
|
||||
|
||||
/* Copy headers from packet to structs on the stack */
|
||||
|
||||
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
|
||||
|
||||
/* Remember original source and destination */
|
||||
|
||||
pseudo.ip6_src = ip6.ip6_dst;
|
||||
pseudo.ip6_dst = ip6.ip6_src;
|
||||
|
||||
pseudo.length = packet->len - ether_size;
|
||||
|
||||
if(type == ICMP6_PACKET_TOO_BIG)
|
||||
icmp6.icmp6_mtu = htonl(pseudo.length);
|
||||
|
||||
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
|
||||
pseudo.length = IP_MSS - ip6_size - icmp6_size;
|
||||
|
||||
/* Copy first part of original contents to ICMP message */
|
||||
|
||||
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
|
||||
|
||||
/* Fill in IPv6 header */
|
||||
|
||||
ip6.ip6_flow = htonl(0x60000000UL);
|
||||
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
|
||||
ip6.ip6_nxt = IPPROTO_ICMPV6;
|
||||
ip6.ip6_hlim = 255;
|
||||
ip6.ip6_src = pseudo.ip6_src;
|
||||
ip6.ip6_dst = pseudo.ip6_dst;
|
||||
|
||||
/* Fill in ICMP header */
|
||||
|
||||
icmp6.icmp6_type = type;
|
||||
icmp6.icmp6_code = code;
|
||||
icmp6.icmp6_cksum = 0;
|
||||
|
||||
/* Create pseudo header */
|
||||
|
||||
pseudo.length = htonl(icmp6_size + pseudo.length);
|
||||
pseudo.next = htonl(IPPROTO_ICMPV6);
|
||||
|
||||
/* Generate checksum */
|
||||
|
||||
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
|
||||
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
|
||||
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
|
||||
|
||||
icmp6.icmp6_cksum = checksum;
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
|
||||
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
|
||||
|
||||
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
||||
static void route_neighborsol(node_t *source, vpn_packet_t *packet);
|
||||
|
||||
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
||||
|
|
@ -611,7 +710,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -626,6 +725,10 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
|||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
|
||||
|
||||
if(decrement_ttl && source != myself && subnet->owner != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
|
||||
|
||||
if(via == source) {
|
||||
|
|
@ -742,6 +845,10 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
|
|||
if(subnet->owner == myself)
|
||||
return; /* silently ignore */
|
||||
|
||||
if(decrement_ttl)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
/* Create neighbor advertation reply */
|
||||
|
||||
memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
|
||||
|
|
@ -837,6 +944,10 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
|
|||
if(subnet->owner == myself)
|
||||
return; /* silently ignore */
|
||||
|
||||
if(decrement_ttl)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
memcpy(&addr, arp.arp_tpa, sizeof addr); /* save protocol addr */
|
||||
memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr); /* swap destination and source protocol address */
|
||||
memcpy(arp.arp_spa, &addr, sizeof addr); /* ... */
|
||||
|
|
@ -871,7 +982,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
subnet = lookup_subnet_mac(NULL, &dest);
|
||||
|
||||
if(!subnet || !subnet->owner) {
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -883,6 +994,10 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return;
|
||||
|
||||
if(decrement_ttl && source != myself && subnet->owner != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
|
||||
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
|
||||
|
|
@ -941,58 +1056,6 @@ static void send_pcap(vpn_packet_t *packet) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = DATA(packet)[16] << 8 | DATA(packet)[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(DATA(packet)[ethlen + 8] < 1) {
|
||||
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
|
||||
DATA(packet)[ethlen + 8]--;
|
||||
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
|
||||
|
||||
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
DATA(packet)[ethlen + 10] = checksum >> 8;
|
||||
DATA(packet)[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
case ETH_P_IPV6:
|
||||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(DATA(packet)[ethlen + 7] < 1) {
|
||||
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
DATA(packet)[ethlen + 7]--;
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void route(node_t *source, vpn_packet_t *packet) {
|
||||
if(pcap)
|
||||
send_pcap(packet);
|
||||
|
|
@ -1005,10 +1068,6 @@ void route(node_t *source, vpn_packet_t *packet) {
|
|||
if(!checklength(source, packet, ether_size))
|
||||
return;
|
||||
|
||||
if(decrement_ttl && source != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||
|
||||
switch (routing_mode) {
|
||||
|
|
@ -1037,7 +1096,7 @@ void route(node_t *source, vpn_packet_t *packet) {
|
|||
break;
|
||||
|
||||
case RMODE_HUB:
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
src/script.c
63
src/script.c
|
|
@ -26,8 +26,44 @@
|
|||
#include "script.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
static void unputenv(const char *p) {
|
||||
const char *e = strchr(p, '=');
|
||||
if(!e)
|
||||
return;
|
||||
int len = e - p;
|
||||
#ifndef HAVE_UNSETENV
|
||||
#ifdef HAVE_MINGW
|
||||
// Windows requires putenv("FOO=") to unset %FOO%
|
||||
len++;
|
||||
#endif
|
||||
#endif
|
||||
char var[len + 1];
|
||||
strncpy(var, p, len);
|
||||
var[len] = 0;
|
||||
#ifdef HAVE_UNSETENV
|
||||
unsetenv(var);
|
||||
#else
|
||||
// We must keep what we putenv() around in memory.
|
||||
// To do this without memory leaks, keep things in a list and reuse if possible.
|
||||
static list_t list = {};
|
||||
for list_each(char, data, &list) {
|
||||
if(!strcmp(data, var)) {
|
||||
putenv(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
char *data = xstrdup(var);
|
||||
list_insert_tail(&list, data);
|
||||
putenv(data);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void putenv(const char *p) {}
|
||||
static void unputenv(const char *p) {}
|
||||
#endif
|
||||
|
||||
bool execute_script(const char *name, char **envp) {
|
||||
#ifdef HAVE_SYSTEM
|
||||
char scriptname[PATH_MAX];
|
||||
char *command;
|
||||
|
||||
|
|
@ -38,9 +74,11 @@ bool execute_script(const char *name, char **envp) {
|
|||
#ifdef HAVE_MINGW
|
||||
if(!*scriptextension) {
|
||||
const char *pathext = getenv("PATHEXT") ?: ".COM;.EXE;.BAT;.CMD";
|
||||
char fullname[strlen(scriptname) + strlen(pathext)];
|
||||
char *ext = fullname + strlen(scriptname);
|
||||
strcpy(fullname, scriptname);
|
||||
size_t pathlen = strlen(pathext);
|
||||
size_t scriptlen = strlen(scriptname);
|
||||
char fullname[scriptlen + pathlen + 1];
|
||||
char *ext = fullname + scriptlen;
|
||||
strncpy(fullname, scriptname, sizeof fullname);
|
||||
|
||||
const char *p = pathext;
|
||||
bool found = false;
|
||||
|
|
@ -51,7 +89,7 @@ bool execute_script(const char *name, char **envp) {
|
|||
ext[q - p] = 0;
|
||||
q++;
|
||||
} else {
|
||||
strcpy(ext, p);
|
||||
strncpy(ext, p, pathlen + 1);
|
||||
}
|
||||
if((found = !access(fullname, F_OK)))
|
||||
break;
|
||||
|
|
@ -67,12 +105,10 @@ bool execute_script(const char *name, char **envp) {
|
|||
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Executing script %s", name);
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
/* Set environment */
|
||||
|
||||
for(int i = 0; envp[i]; i++)
|
||||
putenv(envp[i]);
|
||||
#endif
|
||||
|
||||
if(scriptinterpreter)
|
||||
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
|
||||
|
|
@ -85,15 +121,8 @@ bool execute_script(const char *name, char **envp) {
|
|||
|
||||
/* Unset environment */
|
||||
|
||||
for(int i = 0; envp[i]; i++) {
|
||||
char *e = strchr(envp[i], '=');
|
||||
if(e) {
|
||||
char p[e - envp[i] + 1];
|
||||
strncpy(p, envp[i], e - envp[i]);
|
||||
p[e - envp[i]] = '\0';
|
||||
putenv(p);
|
||||
}
|
||||
}
|
||||
for(int i = 0; envp[i]; i++)
|
||||
unputenv(envp[i]);
|
||||
|
||||
if(status != -1) {
|
||||
#ifdef WEXITSTATUS
|
||||
|
|
@ -116,6 +145,6 @@ bool execute_script(const char *name, char **envp) {
|
|||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
|
|||
|
||||
// Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
|
||||
char seed[s->labellen + 64 + 13];
|
||||
strcpy(seed, "key expansion");
|
||||
memcpy(seed, "key expansion", 13);
|
||||
if(s->initiator) {
|
||||
memcpy(seed + 13, s->mykex + 1, 32);
|
||||
memcpy(seed + 45, s->hiskex + 1, 32);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,15 @@
|
|||
#include "sptps.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Symbols necessary to link with logger.o
|
||||
bool send_request(void *c, const char *msg, ...) { return false; }
|
||||
struct list_t *connection_list = NULL;
|
||||
bool send_meta(void *c, const char *msg , int len) { return false; }
|
||||
char *logfilename = NULL;
|
||||
bool do_detach = false;
|
||||
struct timeval now;
|
||||
|
||||
static bool special;
|
||||
static bool verbose;
|
||||
static bool readonly;
|
||||
static bool writeonly;
|
||||
|
|
@ -64,6 +73,7 @@ static struct option const long_options[] = {
|
|||
{"writeonly", no_argument, NULL, 'w'},
|
||||
{"packet-loss", required_argument, NULL, 'L'},
|
||||
{"replay-window", required_argument, NULL, 'W'},
|
||||
{"special", no_argument, NULL, 's'},
|
||||
{"verbose", required_argument, NULL, 'v'},
|
||||
{"help", no_argument, NULL, 1},
|
||||
{NULL, 0, NULL, 0}
|
||||
|
|
@ -83,6 +93,7 @@ static void usage() {
|
|||
" -w, --writeonly Only send data from stdin to the socket.\n"
|
||||
" -L, --packet-loss RATE Fake packet loss of RATE percent.\n"
|
||||
" -R, --replay-window N Set replay window to N bytes.\n"
|
||||
" -s, --special Enable special handling of lines starting with #, ^ and $.\n"
|
||||
" -v, --verbose Display debug messages.\n"
|
||||
"\n");
|
||||
fprintf(stderr, "Report bugs to tinc@tinc-vpn.org.\n");
|
||||
|
|
@ -101,7 +112,7 @@ int main(int argc, char *argv[]) {
|
|||
ecdsa_t *mykey = NULL, *hiskey = NULL;
|
||||
bool quit = false;
|
||||
|
||||
while((r = getopt_long(argc, argv, "dqrtwL:W:v", long_options, &option_index)) != EOF) {
|
||||
while((r = getopt_long(argc, argv, "dqrstwL:W:v", long_options, &option_index)) != EOF) {
|
||||
switch (r) {
|
||||
case 0: /* long option */
|
||||
break;
|
||||
|
|
@ -144,6 +155,10 @@ int main(int argc, char *argv[]) {
|
|||
verbose = true;
|
||||
break;
|
||||
|
||||
case 's': /* special character handling */
|
||||
special = true;
|
||||
break;
|
||||
|
||||
case '?': /* wrong options */
|
||||
usage();
|
||||
return 1;
|
||||
|
|
@ -318,11 +333,11 @@ int main(int argc, char *argv[]) {
|
|||
readonly = true;
|
||||
continue;
|
||||
}
|
||||
if(buf[0] == '#')
|
||||
if(special && buf[0] == '#')
|
||||
s.outseqno = atoi(buf + 1);
|
||||
if(buf[0] == '^')
|
||||
if(special && buf[0] == '^')
|
||||
sptps_send_record(&s, SPTPS_HANDSHAKE, NULL, 0);
|
||||
else if(buf[0] == '$') {
|
||||
else if(special && buf[0] == '$') {
|
||||
sptps_force_kex(&s);
|
||||
if(len > 1)
|
||||
sptps_send_record(&s, 0, buf, len);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#define __TINC_SUBNET_H__
|
||||
|
||||
#include "net.h"
|
||||
#include "hash.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef enum subnet_type_t {
|
||||
SUBNET_MAC = 0,
|
||||
|
|
@ -45,8 +45,6 @@ typedef struct subnet_ipv6_t {
|
|||
int prefixlength;
|
||||
} subnet_ipv6_t;
|
||||
|
||||
#include "node.h"
|
||||
|
||||
typedef struct subnet_t {
|
||||
struct node_t *owner; /* the owner of this subnet */
|
||||
|
||||
|
|
|
|||
12
src/system.h
12
src/system.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
system.h -- system headers
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2003-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -25,12 +25,6 @@
|
|||
|
||||
#include "have.h"
|
||||
|
||||
#ifndef HAVE_STDBOOL_H
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRSIGNAL
|
||||
# define strsignal(p) ""
|
||||
#endif
|
||||
|
|
@ -39,10 +33,6 @@ typedef int bool;
|
|||
|
||||
#include "dropin.h"
|
||||
|
||||
#ifndef HAVE_SOCKLEN_T
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
#define UNUSED(n) (void)(n);
|
||||
|
||||
#endif /* __TINC_SYSTEM_H__ */
|
||||
|
|
|
|||
285
src/tincctl.c
285
src/tincctl.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
tincctl.c -- Controlling a running tincd
|
||||
Copyright (C) 2007-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -88,7 +88,7 @@ static struct option const long_options[] = {
|
|||
static void version(void) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
"See the AUTHORS file for a complete list.\n\n"
|
||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
"and you are welcome to redistribute it under certain conditions;\n"
|
||||
|
|
@ -153,6 +153,8 @@ static void usage(bool status) {
|
|||
" join INVITATION Join a VPN using an INVITATION\n"
|
||||
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
|
||||
" fsck Check the configuration files for problems.\n"
|
||||
" sign [FILE] Generate a signed version of a file.\n"
|
||||
" verify NODE [FILE] Verify that a file was signed by the given NODE.\n"
|
||||
"\n");
|
||||
printf("Report bugs to tinc@tinc-vpn.org.\n");
|
||||
}
|
||||
|
|
@ -327,7 +329,7 @@ static void disable_old_keys(const char *filename, const char *what) {
|
|||
|
||||
static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
|
||||
FILE *r;
|
||||
char *directory;
|
||||
char directory[PATH_MAX] = ".";
|
||||
char buf[PATH_MAX];
|
||||
char buf2[PATH_MAX];
|
||||
|
||||
|
|
@ -355,7 +357,7 @@ static FILE *ask_and_open(const char *filename, const char *what, const char *mo
|
|||
if(filename[0] != '/') {
|
||||
#endif
|
||||
/* The directory is a relative path or a filename. */
|
||||
directory = get_current_dir_name();
|
||||
getcwd(directory, sizeof directory);
|
||||
snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename);
|
||||
filename = buf2;
|
||||
}
|
||||
|
|
@ -1437,6 +1439,29 @@ char *get_my_name(bool verbose) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ecdsa_t *get_pubkey(FILE *f) {
|
||||
char buf[4096];
|
||||
char *value;
|
||||
while(fgets(buf, sizeof buf, f)) {
|
||||
int len = strcspn(buf, "\t =");
|
||||
value = buf + len;
|
||||
value += strspn(value, "\t ");
|
||||
if(*value == '=') {
|
||||
value++;
|
||||
value += strspn(value, "\t ");
|
||||
}
|
||||
if(!rstrip(value))
|
||||
continue;
|
||||
buf[len] = 0;
|
||||
if(strcasecmp(buf, "Ed25519PublicKey"))
|
||||
continue;
|
||||
if(*value)
|
||||
return ecdsa_set_base64_public_key(value);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const var_t variables[] = {
|
||||
/* Server configuration */
|
||||
{"AddressFamily", VAR_SERVER},
|
||||
|
|
@ -2272,26 +2297,29 @@ static int cmd_exchange_all(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
static int switch_network(char *name) {
|
||||
if(strcmp(name, ".")) {
|
||||
if(!check_netname(name, false)) {
|
||||
fprintf(stderr, "Invalid character in netname!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!check_netname(name, true))
|
||||
fprintf(stderr, "Warning: unsafe character in netname!\n");
|
||||
}
|
||||
|
||||
if(fd >= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
free(confbase);
|
||||
confbase = NULL;
|
||||
free(pidfilename);
|
||||
pidfilename = NULL;
|
||||
free(logfilename);
|
||||
logfilename = NULL;
|
||||
free(unixsocketname);
|
||||
unixsocketname = NULL;
|
||||
free_names();
|
||||
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
|
||||
make_names(false);
|
||||
|
||||
free(tinc_conf);
|
||||
free(hosts_dir);
|
||||
free(prompt);
|
||||
|
||||
free(netname);
|
||||
netname = strcmp(name, ".") ? xstrdup(name) : NULL;
|
||||
|
||||
xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
|
||||
xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
|
||||
xasprintf(&prompt, "%s> ", identname);
|
||||
|
|
@ -2345,6 +2373,231 @@ static int cmd_fsck(int argc, char *argv[]) {
|
|||
return fsck(orig_argv[0]);
|
||||
}
|
||||
|
||||
static void *readfile(FILE *in, size_t *len) {
|
||||
size_t count = 0;
|
||||
size_t alloced = 4096;
|
||||
char *buf = xmalloc(alloced);
|
||||
|
||||
while(!feof(in)) {
|
||||
size_t read = fread(buf + count, 1, alloced - count, in);
|
||||
if(!read)
|
||||
break;
|
||||
count += read;
|
||||
if(count >= alloced) {
|
||||
alloced *= 2;
|
||||
buf = xrealloc(buf, alloced);
|
||||
}
|
||||
}
|
||||
|
||||
if(len)
|
||||
*len = count;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int cmd_sign(int argc, char *argv[]) {
|
||||
if(argc > 2) {
|
||||
fprintf(stderr, "Too many arguments!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!name) {
|
||||
name = get_my_name(true);
|
||||
if(!name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if(!fp) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
ecdsa_t *key = ecdsa_read_pem_private_key(fp);
|
||||
|
||||
if(!key) {
|
||||
fprintf(stderr, "Could not read private key from %s\n", fname);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
FILE *in;
|
||||
|
||||
if(argc == 2) {
|
||||
in = fopen(argv[1], "rb");
|
||||
if(!in) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
|
||||
ecdsa_free(key);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
in = stdin;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
char *data = readfile(in, &len);
|
||||
if(in != stdin)
|
||||
fclose(in);
|
||||
if(!data) {
|
||||
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
|
||||
ecdsa_free(key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ensure we sign our name and current time as well
|
||||
long t = time(NULL);
|
||||
char *trailer;
|
||||
xasprintf(&trailer, " %s %ld", name, t);
|
||||
int trailer_len = strlen(trailer);
|
||||
|
||||
data = xrealloc(data, len + trailer_len);
|
||||
memcpy(data + len, trailer, trailer_len);
|
||||
free(trailer);
|
||||
|
||||
char sig[87];
|
||||
if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
|
||||
fprintf(stderr, "Error generating signature\n");
|
||||
free(data);
|
||||
ecdsa_free(key);
|
||||
return 1;
|
||||
}
|
||||
b64encode(sig, sig, 64);
|
||||
ecdsa_free(key);
|
||||
|
||||
fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
|
||||
fwrite(data, len, 1, stdout);
|
||||
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_verify(int argc, char *argv[]) {
|
||||
if(argc < 2) {
|
||||
fprintf(stderr, "Not enough arguments!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(argc > 3) {
|
||||
fprintf(stderr, "Too many arguments!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *node = argv[1];
|
||||
if(!strcmp(node, ".")) {
|
||||
if(!name) {
|
||||
name = get_my_name(true);
|
||||
if(!name)
|
||||
return 1;
|
||||
}
|
||||
node = name;
|
||||
} else if(!strcmp(node, "*")) {
|
||||
node = NULL;
|
||||
} else {
|
||||
if(!check_id(node)) {
|
||||
fprintf(stderr, "Invalid node name\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *in;
|
||||
|
||||
if(argc == 3) {
|
||||
in = fopen(argv[2], "rb");
|
||||
if(!in) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
in = stdin;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
char *data = readfile(in, &len);
|
||||
if(in != stdin)
|
||||
fclose(in);
|
||||
if(!data) {
|
||||
fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *newline = memchr(data, '\n', len);
|
||||
if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
|
||||
fprintf(stderr, "Invalid input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
*newline++ = '\0';
|
||||
size_t skip = newline - data;
|
||||
|
||||
char signer[MAX_STRING_SIZE] = "";
|
||||
char sig[MAX_STRING_SIZE] = "";
|
||||
long t = 0;
|
||||
|
||||
if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
|
||||
fprintf(stderr, "Invalid input\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(node && strcmp(node, signer)) {
|
||||
fprintf(stderr, "Signature is not made by %s\n", node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!node)
|
||||
node = signer;
|
||||
|
||||
char *trailer;
|
||||
xasprintf(&trailer, " %s %ld", signer, t);
|
||||
int trailer_len = strlen(trailer);
|
||||
|
||||
data = xrealloc(data, len + trailer_len);
|
||||
memcpy(data + len, trailer, trailer_len);
|
||||
free(trailer);
|
||||
|
||||
newline = data + skip;
|
||||
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node);
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if(!fp) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ecdsa_t *key = get_pubkey(fp);
|
||||
if(!key) {
|
||||
rewind(fp);
|
||||
key = ecdsa_read_pem_public_key(fp);
|
||||
}
|
||||
if(!key) {
|
||||
fprintf(stderr, "Could not read public key from %s\n", fname);
|
||||
fclose(fp);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
|
||||
fprintf(stderr, "Invalid signature\n");
|
||||
free(data);
|
||||
ecdsa_free(key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ecdsa_free(key);
|
||||
|
||||
fwrite(newline, len - (newline - data), 1, stdout);
|
||||
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *command;
|
||||
int (*function)(int argc, char *argv[]);
|
||||
|
|
@ -2389,6 +2642,8 @@ static const struct {
|
|||
{"join", cmd_join, false},
|
||||
{"network", cmd_network, false},
|
||||
{"fsck", cmd_fsck, false},
|
||||
{"sign", cmd_sign, false},
|
||||
{"verify", cmd_verify, false},
|
||||
{NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
tincctl.h -- header for tincctl.c.
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2011-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -50,6 +50,7 @@ extern bool sendline(int fd, char *format, ...);
|
|||
extern bool recvline(int fd, char *line, size_t len);
|
||||
extern int check_port(char *name);
|
||||
extern FILE *fopenmask(const char *filename, const char *mode, mode_t perms);
|
||||
extern ecdsa_t *get_pubkey(FILE *f);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
12
src/tincd.c
12
src/tincd.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
tincd.c -- the main file for tincd
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2008 Max Rijevski <maksuf@gmail.com>
|
||||
2009 Michael Tokarev <mjt@tls.msk.ru>
|
||||
2010 Julien Muchembled <jm@jmuchemb.eu>
|
||||
|
|
@ -43,8 +43,6 @@
|
|||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "control.h"
|
||||
#include "crypto.h"
|
||||
|
|
@ -254,11 +252,14 @@ static bool parse_options(int argc, char **argv) {
|
|||
netname = NULL;
|
||||
}
|
||||
|
||||
if(netname && (strpbrk(netname, "\\/") || *netname == '.')) {
|
||||
if(netname && !check_netname(netname, false)) {
|
||||
fprintf(stderr, "Invalid character in netname!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(netname && !check_netname(netname, true))
|
||||
fprintf(stderr, "Warning: unsafe character in netname!\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -331,11 +332,12 @@ int main(int argc, char **argv) {
|
|||
return 1;
|
||||
|
||||
make_names(true);
|
||||
chdir(confbase);
|
||||
|
||||
if(show_version) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
"See the AUTHORS file for a complete list.\n\n"
|
||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
"and you are welcome to redistribute it under certain conditions;\n"
|
||||
|
|
|
|||
18
src/utils.c
18
src/utils.c
|
|
@ -158,7 +158,7 @@ int b64encode_urlsafe(const void *src, char *dst, int length) {
|
|||
const char *winerror(int err) {
|
||||
static char buf[1024], *ptr;
|
||||
|
||||
ptr = buf + sprintf(buf, "(%d) ", err);
|
||||
ptr = buf + snprintf(buf, sizeof buf, "(%d) ", err);
|
||||
|
||||
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) {
|
||||
|
|
@ -191,6 +191,22 @@ bool check_id(const char *id) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool check_netname(const char *netname, bool strict) {
|
||||
if(!netname || !*netname || *netname == '.')
|
||||
return false;
|
||||
|
||||
for(const char *c = netname; *c; c++) {
|
||||
if(iscntrl(*c))
|
||||
return false;
|
||||
if(*c == '/' || *c == '\\')
|
||||
return false;
|
||||
if(strict && strchr(" $%<>:`\"|?*", *c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Windows doesn't define HOST_NAME_MAX. */
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 255
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ extern const char *winerror(int);
|
|||
extern unsigned int bitfield_to_int(const void *bitfield, size_t size);
|
||||
|
||||
extern bool check_id(const char *);
|
||||
extern bool check_netname(const char *, bool strict);
|
||||
char *replace_name(const char *name);
|
||||
|
||||
#endif /* __TINC_UTILS_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue