Merge remote-tracking branch 'guus/1.1' into thkr-foor2Vup

This commit is contained in:
thorkill 2016-05-08 15:58:29 +02:00
commit 4be26caf4e
64 changed files with 3013 additions and 2400 deletions

View file

@ -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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {

View file

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

View file

@ -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;
}

View file

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

View file

@ -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
View file

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

View file

@ -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

View file

@ -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;

View file

@ -1,7 +1,7 @@
/*
ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
2006-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -29,29 +29,6 @@
#define IPPROTO_ICMPV6 58
#endif
#ifndef HAVE_STRUCT_IN6_ADDR
struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} in6_u;
} __attribute__ ((__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) \

View file

@ -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)) {

View file

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

View file

@ -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;
}

View file

@ -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;

View file

@ -1,7 +1,7 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -115,6 +115,7 @@ typedef struct listen_socket_t {
io_t udp;
sockaddr_t sa;
bool bindto;
int priority;
} listen_socket_t;
#include "conf.h"

View file

@ -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))

View file

@ -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++) {

View file

@ -1,7 +1,7 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.org>
@ -35,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

View file

@ -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",

View file

@ -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 {

View file

@ -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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -105,6 +105,260 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
return true;
}
static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp;
memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
}
/* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip = {0};
struct icmp icmp = {0};
struct in_addr ip_src;
struct in_addr ip_dst;
uint32_t oldlen;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
memcpy(&ip, DATA(packet) + ether_size, ip_size);
/* Remember original source and destination */
ip_src = ip.ip_src;
ip_dst = ip.ip_dst;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = ip.ip_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
ip_dst = addr.sin_addr;
}
}
close(sockfd);
}
}
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip_size + icmp_size, DATA(packet) + ether_size, oldlen);
/* Fill in IPv4 header */
ip.ip_v = 4;
ip.ip_hl = ip_size / 4;
ip.ip_tos = 0;
ip.ip_len = htons(ip_size + icmp_size + oldlen);
ip.ip_id = 0;
ip.ip_off = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_sum = 0;
ip.ip_src = ip_dst;
ip.ip_dst = ip_src;
ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
/* Fill in ICMP header */
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip, ip_size);
memcpy(DATA(packet) + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet);
}
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
uint16_t checksum;
struct {
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
uint32_t length;
uint32_t next;
} pseudo;
if(ratelimit(3))
return;
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
memcpy(&ip6, DATA(packet) + ether_size, ip6_size);
/* Remember original source and destination */
pseudo.ip6_src = ip6.ip6_dst;
pseudo.ip6_dst = ip6.ip6_src;
/* Try to reply with an IP address assigned to the local machine */
if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) {
int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd != -1) {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = ip6.ip6_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
pseudo.ip6_src = addr.sin6_addr;
}
}
close(sockfd);
}
}
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
/* Copy first part of original contents to ICMP message */
memmove(DATA(packet) + ether_size + ip6_size + icmp6_size, DATA(packet) + ether_size, pseudo.length);
/* Fill in IPv6 header */
ip6.ip6_flow = htonl(0x60000000UL);
ip6.ip6_plen = htons(icmp6_size + pseudo.length);
ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_hlim = 255;
ip6.ip6_src = pseudo.ip6_src;
ip6.ip6_dst = pseudo.ip6_dst;
/* Fill in ICMP header */
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
/* Create pseudo header */
pseudo.length = htonl(icmp6_size + pseudo.length);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&icmp6, icmp6_size, checksum);
checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
icmp6.icmp6_cksum = checksum;
/* Copy structs on stack back to packet */
memcpy(DATA(packet) + ether_size, &ip6, ip6_size);
memcpy(DATA(packet) + ether_size + ip6_size, &icmp6, icmp6_size);
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
send_packet(source, packet);
}
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
length_t ethlen = ether_size;
if(type == ETH_P_8021Q) {
type = DATA(packet)[16] << 8 | DATA(packet)[17];
ethlen += 4;
}
switch (type) {
case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size))
return false;
if(DATA(packet)[ethlen + 8] <= 1) {
if(DATA(packet)[ethlen + 11] != IPPROTO_ICMP || DATA(packet)[ethlen + 32] != ICMP_TIME_EXCEEDED)
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
}
uint16_t old = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
DATA(packet)[ethlen + 8]--;
uint16_t new = DATA(packet)[ethlen + 8] << 8 | DATA(packet)[ethlen + 9];
uint32_t checksum = DATA(packet)[ethlen + 10] << 8 | DATA(packet)[ethlen + 11];
checksum += old + (~new & 0xFFFF);
while(checksum >> 16)
checksum = (checksum & 0xFFFF) + (checksum >> 16);
DATA(packet)[ethlen + 10] = checksum >> 8;
DATA(packet)[ethlen + 11] = checksum & 0xff;
return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size))
return false;
if(DATA(packet)[ethlen + 7] <= 1) {
if(DATA(packet)[ethlen + 6] != IPPROTO_ICMPV6 || DATA(packet)[ethlen + 40] != ICMP6_TIME_EXCEEDED)
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false;
}
DATA(packet)[ethlen + 7]--;
return true;
default:
return true;
}
}
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
return;
@ -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;
}
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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 */

View file

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

View file

@ -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},
};

View file

@ -1,6 +1,6 @@
/*
tincctl.h -- header for tincctl.c.
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 2011-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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

View file

@ -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"

View file

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

View file

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