Import Upstream version 1.0.27
This commit is contained in:
parent
b33a93f7f6
commit
eed44cd331
44 changed files with 1672 additions and 932 deletions
|
|
@ -17,8 +17,6 @@ tincd_SOURCES = \
|
|||
fake-gai-errnos.h \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c \
|
||||
graph.c graph.h \
|
||||
ipv4.h \
|
||||
ipv6.h \
|
||||
|
|
@ -40,6 +38,7 @@ tincd_SOURCES = \
|
|||
protocol_misc.c \
|
||||
protocol_key.c \
|
||||
protocol_subnet.c \
|
||||
proxy.c proxy.h \
|
||||
raw_socket_device.c \
|
||||
route.c route.h \
|
||||
subnet.c subnet.h \
|
||||
|
|
@ -48,6 +47,12 @@ tincd_SOURCES = \
|
|||
xalloc.h \
|
||||
xmalloc.c
|
||||
|
||||
if !GETOPT
|
||||
tincd_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
tincd_SOURCES += linux/device.c
|
||||
endif
|
||||
|
|
|
|||
121
src/Makefile.in
121
src/Makefile.in
|
|
@ -1,7 +1,7 @@
|
|||
# Makefile.in generated by automake 1.14.1 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
|
@ -15,7 +15,17 @@
|
|||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
|
|
@ -79,18 +89,20 @@ POST_UNINSTALL = :
|
|||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
sbin_PROGRAMS = tincd$(EXEEXT)
|
||||
@LINUX_TRUE@am__append_1 = linux/device.c
|
||||
@BSD_TRUE@am__append_2 = bsd/device.c
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__append_3 = bsd/tunemu.c bsd/tunemu.h
|
||||
@SOLARIS_TRUE@am__append_4 = solaris/device.c
|
||||
@MINGW_TRUE@am__append_5 = mingw/device.c mingw/common.h
|
||||
@CYGWIN_TRUE@am__append_6 = cygwin/device.c
|
||||
@UML_TRUE@am__append_7 = uml_device.c
|
||||
@VDE_TRUE@am__append_8 = vde_device.c
|
||||
@TUNEMU_TRUE@am__append_9 = -lpcap
|
||||
@GETOPT_FALSE@am__append_1 = \
|
||||
@GETOPT_FALSE@ getopt.c getopt.h \
|
||||
@GETOPT_FALSE@ getopt1.c
|
||||
|
||||
@LINUX_TRUE@am__append_2 = linux/device.c
|
||||
@BSD_TRUE@am__append_3 = bsd/device.c
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__append_4 = bsd/tunemu.c bsd/tunemu.h
|
||||
@SOLARIS_TRUE@am__append_5 = solaris/device.c
|
||||
@MINGW_TRUE@am__append_6 = mingw/device.c mingw/common.h
|
||||
@CYGWIN_TRUE@am__append_7 = cygwin/device.c
|
||||
@UML_TRUE@am__append_8 = uml_device.c
|
||||
@VDE_TRUE@am__append_9 = vde_device.c
|
||||
@TUNEMU_TRUE@am__append_10 = -lpcap
|
||||
subdir = src
|
||||
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
||||
$(top_srcdir)/depcomp
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
|
|
@ -99,6 +111,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
|||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
|
|
@ -109,42 +122,44 @@ am__tincd_SOURCES_DIST = have.h system.h avl_tree.c avl_tree.h conf.c \
|
|||
conf.h connection.c connection.h device.h dropin.c dropin.h \
|
||||
dummy_device.c edge.c edge.h ethernet.h event.c event.h \
|
||||
fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h getopt.c getopt.h \
|
||||
getopt1.c graph.c graph.h ipv4.h ipv6.h list.c list.h logger.c \
|
||||
logger.h meta.c meta.h multicast_device.c net.c net.h \
|
||||
net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
|
||||
node.h pidfile.c pidfile.h process.c process.h protocol.c \
|
||||
protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c raw_socket_device.c route.c \
|
||||
fake-getnameinfo.c fake-getnameinfo.h graph.c graph.h ipv4.h \
|
||||
ipv6.h list.c list.h logger.c logger.h meta.c meta.h \
|
||||
multicast_device.c net.c net.h net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c netutl.h node.c node.h pidfile.c \
|
||||
pidfile.h process.c process.h protocol.c protocol.h \
|
||||
protocol_auth.c protocol_edge.c protocol_misc.c protocol_key.c \
|
||||
protocol_subnet.c proxy.c proxy.h raw_socket_device.c route.c \
|
||||
route.h subnet.c subnet.h tincd.c utils.c utils.h xalloc.h \
|
||||
xmalloc.c linux/device.c bsd/device.c bsd/tunemu.c \
|
||||
bsd/tunemu.h solaris/device.c mingw/device.c mingw/common.h \
|
||||
cygwin/device.c uml_device.c vde_device.c
|
||||
xmalloc.c getopt.c getopt.h getopt1.c linux/device.c \
|
||||
bsd/device.c bsd/tunemu.c bsd/tunemu.h solaris/device.c \
|
||||
mingw/device.c mingw/common.h cygwin/device.c uml_device.c \
|
||||
vde_device.c
|
||||
@GETOPT_FALSE@am__objects_1 = getopt.$(OBJEXT) getopt1.$(OBJEXT)
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
@LINUX_TRUE@am__objects_1 = linux/device.$(OBJEXT)
|
||||
@BSD_TRUE@am__objects_2 = bsd/device.$(OBJEXT)
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__objects_3 = bsd/tunemu.$(OBJEXT)
|
||||
@SOLARIS_TRUE@am__objects_4 = solaris/device.$(OBJEXT)
|
||||
@MINGW_TRUE@am__objects_5 = mingw/device.$(OBJEXT)
|
||||
@CYGWIN_TRUE@am__objects_6 = cygwin/device.$(OBJEXT)
|
||||
@UML_TRUE@am__objects_7 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_8 = vde_device.$(OBJEXT)
|
||||
@LINUX_TRUE@am__objects_2 = linux/device.$(OBJEXT)
|
||||
@BSD_TRUE@am__objects_3 = bsd/device.$(OBJEXT)
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__objects_4 = bsd/tunemu.$(OBJEXT)
|
||||
@SOLARIS_TRUE@am__objects_5 = solaris/device.$(OBJEXT)
|
||||
@MINGW_TRUE@am__objects_6 = mingw/device.$(OBJEXT)
|
||||
@CYGWIN_TRUE@am__objects_7 = cygwin/device.$(OBJEXT)
|
||||
@UML_TRUE@am__objects_8 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_9 = vde_device.$(OBJEXT)
|
||||
am_tincd_OBJECTS = avl_tree.$(OBJEXT) conf.$(OBJEXT) \
|
||||
connection.$(OBJEXT) dropin.$(OBJEXT) dummy_device.$(OBJEXT) \
|
||||
edge.$(OBJEXT) event.$(OBJEXT) fake-getaddrinfo.$(OBJEXT) \
|
||||
fake-getnameinfo.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
|
||||
graph.$(OBJEXT) list.$(OBJEXT) logger.$(OBJEXT) meta.$(OBJEXT) \
|
||||
multicast_device.$(OBJEXT) net.$(OBJEXT) net_packet.$(OBJEXT) \
|
||||
net_setup.$(OBJEXT) net_socket.$(OBJEXT) netutl.$(OBJEXT) \
|
||||
node.$(OBJEXT) pidfile.$(OBJEXT) process.$(OBJEXT) \
|
||||
protocol.$(OBJEXT) protocol_auth.$(OBJEXT) \
|
||||
protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \
|
||||
protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \
|
||||
fake-getnameinfo.$(OBJEXT) graph.$(OBJEXT) list.$(OBJEXT) \
|
||||
logger.$(OBJEXT) meta.$(OBJEXT) multicast_device.$(OBJEXT) \
|
||||
net.$(OBJEXT) net_packet.$(OBJEXT) net_setup.$(OBJEXT) \
|
||||
net_socket.$(OBJEXT) netutl.$(OBJEXT) node.$(OBJEXT) \
|
||||
pidfile.$(OBJEXT) process.$(OBJEXT) protocol.$(OBJEXT) \
|
||||
protocol_auth.$(OBJEXT) protocol_edge.$(OBJEXT) \
|
||||
protocol_misc.$(OBJEXT) protocol_key.$(OBJEXT) \
|
||||
protocol_subnet.$(OBJEXT) proxy.$(OBJEXT) \
|
||||
raw_socket_device.$(OBJEXT) route.$(OBJEXT) subnet.$(OBJEXT) \
|
||||
tincd.$(OBJEXT) utils.$(OBJEXT) xmalloc.$(OBJEXT) \
|
||||
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
|
||||
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
|
||||
$(am__objects_7) $(am__objects_8)
|
||||
$(am__objects_7) $(am__objects_8) $(am__objects_9)
|
||||
tincd_OBJECTS = $(am_tincd_OBJECTS)
|
||||
tincd_LDADD = $(LDADD)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
|
|
@ -201,6 +216,7 @@ am__define_uniq_tagged_files = \
|
|||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
|
|
@ -230,7 +246,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
|||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@ $(am__append_9)
|
||||
LIBS = @LIBS@ $(am__append_10)
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
|
|
@ -290,6 +306,7 @@ pdfdir = @pdfdir@
|
|||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
|
@ -302,17 +319,17 @@ tincd_SOURCES = have.h system.h avl_tree.c avl_tree.h conf.c conf.h \
|
|||
connection.c connection.h device.h dropin.c dropin.h \
|
||||
dummy_device.c edge.c edge.h ethernet.h event.c event.h \
|
||||
fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h getopt.c getopt.h \
|
||||
getopt1.c graph.c graph.h ipv4.h ipv6.h list.c list.h logger.c \
|
||||
logger.h meta.c meta.h multicast_device.c net.c net.h \
|
||||
net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
|
||||
node.h pidfile.c pidfile.h process.c process.h protocol.c \
|
||||
protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c raw_socket_device.c route.c \
|
||||
fake-getnameinfo.c fake-getnameinfo.h graph.c graph.h ipv4.h \
|
||||
ipv6.h list.c list.h logger.c logger.h meta.c meta.h \
|
||||
multicast_device.c net.c net.h net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c netutl.h node.c node.h pidfile.c \
|
||||
pidfile.h process.c process.h protocol.c protocol.h \
|
||||
protocol_auth.c protocol_edge.c protocol_misc.c protocol_key.c \
|
||||
protocol_subnet.c proxy.c proxy.h raw_socket_device.c route.c \
|
||||
route.h subnet.c subnet.h tincd.c utils.c utils.h xalloc.h \
|
||||
xmalloc.c $(am__append_1) $(am__append_2) $(am__append_3) \
|
||||
$(am__append_4) $(am__append_5) $(am__append_6) \
|
||||
$(am__append_7) $(am__append_8)
|
||||
$(am__append_7) $(am__append_8) $(am__append_9)
|
||||
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\"
|
||||
all: all-am
|
||||
|
||||
|
|
@ -330,7 +347,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
|
|||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu src/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
|
|
@ -494,6 +510,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_key.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_misc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_subnet.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proxy.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_socket_device.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@
|
||||
|
|
@ -739,6 +756,8 @@ uninstall-am: uninstall-sbinPROGRAMS
|
|||
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
|
||||
uninstall-am uninstall-sbinPROGRAMS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
avl_tree.c -- avl_ tree and linked list convenience
|
||||
Copyright (C) 1998 Michael H. Buselli
|
||||
2000-2005 Ivo Timmermans,
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -123,8 +123,6 @@ static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
|
|||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
|
||||
parent = node;
|
||||
|
||||
while(node) {
|
||||
parent = node->parent;
|
||||
|
||||
|
|
|
|||
153
src/bsd/device.c
153
src/bsd/device.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -33,13 +33,15 @@
|
|||
#include "tunemu.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#if defined(HAVE_FREEBSD) || defined(HAVE_NETBSD) || defined(HAVE_DARWIN)
|
||||
#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,
|
||||
|
|
@ -47,6 +49,9 @@ typedef enum device_type {
|
|||
#ifdef ENABLE_TUNEMU
|
||||
DEVICE_TYPE_TUNEMU,
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
DEVICE_TYPE_UTUN,
|
||||
#endif
|
||||
} device_type_t;
|
||||
|
||||
int device_fd = -1;
|
||||
|
|
@ -63,8 +68,61 @@ 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(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(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(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(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool setup_device(void) {
|
||||
char *type;
|
||||
// Find out which device file to open
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER)
|
||||
|
|
@ -73,8 +131,9 @@ static bool setup_device(void) {
|
|||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : 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"))
|
||||
|
|
@ -82,6 +141,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;
|
||||
|
|
@ -94,10 +157,22 @@ static bool setup_device(void) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0)
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
else
|
||||
#endif
|
||||
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER)
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
|
||||
logger(LOG_ERR, "Only tap devices support switch mode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the device
|
||||
|
||||
switch(device_type) {
|
||||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU: {
|
||||
|
|
@ -105,6 +180,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);
|
||||
|
|
@ -119,6 +198,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(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;
|
||||
|
|
@ -183,6 +283,11 @@ static bool setup_device(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFADDR
|
||||
if(overwrite_mac)
|
||||
ioctl(device_fd, SIOCGIFADDR, mymac.x);
|
||||
#endif
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
|
|
@ -242,31 +347,27 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
packet->len = lenin + 14;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
u_int32_t type;
|
||||
struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
|
||||
|
||||
if((lenin = readv(device_fd, vector, 2)) <= 0) {
|
||||
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ntohl(type)) {
|
||||
case AF_INET:
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
case 6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown address family %x while reading packet from %s %s",
|
||||
ntohl(type), device_info, device);
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -310,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)}, {packet->data + 14, packet->len - 14}};
|
||||
int af;
|
||||
|
||||
af = (packet->data[12] << 8) + packet->data[13];
|
||||
int af = (packet->data[12] << 8) + packet->data[13];
|
||||
uint32_t type;
|
||||
|
||||
switch (af) {
|
||||
case 0x0800:
|
||||
|
|
@ -331,7 +430,9 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(writev(device_fd, vector, 2) < 0) {
|
||||
memcpy(packet->data + 10, &type, sizeof type);
|
||||
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-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
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "../system.h"
|
||||
#include "../net.h"
|
||||
|
||||
#include <w32api/windows.h>
|
||||
#include <w32api/winioctl.h>
|
||||
|
|
@ -26,7 +27,6 @@
|
|||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
|
@ -61,6 +61,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)) {
|
||||
|
|
|
|||
90
src/meta.c
90
src/meta.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.c -- handle the meta communication
|
||||
Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2015 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
|
@ -160,6 +161,17 @@ bool receive_meta(connection_t *c) {
|
|||
c->buflen += lenin;
|
||||
|
||||
while(lenin > 0) {
|
||||
reqlen = 0;
|
||||
|
||||
/* Is it proxy metadata? */
|
||||
|
||||
if(c->allow_request == PROXY) {
|
||||
reqlen = receive_proxy_meta(c, oldlen, lenin);
|
||||
if(reqlen < 0)
|
||||
return false;
|
||||
goto consume;
|
||||
}
|
||||
|
||||
/* Decrypt */
|
||||
|
||||
if(c->status.decryptin && !decrypted) {
|
||||
|
|
@ -177,74 +189,32 @@ bool receive_meta(connection_t *c) {
|
|||
|
||||
if(c->tcplen) {
|
||||
if(c->tcplen <= c->buflen) {
|
||||
if(!c->node) {
|
||||
if(c->outgoing && proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
|
||||
if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else if(c->outgoing && proxytype == PROXY_SOCKS5 && c->allow_request == ID) {
|
||||
if(c->buffer[0] != 5) {
|
||||
logger(LOG_ERR, "Invalid response from proxy server");
|
||||
return false;
|
||||
}
|
||||
if(c->buffer[1] == (char)0xff) {
|
||||
logger(LOG_ERR, "Proxy request rejected: unsuitable authentication method");
|
||||
return false;
|
||||
}
|
||||
if(c->buffer[2] != 5) {
|
||||
logger(LOG_ERR, "Invalid response from proxy server");
|
||||
return false;
|
||||
}
|
||||
if(c->buffer[3] == 0) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "c->tcplen set but c->node is NULL!");
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if(c->allow_request == ALL) {
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
} else {
|
||||
logger(LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
if(c->allow_request != ALL) {
|
||||
logger(LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
c->buflen -= c->tcplen;
|
||||
lenin -= c->tcplen - oldlen;
|
||||
memmove(c->buffer, c->buffer + c->tcplen, c->buflen);
|
||||
oldlen = 0;
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
reqlen = c->tcplen;
|
||||
c->tcplen = 0;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
reqlen = 0;
|
||||
|
||||
for(i = oldlen; i < c->buflen; i++) {
|
||||
if(c->buffer[i] == '\n') {
|
||||
c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */
|
||||
reqlen = i + 1;
|
||||
break;
|
||||
for(i = oldlen; i < c->buflen; i++) {
|
||||
if(c->buffer[i] == '\n') {
|
||||
c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */
|
||||
c->reqlen = reqlen = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(reqlen) {
|
||||
c->reqlen = reqlen;
|
||||
if(!receive_request(c))
|
||||
if(reqlen && !receive_request(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
consume:
|
||||
if(reqlen) {
|
||||
c->buflen -= reqlen;
|
||||
lenin -= reqlen - oldlen;
|
||||
memmove(c->buffer, c->buffer + reqlen, c->buflen);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a MinGW environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-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
|
||||
|
|
@ -43,11 +43,12 @@ static uint64_t device_total_in = 0;
|
|||
static uint64_t device_total_out = 0;
|
||||
|
||||
extern char *myport;
|
||||
OVERLAPPED r_overlapped;
|
||||
OVERLAPPED w_overlapped;
|
||||
|
||||
static DWORD WINAPI tapreader(void *bla) {
|
||||
int status;
|
||||
DWORD len;
|
||||
OVERLAPPED overlapped;
|
||||
vpn_packet_t packet;
|
||||
int errors = 0;
|
||||
|
||||
|
|
@ -55,19 +56,17 @@ static DWORD WINAPI tapreader(void *bla) {
|
|||
|
||||
/* Read from tap device and send to parent */
|
||||
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
for(;;) {
|
||||
overlapped.Offset = 0;
|
||||
overlapped.OffsetHigh = 0;
|
||||
ResetEvent(overlapped.hEvent);
|
||||
ResetEvent(r_overlapped.hEvent);
|
||||
|
||||
status = ReadFile(device_handle, packet.data, MTU, &len, &overlapped);
|
||||
status = ReadFile(device_handle, packet.data, MTU, &len, &r_overlapped);
|
||||
|
||||
if(!status) {
|
||||
if(GetLastError() == ERROR_IO_PENDING) {
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
|
||||
WaitForSingleObject(r_overlapped.hEvent, INFINITE);
|
||||
if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE))
|
||||
continue;
|
||||
} else {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
|
|
@ -114,6 +113,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)) {
|
||||
|
|
@ -201,6 +203,11 @@ static bool setup_device(void) {
|
|||
overwrite_mac = 1;
|
||||
}
|
||||
|
||||
/* Create overlapped events for tap I/O */
|
||||
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
w_overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
|
||||
/* Start the tap reader */
|
||||
|
||||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||
|
|
@ -235,14 +242,48 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
DWORD lenout;
|
||||
OVERLAPPED overlapped = {0};
|
||||
static vpn_packet_t queue;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile(device_handle, packet->data, packet->len, &lenout, &overlapped)) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
/* Check if there is something in progress */
|
||||
|
||||
if(queue.len) {
|
||||
DWORD size;
|
||||
BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE);
|
||||
if(success) {
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
int err = GetLastError();
|
||||
if(err != ERROR_IO_INCOMPLETE) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err));
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Previous overlapped write still in progress");
|
||||
// drop this packet
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, try to write. */
|
||||
|
||||
memcpy(queue.data, packet->data, packet->len);
|
||||
|
||||
if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) {
|
||||
int err = GetLastError();
|
||||
if(err != ERROR_IO_PENDING) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err));
|
||||
return false;
|
||||
}
|
||||
// Write is being done asynchronously.
|
||||
queue.len = packet->len;
|
||||
} else {
|
||||
// Write was completed immediately.
|
||||
ResetEvent(&w_overlapped);
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
|
|
|||
16
src/net.h
16
src/net.h
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -123,20 +123,6 @@ extern time_t now;
|
|||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
|
||||
extern char *proxyhost;
|
||||
extern char *proxyport;
|
||||
extern char *proxyuser;
|
||||
extern char *proxypass;
|
||||
typedef enum proxytype_t {
|
||||
PROXY_NONE = 0,
|
||||
PROXY_SOCKS4,
|
||||
PROXY_SOCKS4A,
|
||||
PROXY_SOCKS5,
|
||||
PROXY_HTTP,
|
||||
PROXY_EXEC,
|
||||
} proxytype_t;
|
||||
extern proxytype_t proxytype;
|
||||
|
||||
extern volatile bool running;
|
||||
|
||||
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
|
||||
|
|
|
|||
|
|
@ -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-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010 Timothy Redaelli <timothy@redaelli.eu>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
int nextpkt = 0;
|
||||
vpn_packet_t *outpkt = pkt[0];
|
||||
vpn_packet_t *outpkt;
|
||||
int outlen, outpad;
|
||||
unsigned char hmac[EVP_MAX_MD_SIZE];
|
||||
int i;
|
||||
|
|
@ -552,14 +552,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
case AF_INET:
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
|
||||
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &origpriority, sizeof(origpriority))) /* SO_PRIORITY doesn't seem to work */
|
||||
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
break;
|
||||
#endif
|
||||
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
|
||||
case AF_INET6:
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
|
||||
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, &origpriority, sizeof(origpriority)))
|
||||
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority)))
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
break;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "netutl.h"
|
||||
#include "process.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "route.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
|
|
@ -47,12 +48,6 @@
|
|||
char *myport;
|
||||
devops_t devops;
|
||||
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
|
||||
bool read_rsa_public_key(connection_t *c) {
|
||||
FILE *fp;
|
||||
char *pubname;
|
||||
|
|
|
|||
|
|
@ -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-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2009 Florian Forster <octo@verplant.org>
|
||||
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
|
|
@ -354,8 +355,19 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool is_valid_host_port(const char *host, const char *port) {
|
||||
for(const char *p = host; *p; p++)
|
||||
if(!isalnum(*p) && *p != '-' && *p != '.')
|
||||
return false;
|
||||
|
||||
for(const char *p = port; *p; p++)
|
||||
if(!isalnum(*p))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_outgoing_connection(connection_t *c) {
|
||||
char *address, *port, *space;
|
||||
struct addrinfo *proxyai = NULL;
|
||||
int result;
|
||||
|
||||
|
|
@ -375,6 +387,8 @@ begin:
|
|||
return;
|
||||
}
|
||||
|
||||
char *address, *port, *space;
|
||||
|
||||
get_config_string(c->outgoing->cfg, &address);
|
||||
|
||||
space = strchr(address, ' ');
|
||||
|
|
@ -387,11 +401,23 @@ begin:
|
|||
}
|
||||
|
||||
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
|
||||
free(address);
|
||||
free(port);
|
||||
|
||||
// If we cannot resolve the address, maybe we are using a proxy that can?
|
||||
if(!c->outgoing->ai && proxytype != PROXY_NONE && is_valid_host_port(address, port)) {
|
||||
memset(&c->address, 0, sizeof c->address);
|
||||
c->address.sa.sa_family = AF_UNKNOWN;
|
||||
c->address.unknown.address = address;
|
||||
c->address.unknown.port = port;
|
||||
} else {
|
||||
free(address);
|
||||
free(port);
|
||||
}
|
||||
|
||||
c->outgoing->aip = c->outgoing->ai;
|
||||
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
|
||||
|
||||
if(!c->outgoing->ai && proxytype != PROXY_NONE)
|
||||
goto connect;
|
||||
}
|
||||
|
||||
if(!c->outgoing->aip) {
|
||||
|
|
@ -404,6 +430,7 @@ begin:
|
|||
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
|
||||
c->outgoing->aip = c->outgoing->aip->ai_next;
|
||||
|
||||
connect:
|
||||
if(c->hostname)
|
||||
free(c->hostname);
|
||||
|
||||
|
|
@ -457,8 +484,11 @@ begin:
|
|||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
if(result == -1) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
c->last_ping_time = now;
|
||||
c->status.connecting = true;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ bool hostnames = false;
|
|||
Return NULL on failure.
|
||||
*/
|
||||
struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) {
|
||||
struct addrinfo *ai, hint = {0};
|
||||
struct addrinfo *ai = NULL, hint = {0};
|
||||
int err;
|
||||
|
||||
hint.ai_family = addressfamily;
|
||||
|
|
@ -55,7 +55,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
|
|||
}
|
||||
|
||||
sockaddr_t str2sockaddr(const char *address, const char *port) {
|
||||
struct addrinfo *ai, hint = {0};
|
||||
struct addrinfo *ai = NULL, hint = {0};
|
||||
sockaddr_t result;
|
||||
int err;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol.c -- handle the meta-protocol, basic functions
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -125,20 +125,6 @@ void forward_request(connection_t *from) {
|
|||
bool receive_request(connection_t *c) {
|
||||
int request;
|
||||
|
||||
if(c->outgoing && proxytype == PROXY_HTTP && c->allow_request == ID) {
|
||||
if(!c->buffer[0] || c->buffer[0] == '\r')
|
||||
return true;
|
||||
if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
|
||||
if(!strncmp(c->buffer + 9, "200", 3)) {
|
||||
logger(LOG_DEBUG, "Proxy request granted");
|
||||
return true;
|
||||
} else {
|
||||
logger(LOG_DEBUG, "Proxy request rejected: %s", c->buffer + 9);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sscanf(c->buffer, "%d", &request) == 1) {
|
||||
if((request < 0) || (request >= LAST) || !request_handlers[request]) {
|
||||
ifdebug(META)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol.h -- header for protocol.c
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
/* Request numbers */
|
||||
|
||||
typedef enum request_t {
|
||||
PROXY = -2,
|
||||
ALL = -1, /* Guardian for allow_request */
|
||||
ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK,
|
||||
STATUS, ERROR, TERMREQ,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol_auth.c -- handle the meta-protocol, authentication
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -36,95 +36,10 @@
|
|||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static bool send_proxyrequest(connection_t *c) {
|
||||
switch(proxytype) {
|
||||
case PROXY_HTTP: {
|
||||
char *host;
|
||||
char *port;
|
||||
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
|
||||
free(host);
|
||||
free(port);
|
||||
return true;
|
||||
}
|
||||
case PROXY_SOCKS4: {
|
||||
if(c->address.sa.sa_family != AF_INET) {
|
||||
logger(LOG_ERR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
|
||||
return false;
|
||||
}
|
||||
char s4req[9 + (proxyuser ? strlen(proxyuser) : 0)];
|
||||
s4req[0] = 4;
|
||||
s4req[1] = 1;
|
||||
memcpy(s4req + 2, &c->address.in.sin_port, 2);
|
||||
memcpy(s4req + 4, &c->address.in.sin_addr, 4);
|
||||
if(proxyuser)
|
||||
strcpy(s4req + 8, proxyuser);
|
||||
s4req[sizeof s4req - 1] = 0;
|
||||
c->tcplen = 8;
|
||||
return send_meta(c, s4req, sizeof s4req);
|
||||
}
|
||||
case PROXY_SOCKS5: {
|
||||
int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
|
||||
c->tcplen = 2;
|
||||
if(proxypass)
|
||||
len += 3 + strlen(proxyuser) + strlen(proxypass);
|
||||
char s5req[len];
|
||||
int i = 0;
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
if(proxypass) {
|
||||
s5req[i++] = 2;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = strlen(proxyuser);
|
||||
strcpy(s5req + i, proxyuser);
|
||||
i += strlen(proxyuser);
|
||||
s5req[i++] = strlen(proxypass);
|
||||
strcpy(s5req + i, proxypass);
|
||||
i += strlen(proxypass);
|
||||
c->tcplen += 2;
|
||||
} else {
|
||||
s5req[i++] = 0;
|
||||
}
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = 0;
|
||||
if(c->address.sa.sa_family == AF_INET) {
|
||||
s5req[i++] = 1;
|
||||
memcpy(s5req + i, &c->address.in.sin_addr, 4);
|
||||
i += 4;
|
||||
memcpy(s5req + i, &c->address.in.sin_port, 2);
|
||||
i += 2;
|
||||
c->tcplen += 10;
|
||||
} else if(c->address.sa.sa_family == AF_INET6) {
|
||||
s5req[i++] = 3;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
|
||||
i += 16;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_port, 2);
|
||||
i += 2;
|
||||
c->tcplen += 22;
|
||||
} else {
|
||||
logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
|
||||
return false;
|
||||
}
|
||||
if(i > len)
|
||||
abort();
|
||||
return send_meta(c, s5req, sizeof s5req);
|
||||
}
|
||||
case PROXY_SOCKS4A:
|
||||
logger(LOG_ERR, "Proxy type not implemented yet");
|
||||
return false;
|
||||
case PROXY_EXEC:
|
||||
return true;
|
||||
default:
|
||||
logger(LOG_ERR, "Unknown proxy type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool send_id(connection_t *c) {
|
||||
if(proxytype && c->outgoing)
|
||||
if(!send_proxyrequest(c))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol_edge.c -- handle the meta-protocol, edges
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Michael Tokarev <mjt@corpit.ru>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -125,8 +125,18 @@ bool add_edge_h(connection_t *c) {
|
|||
} else {
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
|
||||
"ADD_EDGE", c->name, c->hostname);
|
||||
edge_del(e);
|
||||
graph();
|
||||
e->options = options;
|
||||
if(sockaddrcmp(&e->address, &address)) {
|
||||
sockaddrfree(&e->address);
|
||||
e->address = address;
|
||||
}
|
||||
if(e->weight != weight) {
|
||||
avl_node_t *node = avl_unlink(edge_weight_tree, e);
|
||||
e->weight = weight;
|
||||
avl_insert_node(edge_weight_tree, node);
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
} else
|
||||
return true;
|
||||
|
|
@ -150,6 +160,7 @@ bool add_edge_h(connection_t *c) {
|
|||
e->weight = weight;
|
||||
edge_add(e);
|
||||
|
||||
done:
|
||||
/* Tell the rest about the new edge */
|
||||
|
||||
if(!tunnelserver)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
protocol_key.c -- handle the meta-protocol, key exchange
|
||||
Copyright (C) 1999-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
|
||||
|
|
@ -233,7 +233,7 @@ bool ans_key_h(connection_t *c) {
|
|||
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;
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
|
||||
sockaddr2str(&from->address, &address, &port);
|
||||
|
|
|
|||
287
src/proxy.c
Normal file
287
src/proxy.c
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
proxy.c -- Proxy handling functions.
|
||||
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "connection.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h" //
|
||||
|
||||
proxytype_t proxytype;
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
|
||||
static void update_address_ipv4(connection_t *c, void *address, void *port) {
|
||||
sockaddrfree(&c->address);
|
||||
memset(&c->address, 0, sizeof c->address);
|
||||
c->address.sa.sa_family = AF_INET;
|
||||
if(address)
|
||||
memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t));
|
||||
if(port)
|
||||
memcpy(&c->address.in.sin_port, port, sizeof(uint16_t));
|
||||
// OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves.
|
||||
if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4))
|
||||
memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4);
|
||||
}
|
||||
|
||||
static void update_address_ipv6(connection_t *c, void *address, void *port) {
|
||||
sockaddrfree(&c->address);
|
||||
memset(&c->address, 0, sizeof c->address);
|
||||
c->address.sa.sa_family = AF_INET6;
|
||||
if(address)
|
||||
memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t));
|
||||
if(port)
|
||||
memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t));
|
||||
// OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves.
|
||||
if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
|
||||
memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8);
|
||||
}
|
||||
|
||||
bool send_proxyrequest(connection_t *c) {
|
||||
switch(proxytype) {
|
||||
case PROXY_SOCKS4:
|
||||
if(c->address.sa.sa_family != AF_INET) {
|
||||
logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!");
|
||||
return false;
|
||||
}
|
||||
case PROXY_SOCKS4A: {
|
||||
if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
|
||||
logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
|
||||
return false;
|
||||
}
|
||||
int len = 9;
|
||||
if(proxyuser)
|
||||
len += strlen(proxyuser);
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
len += 1 + strlen(c->address.unknown.address);
|
||||
char s4req[len];
|
||||
s4req[0] = 4;
|
||||
s4req[1] = 1;
|
||||
if(c->address.sa.sa_family == AF_INET) {
|
||||
memcpy(s4req + 2, &c->address.in.sin_port, 2);
|
||||
memcpy(s4req + 4, &c->address.in.sin_addr, 4);
|
||||
} else {
|
||||
uint16_t port = htons(atoi(c->address.unknown.port));
|
||||
memcpy(s4req + 2, &port, 2);
|
||||
memcpy(s4req + 4, "\0\0\0\1", 4);
|
||||
strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
|
||||
}
|
||||
if(proxyuser)
|
||||
strcpy(s4req + 8, proxyuser);
|
||||
else
|
||||
s4req[8] = 0;
|
||||
s4req[sizeof s4req - 1] = 0;
|
||||
c->allow_request = PROXY;
|
||||
return send_meta(c, s4req, sizeof s4req);
|
||||
}
|
||||
|
||||
case PROXY_SOCKS5: {
|
||||
int len = 3 + 6;
|
||||
if(c->address.sa.sa_family == AF_INET) {
|
||||
len += 4;
|
||||
} else if(c->address.sa.sa_family == AF_INET6) {
|
||||
len += 16;
|
||||
} else if(c->address.sa.sa_family == AF_UNKNOWN) {
|
||||
len += 1 + strlen(c->address.unknown.address);
|
||||
} else {
|
||||
logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
|
||||
return false;
|
||||
}
|
||||
if(proxypass)
|
||||
len += 3 + strlen(proxyuser) + strlen(proxypass);
|
||||
char s5req[len];
|
||||
int i = 0;
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
if(proxypass) {
|
||||
s5req[i++] = 2;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = strlen(proxyuser);
|
||||
strcpy(s5req + i, proxyuser);
|
||||
i += strlen(proxyuser);
|
||||
s5req[i++] = strlen(proxypass);
|
||||
strcpy(s5req + i, proxypass);
|
||||
i += strlen(proxypass);
|
||||
} else {
|
||||
s5req[i++] = 0;
|
||||
}
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = 0;
|
||||
if(c->address.sa.sa_family == AF_INET) {
|
||||
s5req[i++] = 1;
|
||||
memcpy(s5req + i, &c->address.in.sin_addr, 4);
|
||||
i += 4;
|
||||
memcpy(s5req + i, &c->address.in.sin_port, 2);
|
||||
i += 2;
|
||||
} else if(c->address.sa.sa_family == AF_INET6) {
|
||||
s5req[i++] = 4;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
|
||||
i += 16;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_port, 2);
|
||||
i += 2;
|
||||
} else if(c->address.sa.sa_family == AF_UNKNOWN) {
|
||||
s5req[i++] = 3;
|
||||
int len = strlen(c->address.unknown.address);
|
||||
s5req[i++] = len;
|
||||
memcpy(s5req + i, c->address.unknown.address, len);
|
||||
i += len;
|
||||
uint16_t port = htons(atoi(c->address.unknown.port));
|
||||
memcpy(s5req + i, &port, 2);
|
||||
i += 2;
|
||||
} else {
|
||||
logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
|
||||
return false;
|
||||
}
|
||||
if(i > len)
|
||||
abort();
|
||||
c->allow_request = PROXY;
|
||||
return send_meta(c, s5req, sizeof s5req);
|
||||
}
|
||||
|
||||
case PROXY_HTTP: {
|
||||
char *host;
|
||||
char *port;
|
||||
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
|
||||
free(host);
|
||||
free(port);
|
||||
c->allow_request = PROXY;
|
||||
return true;
|
||||
}
|
||||
|
||||
case PROXY_EXEC:
|
||||
return true;
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "Unknown proxy type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int receive_proxy_meta(connection_t *c, int start, int lenin) {
|
||||
switch(proxytype) {
|
||||
case PROXY_SOCKS4:
|
||||
case PROXY_SOCKS4A:
|
||||
if(c->buflen < 8)
|
||||
return 0;
|
||||
if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
|
||||
c->allow_request = ID;
|
||||
return 8;
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy request rejected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
case PROXY_SOCKS5:
|
||||
if(c->buflen < 2)
|
||||
return 0;
|
||||
if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
|
||||
logger(LOG_ERR, "Proxy authentication method rejected");
|
||||
return -1;
|
||||
}
|
||||
int offset = 2;
|
||||
if(c->buffer[1] == 0x02) {
|
||||
if(c->buflen < 4)
|
||||
return 0;
|
||||
if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
|
||||
logger(LOG_ERR, "Proxy username/password rejected");
|
||||
return -1;
|
||||
}
|
||||
offset += 2;
|
||||
}
|
||||
if(c->buflen - offset < 7)
|
||||
return 0;
|
||||
if(c->buffer[offset] != 0x05 || c->buffer[offset + 1] != 0x00) {
|
||||
logger(LOG_ERR, "Proxy request rejected");
|
||||
return -1;
|
||||
}
|
||||
int replen = offset + 6;
|
||||
switch(c->buffer[offset + 3]) {
|
||||
case 0x01: // IPv4
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
|
||||
replen += 4;
|
||||
break;
|
||||
case 0x03: // Hostname
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
update_address_ipv4(c, "\0\0\0\1", "\0\0");
|
||||
replen += ((uint8_t *)c->buffer)[offset + 4];
|
||||
break;
|
||||
case 0x04: // IPv6
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
|
||||
replen += 16;
|
||||
break;
|
||||
default:
|
||||
logger(LOG_ERR, "Proxy reply malformed");
|
||||
return -1;
|
||||
}
|
||||
if(c->buflen < replen) {
|
||||
return 0;
|
||||
} else {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
|
||||
c->allow_request = ID;
|
||||
return replen;
|
||||
}
|
||||
|
||||
case PROXY_HTTP: {
|
||||
char *p = memchr(c->buffer, '\n', c->buflen);
|
||||
if(!p || p - c->buffer >= c->buflen)
|
||||
return 0;
|
||||
p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer));
|
||||
if(!p)
|
||||
return 0;
|
||||
|
||||
if(c->buflen < 9)
|
||||
return 0;
|
||||
|
||||
if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
|
||||
if(!strncmp(c->buffer + 9, "200", 3)) {
|
||||
if(c->address.sa.sa_family == AF_UNKNOWN)
|
||||
update_address_ipv4(c, "\0\0\0\1", "\0\0");
|
||||
logger(LOG_DEBUG, "Proxy request granted");
|
||||
replen = p + 1 - c->buffer;
|
||||
c->allow_request = ID;
|
||||
return replen;
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy request rejected: %s", c->buffer + 9);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy reply malformed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
43
src/proxy.h
Normal file
43
src/proxy.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
proxy.h -- header for proxy.c
|
||||
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_PROXY_H__
|
||||
#define __TINC_PROXY_H__
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
typedef enum proxytype_t {
|
||||
PROXY_NONE = 0,
|
||||
PROXY_SOCKS4,
|
||||
PROXY_SOCKS4A,
|
||||
PROXY_SOCKS5,
|
||||
PROXY_HTTP,
|
||||
PROXY_EXEC,
|
||||
} proxytype_t;
|
||||
|
||||
extern proxytype_t proxytype;
|
||||
extern char *proxyhost;
|
||||
extern char *proxyport;
|
||||
extern char *proxyuser;
|
||||
extern char *proxypass;
|
||||
|
||||
extern bool send_proxyrequest(struct connection_t *c);
|
||||
extern int receive_proxy_meta(struct connection_t *c, int start, int lenin);
|
||||
|
||||
#endif
|
||||
509
src/route.c
509
src/route.c
|
|
@ -2,6 +2,7 @@
|
|||
route.c -- routing
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2015 Vittorio Gambaletta
|
||||
|
||||
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
|
||||
|
|
@ -101,6 +102,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, &packet->data[0], sizeof tmp);
|
||||
memcpy(&packet->data[0], &packet->data[6], sizeof tmp);
|
||||
memcpy(&packet->data[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, packet->data + 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(packet->data + ether_size + ip_size + icmp_size, packet->data + 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(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &ip, ip_size);
|
||||
memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
|
||||
|
||||
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, packet->data + 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(packet->data + ether_size + ip6_size + icmp6_size, packet->data + 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(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
|
||||
|
||||
icmp6.icmp6_cksum = checksum;
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &ip6, ip6_size);
|
||||
memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size);
|
||||
|
||||
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 = packet->data[12] << 8 | packet->data[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 8] <= 1) {
|
||||
if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
packet->data[ethlen + 8]--;
|
||||
uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
|
||||
uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
packet->data[ethlen + 10] = checksum >> 8;
|
||||
packet->data[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
case ETH_P_IPV6:
|
||||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 7] <= 1) {
|
||||
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->data[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;
|
||||
|
|
@ -160,7 +415,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
/* Found it */
|
||||
uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
|
||||
uint16_t newmss = mtu - start - 20;
|
||||
uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
|
||||
uint32_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
|
||||
|
||||
if(oldmss <= newmss)
|
||||
break;
|
||||
|
|
@ -171,21 +426,16 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
packet->data[start + 22 + i] = newmss >> 8;
|
||||
packet->data[start + 23 + i] = newmss & 0xff;
|
||||
csum ^= 0xffff;
|
||||
csum -= oldmss;
|
||||
csum += oldmss ^ 0xffff;
|
||||
csum += newmss;
|
||||
csum = (csum & 0xffff) + (csum >> 16);
|
||||
csum += csum >> 16;
|
||||
csum ^= 0xffff;
|
||||
packet->data[start + 16] = csum >> 8;
|
||||
packet->data[start + 17] = csum & 0xff;
|
||||
packet->data[start + 17] = csum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_mac_addresses(vpn_packet_t *packet) {
|
||||
mac_t tmp;
|
||||
memcpy(&tmp, &packet->data[0], sizeof tmp);
|
||||
memcpy(&packet->data[0], &packet->data[6], sizeof tmp);
|
||||
memcpy(&packet->data[6], &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
static void learn_mac(mac_t *address) {
|
||||
subnet_t *subnet;
|
||||
|
|
@ -249,77 +499,12 @@ void age_subnets(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/* RFC 792 */
|
||||
static void route_broadcast(node_t *source, vpn_packet_t *packet) {
|
||||
if(decrement_ttl && source != myself)
|
||||
if(!do_decrement_ttl(source, packet))
|
||||
return;
|
||||
|
||||
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip ip = {0};
|
||||
struct icmp icmp = {0};
|
||||
|
||||
struct in_addr ip_src;
|
||||
struct in_addr ip_dst;
|
||||
uint32_t oldlen;
|
||||
|
||||
if(ratelimit(3))
|
||||
return;
|
||||
|
||||
/* Swap Ethernet source and destination addresses */
|
||||
|
||||
swap_mac_addresses(packet);
|
||||
|
||||
/* Copy headers from packet into properly aligned structs on the stack */
|
||||
|
||||
memcpy(&ip, packet->data + 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(packet->data + ether_size + ip_size + icmp_size, packet->data + 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(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &ip, ip_size);
|
||||
memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
|
||||
|
||||
packet->len = ether_size + ip_size + icmp_size + oldlen;
|
||||
|
||||
send_packet(source, packet);
|
||||
broadcast_packet(source, packet);
|
||||
}
|
||||
|
||||
/* RFC 791 */
|
||||
|
|
@ -403,6 +588,10 @@ static void route_ipv4_unicast(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 = packet->data[15];
|
||||
|
||||
|
|
@ -442,91 +631,11 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
packet->data[31] == 255 &&
|
||||
packet->data[32] == 255 &&
|
||||
packet->data[33] == 255)))
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
else
|
||||
route_ipv4_unicast(source, packet);
|
||||
}
|
||||
|
||||
/* RFC 2463 */
|
||||
|
||||
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
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, packet->data + 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(packet->data + ether_size + ip6_size + icmp6_size, packet->data + 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(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
|
||||
|
||||
icmp6.icmp6_cksum = checksum;
|
||||
|
||||
/* Copy structs on stack back to packet */
|
||||
|
||||
memcpy(packet->data + ether_size, &ip6, ip6_size);
|
||||
memcpy(packet->data + ether_size + ip6_size, &icmp6, icmp6_size);
|
||||
|
||||
packet->len = ether_size + ip6_size + ntohl(pseudo.length);
|
||||
|
||||
send_packet(source, packet);
|
||||
}
|
||||
|
||||
static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
||||
subnet_t *subnet;
|
||||
node_t *via;
|
||||
|
|
@ -562,6 +671,10 @@ static void route_ipv6_unicast(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) {
|
||||
|
|
@ -678,6 +791,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(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
|
||||
|
|
@ -735,7 +852,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if(broadcast_mode && packet->data[38] == 255)
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
else
|
||||
route_ipv6_unicast(source, packet);
|
||||
}
|
||||
|
|
@ -788,6 +905,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(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
|
||||
packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
|
||||
|
||||
|
|
@ -824,7 +945,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
subnet = lookup_subnet_mac(NULL, &dest);
|
||||
|
||||
if(!subnet) {
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -836,6 +957,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 = packet->data[12] << 8 | packet->data[13];
|
||||
|
||||
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
|
||||
|
|
@ -877,58 +1002,6 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
send_packet(subnet->owner, packet);
|
||||
}
|
||||
|
||||
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 8] < 1) {
|
||||
if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
packet->data[ethlen + 8]--;
|
||||
uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
|
||||
uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
packet->data[ethlen + 10] = checksum >> 8;
|
||||
packet->data[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
case ETH_P_IPV6:
|
||||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[ethlen + 7] < 1) {
|
||||
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->data[ethlen + 7]--;
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void route(node_t *source, vpn_packet_t *packet) {
|
||||
if(forwarding_mode == FMODE_KERNEL && source != myself) {
|
||||
send_packet(myself, packet);
|
||||
|
|
@ -938,10 +1011,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;
|
||||
|
||||
switch (routing_mode) {
|
||||
case RMODE_ROUTER:
|
||||
{
|
||||
|
|
@ -972,7 +1041,7 @@ void route(node_t *source, vpn_packet_t *packet) {
|
|||
break;
|
||||
|
||||
case RMODE_HUB:
|
||||
broadcast_packet(source, packet);
|
||||
route_broadcast(source, packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
src/subnet.c
21
src/subnet.c
|
|
@ -534,18 +534,17 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||
xasprintf(&envp[3], "NODE=%s", owner->name);
|
||||
xasprintf(&envp[4], "NAME=%s", myself->name);
|
||||
|
||||
if(owner != myself) {
|
||||
sockaddr2str(&owner->address, &address, &port);
|
||||
// 4 and 5 are reserved for SUBNET and WEIGHT
|
||||
xasprintf(&envp[6], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[7], "REMOTEPORT=%s", port);
|
||||
// 5 and 6 are reserved for SUBNET and WEIGHT
|
||||
xasprintf(&envp[7], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[8], "REMOTEPORT=%s", port);
|
||||
free(port);
|
||||
free(address);
|
||||
}
|
||||
|
||||
xasprintf(&envp[8], "NAME=%s", myself->name);
|
||||
|
||||
name = up ? "subnet-up" : "subnet-down";
|
||||
|
||||
if(!subnet) {
|
||||
|
|
@ -561,12 +560,12 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
weight = empty;
|
||||
|
||||
// Prepare the SUBNET and WEIGHT variables
|
||||
if(envp[4])
|
||||
free(envp[4]);
|
||||
if(envp[5])
|
||||
free(envp[5]);
|
||||
xasprintf(&envp[4], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[5], "WEIGHT=%s", weight);
|
||||
if(envp[6])
|
||||
free(envp[6]);
|
||||
xasprintf(&envp[5], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[6], "WEIGHT=%s", weight);
|
||||
|
||||
execute_script(name, envp);
|
||||
}
|
||||
|
|
@ -580,8 +579,8 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
|||
weight = empty;
|
||||
|
||||
// Prepare the SUBNET and WEIGHT variables
|
||||
xasprintf(&envp[4], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[5], "WEIGHT=%s", weight);
|
||||
xasprintf(&envp[5], "SUBNET=%s", netstr);
|
||||
xasprintf(&envp[6], "WEIGHT=%s", weight);
|
||||
|
||||
execute_script(name, envp);
|
||||
}
|
||||
|
|
|
|||
15
src/tincd.c
15
src/tincd.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
tincd.c -- the main file for tincd
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2008 Max Rijevski <maksuf@gmail.com>
|
||||
2009 Michael Tokarev <mjt@tls.msk.ru>
|
||||
2010 Julien Muchembled <jm@jmuchemb.eu>
|
||||
|
|
@ -49,7 +49,12 @@
|
|||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include "getopt.h"
|
||||
#endif
|
||||
|
||||
#include "pidfile.h"
|
||||
|
||||
#include "conf.h"
|
||||
|
|
@ -239,7 +244,8 @@ static bool parse_options(int argc, char **argv) {
|
|||
usage(true);
|
||||
return false;
|
||||
}
|
||||
netname = strcmp(optarg, ".") != 0 ? xstrdup(optarg) : NULL;
|
||||
if(optarg && strcmp(optarg, "."))
|
||||
netname = xstrdup(optarg);
|
||||
break;
|
||||
|
||||
case 'o': /* option */
|
||||
|
|
@ -547,9 +553,8 @@ int main(int argc, char **argv) {
|
|||
make_names();
|
||||
|
||||
if(show_version) {
|
||||
printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE,
|
||||
VERSION, __DATE__, __TIME__, PROT_CURRENT);
|
||||
printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
printf("%s version %s\n", PACKAGE, VERSION);
|
||||
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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue