Import Upstream version 1.0.10

This commit is contained in:
Guus Sliepen 2019-08-26 13:44:38 +02:00
parent 5d002cc66a
commit fa871d431d
152 changed files with 15479 additions and 25408 deletions

View file

@ -1,5 +1,4 @@
## Produce this file with automake to get Makefile.in
# $Id: Makefile.am,v 1.4.4.33 2003/08/02 15:13:08 guus Exp $
sbin_PROGRAMS = tincd
@ -9,6 +8,10 @@ tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
if TUNEMU
tincd_SOURCES += bsd/tunemu.c
endif
nodist_tincd_SOURCES = device.c
DEFAULT_INCLUDES =
@ -16,9 +19,13 @@ DEFAULT_INCLUDES =
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h
protocol.h route.h subnet.h bsd/tunemu.h
LIBS = @LIBS@ @LIBINTL@
LIBS = @LIBS@
if TUNEMU
LIBS += -lpcap
endif
tincd_LDADD = \
$(top_builddir)/lib/libvpn.a

View file

@ -1,8 +1,9 @@
# Makefile.in generated by automake 1.10.1 from Makefile.am.
# Makefile.in generated by automake 1.11 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
# Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -14,13 +15,12 @@
@SET_MAKE@
# $Id: Makefile.am,v 1.4.4.33 2003/08/02 15:13:08 guus Exp $
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
@ -36,25 +36,29 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
sbin_PROGRAMS = tincd$(EXEEXT)
@TUNEMU_TRUE@am__append_1 = bsd/tunemu.c
@TUNEMU_TRUE@am__append_2 = -lpcap
subdir = src
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/lzo.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)"
sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(sbin_PROGRAMS)
am__tincd_SOURCES_DIST = conf.c connection.c edge.c event.c graph.c \
logger.c meta.c net.c net_packet.c net_setup.c net_socket.c \
netutl.c node.c process.c protocol.c protocol_auth.c \
protocol_edge.c protocol_misc.c protocol_key.c \
protocol_subnet.c route.c subnet.c tincd.c bsd/tunemu.c
@TUNEMU_TRUE@am__objects_1 = tunemu.$(OBJEXT)
am_tincd_OBJECTS = conf.$(OBJEXT) connection.$(OBJEXT) edge.$(OBJEXT) \
event.$(OBJEXT) graph.$(OBJEXT) logger.$(OBJEXT) \
meta.$(OBJEXT) net.$(OBJEXT) net_packet.$(OBJEXT) \
@ -63,18 +67,19 @@ am_tincd_OBJECTS = conf.$(OBJEXT) connection.$(OBJEXT) edge.$(OBJEXT) \
protocol_auth.$(OBJEXT) protocol_edge.$(OBJEXT) \
protocol_misc.$(OBJEXT) protocol_key.$(OBJEXT) \
protocol_subnet.$(OBJEXT) route.$(OBJEXT) subnet.$(OBJEXT) \
tincd.$(OBJEXT)
tincd.$(OBJEXT) $(am__objects_1)
nodist_tincd_OBJECTS = device.$(OBJEXT)
tincd_OBJECTS = $(am_tincd_OBJECTS) $(nodist_tincd_OBJECTS)
tincd_DEPENDENCIES = $(top_builddir)/lib/libvpn.a
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(tincd_SOURCES) $(nodist_tincd_SOURCES)
DIST_SOURCES = $(tincd_SOURCES)
DIST_SOURCES = $(am__tincd_SOURCES_DIST)
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
@ -99,7 +104,6 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GMSGFMT = @GMSGFMT@
GREP = @GREP@
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
INSTALL = @INSTALL@
@ -107,38 +111,28 @@ INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INTLLIBS = @INTLLIBS@
LDFLAGS = @LDFLAGS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ @LIBINTL@
LIBS = @LIBS@ $(am__append_2)
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
MKINSTALLDIRS = @MKINSTALLDIRS@
MSGFMT = @MSGFMT@
MSGMERGE = @MSGMERGE@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POSUB = @POSUB@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@ -186,17 +180,19 @@ sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c
tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c \
meta.c net.c net_packet.c net_setup.c net_socket.c netutl.c \
node.c process.c protocol.c protocol_auth.c protocol_edge.c \
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
subnet.c tincd.c $(am__append_1)
nodist_tincd_SOURCES = device.c
DEFAULT_INCLUDES =
noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h meta.h net.h netutl.h node.h process.h \
protocol.h route.h subnet.h
protocol.h route.h subnet.h bsd/tunemu.h
tincd_LDADD = \
$(top_builddir)/lib/libvpn.a
@ -210,14 +206,14 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
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 \
@ -235,26 +231,41 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
@list='$(sbin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
$(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
else :; fi; \
done
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \
then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
} \
; done
uninstall-sbinPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(sbin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
rm -f "$(DESTDIR)$(sbindir)/$$f"; \
done
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' `; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(sbindir)" && rm -f $$files
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
@ -292,34 +303,49 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tunemu.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
tunemu.o: bsd/tunemu.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tunemu.o -MD -MP -MF $(DEPDIR)/tunemu.Tpo -c -o tunemu.o `test -f 'bsd/tunemu.c' || echo '$(srcdir)/'`bsd/tunemu.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tunemu.Tpo $(DEPDIR)/tunemu.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bsd/tunemu.c' object='tunemu.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tunemu.o `test -f 'bsd/tunemu.c' || echo '$(srcdir)/'`bsd/tunemu.c
tunemu.obj: bsd/tunemu.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tunemu.obj -MD -MP -MF $(DEPDIR)/tunemu.Tpo -c -o tunemu.obj `if test -f 'bsd/tunemu.c'; then $(CYGPATH_W) 'bsd/tunemu.c'; else $(CYGPATH_W) '$(srcdir)/bsd/tunemu.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tunemu.Tpo $(DEPDIR)/tunemu.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bsd/tunemu.c' object='tunemu.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tunemu.obj `if test -f 'bsd/tunemu.c'; then $(CYGPATH_W) 'bsd/tunemu.c'; else $(CYGPATH_W) '$(srcdir)/bsd/tunemu.c'; fi`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
@ -327,29 +353,34 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
@ -370,13 +401,17 @@ distdir: $(DISTFILES)
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
@ -410,6 +445,7 @@ clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@ -430,6 +466,8 @@ dvi-am:
html: html-am
html-am:
info: info-am
info-am:
@ -438,18 +476,28 @@ install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-sbinPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
@ -489,6 +537,7 @@ uninstall-am: uninstall-sbinPROGRAMS
dist-hook:
rm -f `find . -type l`
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -1,7 +1,8 @@
/*
device.c -- Interaction BSD tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2008 Guus Sliepen <guus@tinc-vpn.org>
2001-2009 Guus Sliepen <guus@tinc-vpn.org>
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1398 2004-11-01 15:18:53Z guus $
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"
@ -27,6 +26,11 @@
#include "net.h"
#include "route.h"
#include "utils.h"
#include "xalloc.h"
#ifdef HAVE_TUNEMU
#include "bsd/tunemu.h"
#endif
#define DEFAULT_DEVICE "/dev/tun0"
@ -34,15 +38,20 @@ typedef enum device_type {
DEVICE_TYPE_TUN,
DEVICE_TYPE_TUNIFHEAD,
DEVICE_TYPE_TAP,
#ifdef HAVE_TUNEMU
DEVICE_TYPE_TUNEMU,
#endif
} device_type_t;
int device_fd = -1;
char *device;
char *iface;
char *device_info;
char *device = NULL;
char *iface = NULL;
static char *device_info = NULL;
static int device_total_in = 0;
static int device_total_out = 0;
#if defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD)
#if defined(TUNEMU)
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD)
static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
#else
static device_type_t device_type = DEVICE_TYPE_TUN;
@ -51,22 +60,19 @@ static device_type_t device_type = DEVICE_TYPE_TUN;
bool setup_device(void) {
char *type;
cp();
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = DEFAULT_DEVICE;
device = xstrdup(DEFAULT_DEVICE);
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return false;
}
iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "tun"))
/* use default */;
#ifdef HAVE_TUNEMU
else if(!strcasecmp(type, "tunemu"))
device_type = DEVICE_TYPE_TUNEMU;
#endif
else if(!strcasecmp(type, "tunnohead"))
device_type = DEVICE_TYPE_TUN;
else if(!strcasecmp(type, "tunifhead"))
@ -74,7 +80,7 @@ bool setup_device(void) {
else if(!strcasecmp(type, "tap"))
device_type = DEVICE_TYPE_TAP;
else {
logger(LOG_ERR, _("Unknown device type %s!"), type);
logger(LOG_ERR, "Unknown device type %s!", type);
return false;
}
} else {
@ -82,6 +88,23 @@ bool setup_device(void) {
device_type = DEVICE_TYPE_TAP;
}
switch(device_type) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU: {
char dynamic_name[256] = "";
device_fd = tunemu_open(dynamic_name);
}
break;
#endif
default:
device_fd = open(device, O_RDWR | O_NONBLOCK);
}
if(device_fd < 0) {
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
return false;
}
switch(device_type) {
default:
device_type = DEVICE_TYPE_TUN;
@ -90,7 +113,7 @@ bool setup_device(void) {
{
const int zero = 0;
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false;
}
}
@ -102,14 +125,14 @@ bool setup_device(void) {
}
#endif
device_info = _("Generic BSD tun device");
device_info = "Generic BSD tun device";
break;
case DEVICE_TYPE_TUNIFHEAD:
#ifdef TUNSIFHEAD
{
const int one = 1;
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false;
}
}
@ -121,35 +144,67 @@ bool setup_device(void) {
}
#endif
device_info = _("Generic BSD tun device");
device_info = "Generic BSD tun device";
break;
case DEVICE_TYPE_TAP:
if(routing_mode == RMODE_ROUTER)
overwrite_mac = true;
device_info = _("Generic BSD tap device");
device_info = "Generic BSD tap device";
#ifdef TAPGIFNAME
{
struct ifreq ifr;
if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) {
if(iface)
free(iface);
iface = xstrdup(ifr.ifr_name);
}
}
#endif
break;
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
device_info = "BSD tunemu device";
break;
#endif
}
logger(LOG_INFO, _("%s is a %s"), device, device_info);
logger(LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void) {
cp();
switch(device_type) {
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
tunemu_close(device_fd);
break;
#endif
default:
close(device_fd);
}
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
switch(device_type) {
case DEVICE_TYPE_TUN:
if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
if(device_type == DEVICE_TYPE_TUNEMU)
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
else
#else
lenin = read(device_fd, packet->data + 14, MTU - 14);
#endif
if(lenin <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -165,7 +220,7 @@ bool read_packet(vpn_packet_t *packet) {
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
_ ("Unknown IP version %d while reading packet from %s %s"),
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
@ -178,7 +233,7 @@ bool read_packet(vpn_packet_t *packet) {
struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
if((lenin = readv(device_fd, vector, 2)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -196,7 +251,7 @@ bool read_packet(vpn_packet_t *packet) {
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
_ ("Unknown address family %x while reading packet from %s %s"),
"Unknown address family %x while reading packet from %s %s",
ntohl(type), device_info, device);
return false;
}
@ -207,7 +262,7 @@ bool read_packet(vpn_packet_t *packet) {
case DEVICE_TYPE_TAP:
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -221,23 +276,20 @@ bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"),
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
packet->len, device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
switch(device_type) {
case DEVICE_TYPE_TUN:
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -259,13 +311,13 @@ bool write_packet(vpn_packet_t *packet)
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
_("Unknown address family %x while writing packet to %s %s"),
"Unknown address family %x while writing packet to %s %s",
af, device_info, device);
return false;
}
if(writev(device_fd, vector, 2) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -274,12 +326,22 @@ bool write_packet(vpn_packet_t *packet)
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
break;
#ifdef HAVE_TUNEMU
case DEVICE_TYPE_TUNEMU:
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
break;
#endif
default:
return false;
}
@ -289,11 +351,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

386
src/bsd/tunemu.c Normal file
View file

@ -0,0 +1,386 @@
/*
* tunemu - Tun device emulation for Darwin
* Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "tunemu.h"
#include <sys/socket.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <util.h>
#include <pcap.h>
#include <stdarg.h>
#include <errno.h>
#include <stdint.h>
#include <stdint.h>
#include <ctype.h>
#include <fcntl.h>
#define PPPPROTO_CTL 1
#define PPP_IP 0x21
#define PPP_IPV6 0x57
#define SC_LOOP_TRAFFIC 0x00000200
#define PPPIOCNEWUNIT _IOWR('t', 62, int)
#define PPPIOCSFLAGS _IOW('t', 89, int)
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
#define PPPIOCATTCHAN _IOW('t', 56, int)
#define PPPIOCGCHAN _IOR('t', 55, int)
#define PPPIOCCONNECT _IOW('t', 58, int)
#define PPPIOCGUNIT _IOR('t', 86, int)
struct sockaddr_ppp
{
u_int8_t ppp_len;
u_int8_t ppp_family;
u_int16_t ppp_proto;
u_int32_t ppp_cookie;
};
enum NPmode
{
NPMODE_PASS,
NPMODE_DROP,
NPMODE_ERROR,
NPMODE_QUEUE
};
struct npioctl
{
int protocol;
enum NPmode mode;
};
#define PPP_KEXT_PATH "/System/Library/Extensions/PPP.kext"
#define ERROR_BUFFER_SIZE 1024
char tunemu_error[ERROR_BUFFER_SIZE];
static int pcap_use_count = 0;
static pcap_t *pcap = NULL;
static int data_buffer_length = 0;
static char *data_buffer = NULL;
static void tun_error(char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
va_end(vl);
}
static void tun_noerror()
{
*tunemu_error = 0;
}
static void closeall()
{
int fd = getdtablesize();
while (fd--)
close(fd);
open("/dev/null", O_RDWR, 0);
dup(0);
dup(0);
}
static int ppp_load_kext()
{
int pid = fork();
if (pid < 0)
{
tun_error("fork for ppp kext: %s", strerror(errno));
return -1;
}
if (pid == 0)
{
closeall();
execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL);
exit(1);
}
int status;
while (waitpid(pid, &status, 0) < 0)
{
if (errno == EINTR)
continue;
tun_error("waitpid for ppp kext: %s", strerror(errno));
return -1;
}
if (WEXITSTATUS(status) != 0)
{
tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH);
return -1;
}
tun_noerror();
return 0;
}
static int ppp_new_instance()
{
// create ppp socket
int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
if (ppp_sockfd < 0)
{
if (ppp_load_kext() < 0)
return -1;
ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
if (ppp_sockfd < 0)
{
tun_error("creating ppp socket: %s", strerror(errno));
return -1;
}
}
// connect to ppp procotol
struct sockaddr_ppp pppaddr;
pppaddr.ppp_len = sizeof(struct sockaddr_ppp);
pppaddr.ppp_family = AF_PPP;
pppaddr.ppp_proto = PPPPROTO_CTL;
pppaddr.ppp_cookie = 0;
if (connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0)
{
tun_error("connecting ppp socket: %s", strerror(errno));
close(ppp_sockfd);
return -1;
}
tun_noerror();
return ppp_sockfd;
}
static int ppp_new_unit(int *unit_number)
{
int fd = ppp_new_instance();
if (fd < 0)
return -1;
// create ppp unit
if (ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0)
{
tun_error("creating ppp unit: %s", strerror(errno));
close(fd);
return -1;
}
tun_noerror();
return fd;
}
static int ppp_setup_unit(int unit_fd)
{
// send traffic to program
int flags = SC_LOOP_TRAFFIC;
if (ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0)
{
tun_error("setting ppp loopback mode: %s", strerror(errno));
return -1;
}
// allow packets
struct npioctl npi;
npi.protocol = PPP_IP;
npi.mode = NPMODE_PASS;
if (ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0)
{
tun_error("starting ppp unit: %s", strerror(errno));
return -1;
}
tun_noerror();
return 0;
}
static int open_pcap()
{
if (pcap != NULL)
{
pcap_use_count++;
return 0;
}
char errbuf[PCAP_ERRBUF_SIZE];
pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf);
pcap_use_count = 1;
if (pcap == NULL)
{
tun_error("opening pcap: %s", errbuf);
return -1;
}
tun_noerror();
return 0;
}
static void close_pcap()
{
if (pcap == NULL)
return;
pcap_use_count--;
if (pcap_use_count == 0)
{
pcap_close(pcap);
pcap = NULL;
}
}
static void allocate_data_buffer(int size)
{
if (data_buffer_length < size)
{
free(data_buffer);
data_buffer_length = size;
data_buffer = malloc(data_buffer_length);
}
}
static void make_device_name(tunemu_device device, int unit_number)
{
snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number);
}
static int check_device_name(tunemu_device device)
{
if (strlen(device) < 4)
return -1;
int unit_number = atoi(device + 3);
if (unit_number < 0 || unit_number > 999)
return -1;
tunemu_device compare;
make_device_name(compare, unit_number);
if (strcmp(device, compare) != 0)
return -1;
return 0;
}
int tunemu_open(tunemu_device device)
{
int ppp_unit_number = -1;
if (device[0] != 0)
{
if (check_device_name(device) < 0)
{
tun_error("invalid device name \"%s\"", device);
return -1;
}
ppp_unit_number = atoi(device + 3);
}
int ppp_unit_fd = ppp_new_unit(&ppp_unit_number);
if (ppp_unit_fd < 0)
return -1;
if (ppp_setup_unit(ppp_unit_fd) < 0)
{
close(ppp_unit_fd);
return -1;
}
if (open_pcap() < 0)
{
close(ppp_unit_fd);
return -1;
}
make_device_name(device, ppp_unit_number);
return ppp_unit_fd;
}
int tunemu_close(int ppp_sockfd)
{
int ret = close(ppp_sockfd);
if (ret == 0)
close_pcap();
return ret;
}
int tunemu_read(int ppp_sockfd, char *buffer, int length)
{
allocate_data_buffer(length + 2);
length = read(ppp_sockfd, data_buffer, length + 2);
if (length < 0)
{
tun_error("reading packet: %s", strerror(errno));
return length;
}
tun_noerror();
length -= 2;
if (length < 0)
return 0;
memcpy(buffer, data_buffer + 2, length);
return length;
}
int tunemu_write(int ppp_sockfd, char *buffer, int length)
{
allocate_data_buffer(length + 4);
data_buffer[0] = 0x02;
data_buffer[1] = 0x00;
data_buffer[2] = 0x00;
data_buffer[3] = 0x00;
memcpy(data_buffer + 4, buffer, length);
if (pcap == NULL)
{
tun_error("pcap not open");
return -1;
}
length = pcap_inject(pcap, data_buffer, length + 4);
if (length < 0)
{
tun_error("injecting packet: %s", pcap_geterr(pcap));
return length;
}
tun_noerror();
length -= 4;
if (length < 0)
return 0;
return length;
}

32
src/bsd/tunemu.h Normal file
View file

@ -0,0 +1,32 @@
/*
* tunemu - Tun device emulation for Darwin
* Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TUNEMU_H
#define TUNEMU_H
typedef char tunemu_device[7];
extern char tunemu_error[];
int tunemu_open(tunemu_device dev);
int tunemu_close(int fd);
int tunemu_read(int fd, char *buffer, int length);
int tunemu_write(int fd, char *buffer, int length);
#endif

View file

@ -2,7 +2,7 @@
conf.c -- configuration code
Copyright (C) 1998 Robert van der Meulen
1998-2005 Ivo Timmermans
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2000 Cris van Pelt
This program is free software; you can redistribute it and/or modify
@ -15,11 +15,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.c 1595 2008-12-22 20:27:52Z guus $
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"
@ -38,8 +36,7 @@ int pingtimeout = 0; /* seconds to wait for response */
char *confbase = NULL; /* directory in which all config files are */
char *netname = NULL; /* name of the vpn network */
static int config_compare(const config_t *a, const config_t *b)
{
static int config_compare(const config_t *a, const config_t *b) {
int result;
result = strcasecmp(a->variable, b->variable);
@ -55,32 +52,20 @@ static int config_compare(const config_t *a, const config_t *b)
return strcmp(a->file, b->file);
}
void init_configuration(avl_tree_t ** config_tree)
{
cp();
void init_configuration(avl_tree_t ** config_tree) {
*config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
}
void exit_configuration(avl_tree_t ** config_tree)
{
cp();
void exit_configuration(avl_tree_t ** config_tree) {
avl_delete_tree(*config_tree);
*config_tree = NULL;
}
config_t *new_config(void)
{
cp();
config_t *new_config(void) {
return xmalloc_and_zero(sizeof(config_t));
}
void free_config(config_t *cfg)
{
cp();
void free_config(config_t *cfg) {
if(cfg->variable)
free(cfg->variable);
@ -93,19 +78,13 @@ void free_config(config_t *cfg)
free(cfg);
}
void config_add(avl_tree_t *config_tree, config_t *cfg)
{
cp();
void config_add(avl_tree_t *config_tree, config_t *cfg) {
avl_insert(config_tree, cfg);
}
config_t *lookup_config(avl_tree_t *config_tree, char *variable)
{
config_t *lookup_config(avl_tree_t *config_tree, char *variable) {
config_t cfg, *found;
cp();
cfg.variable = variable;
cfg.file = "";
cfg.line = 0;
@ -121,13 +100,10 @@ config_t *lookup_config(avl_tree_t *config_tree, char *variable)
return found;
}
config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
{
config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) {
avl_node_t *node;
config_t *found;
cp();
node = avl_search_node(config_tree, cfg);
if(node) {
@ -142,10 +118,7 @@ config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg)
return NULL;
}
bool get_config_bool(const config_t *cfg, bool *result)
{
cp();
bool get_config_bool(const config_t *cfg, bool *result) {
if(!cfg)
return false;
@ -157,32 +130,26 @@ bool get_config_bool(const config_t *cfg, bool *result)
return true;
}
logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
bool get_config_int(const config_t *cfg, int *result)
{
cp();
bool get_config_int(const config_t *cfg, int *result) {
if(!cfg)
return false;
if(sscanf(cfg->value, "%d", result) == 1)
return true;
logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
bool get_config_string(const config_t *cfg, char **result)
{
cp();
bool get_config_string(const config_t *cfg, char **result) {
if(!cfg)
return false;
@ -191,12 +158,9 @@ bool get_config_string(const config_t *cfg, char **result)
return true;
}
bool get_config_address(const config_t *cfg, struct addrinfo **result)
{
bool get_config_address(const config_t *cfg, struct addrinfo **result) {
struct addrinfo *ai;
cp();
if(!cfg)
return false;
@ -207,23 +171,20 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result)
return true;
}
logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
bool get_config_subnet(const config_t *cfg, subnet_t ** result)
{
bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
subnet_t subnet = {0};
cp();
if(!cfg)
return false;
if(!str2net(&subnet, cfg->value)) {
logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
@ -234,7 +195,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result)
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
|| ((subnet.type == SUBNET_IPV6)
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line);
return false;
}
@ -254,8 +215,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result)
given, and buf needs to be expanded, the var pointed to by buflen
will be increased.
*/
static char *readline(FILE * fp, char **buf, size_t *buflen)
{
static char *readline(FILE * fp, char **buf, size_t *buflen) {
char *newline = NULL;
char *p;
char *line; /* The array that contains everything that has been read so far */
@ -301,6 +261,8 @@ static char *readline(FILE * fp, char **buf, size_t *buflen)
size = newsize;
} else {
*newline = '\0'; /* kill newline */
if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
newline[-1] = '\0';
break; /* yay */
}
}
@ -317,8 +279,7 @@ static char *readline(FILE * fp, char **buf, size_t *buflen)
Parse a configuration file and put the results in the configuration tree
starting at *base.
*/
int read_config_file(avl_tree_t *config_tree, const char *fname)
{
int read_config_file(avl_tree_t *config_tree, const char *fname) {
int err = -2; /* Parse error */
FILE *fp;
char *buffer, *line;
@ -329,12 +290,10 @@ int read_config_file(avl_tree_t *config_tree, const char *fname)
config_t *cfg;
size_t bufsize;
cp();
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
logger(LOG_ERR, "Cannot open config file %s: %s", fname,
strerror(errno));
return -3;
}
@ -388,7 +347,7 @@ int read_config_file(avl_tree_t *config_tree, const char *fname)
if(!*value) {
logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
logger(LOG_ERR, "No value for variable `%s' on line %d while reading config file %s",
variable, lineno, fname);
break;
}
@ -408,18 +367,15 @@ int read_config_file(avl_tree_t *config_tree, const char *fname)
return err;
}
bool read_server_config()
{
bool read_server_config() {
char *fname;
int x;
cp();
asprintf(&fname, "%s/tinc.conf", confbase);
xasprintf(&fname, "%s/tinc.conf", confbase);
x = read_config_file(config_tree, fname);
if(x == -1) { /* System error: complain */
logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
}
free(fname);
@ -427,8 +383,7 @@ bool read_server_config()
return x == 0;
}
FILE *ask_and_open(const char *filename, const char *what, const char *mode)
{
FILE *ask_and_open(const char *filename, const char *what) {
FILE *r;
char *directory;
char *fn;
@ -441,14 +396,14 @@ FILE *ask_and_open(const char *filename, const char *what, const char *mode)
fn = xstrdup(filename);
} else {
/* Ask for a file and/or directory name. */
fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
what, filename);
fflush(stdout);
fn = readline(stdin, NULL, NULL);
if(!fn) {
fprintf(stderr, _("Error while reading stdin: %s\n"),
fprintf(stderr, "Error while reading stdin: %s\n",
strerror(errno));
return NULL;
}
@ -467,7 +422,7 @@ FILE *ask_and_open(const char *filename, const char *what, const char *mode)
char *p;
directory = get_current_dir_name();
asprintf(&p, "%s/%s", directory, fn);
xasprintf(&p, "%s/%s", directory, fn);
free(fn);
free(directory);
fn = p;
@ -477,10 +432,10 @@ FILE *ask_and_open(const char *filename, const char *what, const char *mode)
/* Open it first to keep the inode busy */
r = fopen(fn, mode);
r = fopen(fn, "r+") ?: fopen(fn, "w+");
if(!r) {
fprintf(stderr, _("Error opening file `%s': %s\n"),
fprintf(stderr, "Error opening file `%s': %s\n",
fn, strerror(errno));
free(fn);
return NULL;
@ -490,3 +445,34 @@ FILE *ask_and_open(const char *filename, const char *what, const char *mode)
return r;
}
bool disable_old_keys(FILE *f) {
char buf[100];
long pos;
bool disabled = false;
rewind(f);
pos = ftell(f);
while(fgets(buf, sizeof buf, f)) {
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
buf[11] = 'O';
buf[12] = 'L';
buf[13] = 'D';
fseek(f, pos, SEEK_SET);
fputs(buf, f);
disabled = true;
}
else if(!strncmp(buf, "-----END RSA", 12)) {
buf[ 9] = 'O';
buf[10] = 'L';
buf[11] = 'D';
fseek(f, pos, SEEK_SET);
fputs(buf, f);
disabled = true;
}
pos = ftell(f);
}
return disabled;
}

View file

@ -1,7 +1,7 @@
/*
conf.h -- header for conf.c
Copyright (C) 1998-2005 Ivo Timmermans
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.h 1452 2006-04-26 13:52:58Z guus $
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_CONF_H__
@ -58,7 +56,8 @@ extern bool get_config_subnet(const config_t *, struct subnet_t **);
extern int read_config_file(avl_tree_t *, const char *);
extern bool read_server_config(void);
extern FILE *ask_and_open(const char *, const char *, const char *);
extern FILE *ask_and_open(const char *, const char *);
extern bool is_safe_path(const char *);
extern bool disable_old_keys(FILE *);
#endif /* __TINC_CONF_H__ */

View file

@ -1,7 +1,8 @@
/*
connection.c -- connection list management
Copyright (C) 2000-2007 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
2008 Max Rijevski <maksuf@gmail.com>
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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.c 1600 2008-12-23 23:14:37Z guus $
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"
@ -35,35 +34,25 @@
avl_tree_t *connection_tree; /* Meta connections */
connection_t *broadcast;
static int connection_compare(const connection_t *a, const connection_t *b)
{
return (void *)a - (void *)b;
static int connection_compare(const connection_t *a, const connection_t *b) {
return a < b ? -1 : a == b ? 0 : 1;
}
void init_connections(void)
{
cp();
void init_connections(void) {
connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
broadcast = new_connection();
broadcast->name = xstrdup(_("everyone"));
broadcast->hostname = xstrdup(_("BROADCAST"));
broadcast->name = xstrdup("everyone");
broadcast->hostname = xstrdup("BROADCAST");
}
void exit_connections(void)
{
cp();
void exit_connections(void) {
avl_delete_tree(connection_tree);
free_connection(broadcast);
}
connection_t *new_connection(void)
{
connection_t *new_connection(void) {
connection_t *c;
cp();
c = xmalloc_and_zero(sizeof(connection_t));
if(!c)
@ -74,10 +63,7 @@ connection_t *new_connection(void)
return c;
}
void free_connection(connection_t *c)
{
cp();
void free_connection(connection_t *c) {
if(c->name)
free(c->name);
@ -118,47 +104,35 @@ void free_connection(connection_t *c)
free(c);
}
void connection_add(connection_t *c)
{
cp();
void connection_add(connection_t *c) {
avl_insert(connection_tree, c);
}
void connection_del(connection_t *c)
{
cp();
void connection_del(connection_t *c) {
avl_delete(connection_tree, c);
}
void dump_connections(void)
{
void dump_connections(void) {
avl_node_t *node;
connection_t *c;
cp();
logger(LOG_DEBUG, _("Connections:"));
logger(LOG_DEBUG, "Connections:");
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x outbuf %d/%d/%d"),
c->name, c->hostname, c->options, c->socket, c->status.value,
logger(LOG_DEBUG, " %s at %s options %lx socket %d status %04x outbuf %d/%d/%d",
c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status),
c->outbufsize, c->outbufstart, c->outbuflen);
}
logger(LOG_DEBUG, _("End of connections."));
logger(LOG_DEBUG, "End of connections.");
}
bool read_connection_config(connection_t *c)
{
bool read_connection_config(connection_t *c) {
char *fname;
int x;
cp();
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
x = read_config_file(c->config_tree, fname);
free(fname);

View file

@ -1,6 +1,6 @@
/*
connection.h -- header for connection.c
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.h 1456 2006-08-08 13:21:08Z guus $
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_CONNECTION_H__
@ -32,20 +30,17 @@
#define OPTION_TCPONLY 0x0002
#define OPTION_PMTU_DISCOVERY 0x0004
typedef union connection_status_t {
struct {
int pinged:1; /* sent ping */
int active:1; /* 1 if active.. */
int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
int termreq:1; /* the termination of this connection was requested */
int remove:1; /* Set to 1 if you want this connection removed */
int timeout:1; /* 1 if gotten timeout */
int encryptout:1; /* 1 if we can encrypt outgoing traffic */
int decryptin:1; /* 1 if we have to decrypt incoming traffic */
int mst:1; /* 1 if this connection is part of a minimum spanning tree */
int unused:23;
};
uint32_t value;
typedef struct connection_status_t {
int pinged:1; /* sent ping */
int active:1; /* 1 if active.. */
int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
int termreq:1; /* the termination of this connection was requested */
int remove:1; /* Set to 1 if you want this connection removed */
int timeout:1; /* 1 if gotten timeout */
int encryptout:1; /* 1 if we can encrypt outgoing traffic */
int decryptin:1; /* 1 if we have to decrypt incoming traffic */
int mst:1; /* 1 if this connection is part of a minimum spanning tree */
int unused:23;
} connection_status_t;
#include "edge.h"

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Windows tap driver in a Cygwin environment
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2006 Guus Sliepen <guus@tinc-vpn.org>
2002-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -38,7 +36,7 @@ int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE;
char *device = NULL;
char *iface = NULL;
char *device_info = NULL;
static char *device_info = NULL;
static int device_total_in = 0;
static int device_total_out = 0;
@ -46,8 +44,7 @@ static int device_total_out = 0;
static pid_t reader_pid;
static int sp[2];
bool setup_device(void)
{
bool setup_device(void) {
HKEY key, key2;
int i, err;
@ -60,15 +57,13 @@ bool setup_device(void)
bool found = false;
cp();
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false;
}
@ -120,7 +115,7 @@ bool setup_device(void)
RegCloseKey(key);
if(!found) {
logger(LOG_ERR, _("No Windows tap device found!"));
logger(LOG_ERR, "No Windows tap device found!");
return false;
}
@ -137,7 +132,7 @@ bool setup_device(void)
Furthermore I don't really know how to do it the "Windows" way. */
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
return false;
}
@ -146,7 +141,7 @@ bool setup_device(void)
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for writing: %s"), device, iface, winerror(GetLastError()));
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
return false;
}
@ -155,7 +150,7 @@ bool setup_device(void)
/* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
return false;
}
@ -168,7 +163,7 @@ bool setup_device(void)
reader_pid = fork();
if(reader_pid == -1) {
logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
return false;
}
@ -184,13 +179,13 @@ bool setup_device(void)
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for reading: %s"), device, iface, winerror(GetLastError()));
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
buf[0] = 0;
write(sp[1], buf, 1);
exit(1);
}
logger(LOG_DEBUG, _("Tap reader forked and running."));
logger(LOG_DEBUG, "Tap reader forked and running.");
/* Notify success */
@ -207,36 +202,33 @@ bool setup_device(void)
read(device_fd, &gelukt, 1);
if(gelukt != 1) {
logger(LOG_DEBUG, _("Tap reader failed!"));
logger(LOG_DEBUG, "Tap reader failed!");
return false;
}
device_info = _("Windows tap device");
device_info = "Windows tap device";
logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
close(sp[0]);
close(sp[1]);
CloseHandle(device_handle);
kill(reader_pid, SIGKILL);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -245,23 +237,20 @@ bool read_packet(vpn_packet_t *packet)
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
bool write_packet(vpn_packet_t *packet) {
long lenout;
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
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, NULL)) {
logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
@ -270,11 +259,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

View file

@ -1,6 +1,6 @@
/*
net.h -- generic header for device.c
Copyright (C) 2001-2005 Ivo Timmermans <zarq@iname.com>
Copyright (C) 2001-2005 Ivo Timmermans
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.h 1452 2006-04-26 13:52:58Z guus $
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_DEVICE_H__

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: edge.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -32,13 +30,11 @@
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
static int edge_compare(const edge_t *a, const edge_t *b)
{
static int edge_compare(const edge_t *a, const edge_t *b) {
return strcmp(a->to->name, b->to->name);
}
static int edge_weight_compare(const edge_t *a, const edge_t *b)
{
static int edge_weight_compare(const edge_t *a, const edge_t *b) {
int result;
result = a->weight - b->weight;
@ -54,56 +50,35 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b)
return strcmp(a->to->name, b->to->name);
}
void init_edges(void)
{
cp();
void init_edges(void) {
edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
}
avl_tree_t *new_edge_tree(void)
{
cp();
avl_tree_t *new_edge_tree(void) {
return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
}
void free_edge_tree(avl_tree_t *edge_tree)
{
cp();
void free_edge_tree(avl_tree_t *edge_tree) {
avl_delete_tree(edge_tree);
}
void exit_edges(void)
{
cp();
void exit_edges(void) {
avl_delete_tree(edge_weight_tree);
}
/* Creation and deletion of connection elements */
edge_t *new_edge(void)
{
cp();
edge_t *new_edge(void) {
return xmalloc_and_zero(sizeof(edge_t));
}
void free_edge(edge_t *e)
{
cp();
void free_edge(edge_t *e) {
sockaddrfree(&e->address);
free(e);
}
void edge_add(edge_t *e)
{
cp();
void edge_add(edge_t *e) {
avl_insert(edge_weight_tree, e);
avl_insert(e->from->edge_tree, e);
@ -113,10 +88,7 @@ void edge_add(edge_t *e)
e->reverse->reverse = e;
}
void edge_del(edge_t *e)
{
cp();
void edge_del(edge_t *e) {
if(e->reverse)
e->reverse->reverse = NULL;
@ -124,39 +96,33 @@ void edge_del(edge_t *e)
avl_delete(e->from->edge_tree, e);
}
edge_t *lookup_edge(node_t *from, node_t *to)
{
edge_t *lookup_edge(node_t *from, node_t *to) {
edge_t v;
cp();
v.from = from;
v.to = to;
return avl_search(from->edge_tree, &v);
}
void dump_edges(void)
{
void dump_edges(void) {
avl_node_t *node, *node2;
node_t *n;
edge_t *e;
char *address;
cp();
logger(LOG_DEBUG, _("Edges:"));
logger(LOG_DEBUG, "Edges:");
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
e = node2->data;
address = sockaddr2hostname(&e->address);
logger(LOG_DEBUG, _(" %s to %s at %s options %lx weight %d"),
logger(LOG_DEBUG, " %s to %s at %s options %lx weight %d",
e->from->name, e->to->name, address, e->options, e->weight);
free(address);
}
}
logger(LOG_DEBUG, _("End of edges."));
logger(LOG_DEBUG, "End of edges.");
}

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: edge.h 1452 2006-04-26 13:52:58Z guus $
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_EDGE_H__

View file

@ -1,6 +1,6 @@
/*
event.c -- event queue
Copyright (C) 2002-2007 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
2002-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: event.c 1595 2008-12-22 20:27:52Z guus $
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"
@ -32,8 +30,7 @@ extern time_t now;
int id;
static int event_compare(const event_t *a, const event_t *b)
{
static int event_compare(const event_t *a, const event_t *b) {
if(a->time > b->time)
return 1;
@ -43,82 +40,66 @@ static int event_compare(const event_t *a, const event_t *b)
return a->id - b->id;
}
void init_events(void)
{
cp();
event_tree = avl_alloc_tree((avl_compare_t) event_compare, NULL);
void init_events(void) {
event_tree = avl_alloc_tree((avl_compare_t) event_compare, (avl_action_t) free_event);
}
void exit_events(void)
{
cp();
void exit_events(void) {
avl_delete_tree(event_tree);
}
void flush_events(void)
{
avl_tree_t *to_flush;
void expire_events(void) {
avl_node_t *node;
event_t *event;
time_t diff;
/*
* Events can be inserted from event handlers, so only flush events
* already in the priority queue.
* Make all events appear expired by substracting the difference between
* the expiration time of the last event and the current time.
*/
cp();
if(!event_tree->tail)
return;
to_flush = event_tree;
init_events();
while (to_flush->head) {
event = to_flush->head->data;
event->handler(event->data);
avl_delete(to_flush, event);
event = event_tree->tail->data;
if(event->time < now)
return;
diff = 1 + event->time - now;
for(node = event_tree->head; node; node = node->next) {
event = node->data;
event->time -= diff;
}
avl_delete_tree(to_flush);
}
event_t *new_event(void)
{
cp();
event_t *new_event(void) {
return xmalloc_and_zero(sizeof(event_t));
}
void free_event(event_t *event)
{
cp();
void free_event(event_t *event) {
free(event);
}
void event_add(event_t *event)
{
cp();
void event_add(event_t *event) {
event->id = ++id;
avl_insert(event_tree, event);
}
void event_del(event_t *event)
{
cp();
void event_del(event_t *event) {
avl_delete(event_tree, event);
}
event_t *get_expired_event(void)
{
event_t *get_expired_event(void) {
event_t *event;
cp();
if(event_tree->head) {
event = event_tree->head->data;
if(event->time < now) {
event_del(event);
avl_node_t *node = event_tree->head;
avl_unlink_node(event_tree, node);
free(node);
return event;
}
}

View file

@ -1,6 +1,6 @@
/*
event.h -- header for event.c
Copyright (C) 2002-2007 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
2002-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: event.h 1595 2008-12-22 20:27:52Z guus $
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_EVENT_H__
@ -38,7 +36,7 @@ typedef struct {
extern void init_events(void);
extern void exit_events(void);
extern void flush_events(void);
extern void expire_events(void);
extern event_t *new_event(void) __attribute__ ((__malloc__));
extern void free_event(event_t *);
extern void event_add(event_t *);

View file

@ -1,6 +1,6 @@
/*
graph.c -- graph algorithms
Copyright (C) 2001-2007 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2009 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: graph.c 1595 2008-12-22 20:27:52Z guus $
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.
*/
/* We need to generate two trees from the graph:
@ -57,6 +55,7 @@
#include "process.h"
#include "subnet.h"
#include "utils.h"
#include "xalloc.h"
static bool graph_changed = true;
@ -65,8 +64,7 @@ static bool graph_changed = true;
Please note that sorting on weight is already done by add_edge().
*/
void mst_kruskal(void)
{
void mst_kruskal(void) {
avl_node_t *node, *next;
edge_t *e;
node_t *n;
@ -75,8 +73,6 @@ void mst_kruskal(void)
int safe_edges = 0;
bool skipped;
cp();
/* Clear MST status on connections */
for(node = connection_tree->head; node; node = node->next) {
@ -149,8 +145,7 @@ void mst_kruskal(void)
Running time: O(E)
*/
void sssp_bfs(void)
{
void sssp_bfs(void) {
avl_node_t *node, *next, *to;
edge_t *e;
node_t *n;
@ -162,8 +157,6 @@ void sssp_bfs(void)
char *envp[7];
int i;
cp();
todo_list = list_alloc(NULL);
/* Clear visited status on nodes */
@ -226,27 +219,8 @@ void sssp_bfs(void)
e->to->via = indirect ? n->via : e->to;
e->to->options = e->options;
if(sockaddrcmp(&e->to->address, &e->address)) {
node = avl_unlink(node_udp_tree, e->to);
sockaddrfree(&e->to->address);
sockaddrcpy(&e->to->address, &e->address);
if(e->to->hostname)
free(e->to->hostname);
e->to->hostname = sockaddr2hostname(&e->to->address);
if(node)
avl_insert_node(node_udp_tree, node);
if(e->to->options & OPTION_PMTU_DISCOVERY) {
e->to->mtuprobes = 0;
e->to->minmtu = 0;
e->to->maxmtu = MTU;
if(e->to->status.validkey)
send_mtu_probe(e->to);
}
}
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
update_node_udp(e->to, &e->address);
list_insert_tail(todo_list, e->to);
}
@ -267,15 +241,15 @@ void sssp_bfs(void)
n->status.reachable = !n->status.reachable;
if(n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became reachable"),
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
n->name, n->hostname);
avl_insert(node_udp_tree, n);
} else {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became unreachable"),
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
n->name, n->hostname);
avl_delete(node_udp_tree, n);
}
/* TODO: only clear status.validkey if node is unreachable? */
n->status.validkey = false;
n->status.waitingforkey = false;
@ -283,18 +257,23 @@ void sssp_bfs(void)
n->minmtu = 0;
n->mtuprobes = 0;
asprintf(&envp[0], "NETNAME=%s", netname ? : "");
asprintf(&envp[1], "DEVICE=%s", device ? : "");
asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
asprintf(&envp[3], "NODE=%s", n->name);
if(n->mtuevent) {
event_del(n->mtuevent);
n->mtuevent = NULL;
}
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
xasprintf(&envp[3], "NODE=%s", n->name);
sockaddr2str(&n->address, &address, &port);
asprintf(&envp[4], "REMOTEADDRESS=%s", address);
asprintf(&envp[5], "REMOTEPORT=%s", port);
xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
xasprintf(&envp[5], "REMOTEPORT=%s", port);
envp[6] = NULL;
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
asprintf(&name,
xasprintf(&name,
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
n->name);
execute_script(name, envp);
@ -311,8 +290,8 @@ void sssp_bfs(void)
}
}
void graph(void)
{
void graph(void) {
subnet_cache_flush();
sssp_bfs();
mst_kruskal();
graph_changed = true;
@ -326,8 +305,7 @@ void graph(void)
dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
*/
void dump_graph(void)
{
void dump_graph(void) {
avl_node_t *node;
node_t *n;
edge_t *e;
@ -344,7 +322,7 @@ void dump_graph(void)
if(filename[0] == '|') {
file = popen(filename + 1, "w");
} else {
asprintf(&tmpname, "%s.new", filename);
xasprintf(&tmpname, "%s.new", filename);
file = fopen(tmpname, "w");
}

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: graph.h 1463 2006-11-11 14:11:16Z guus $
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_GRAPH_H__

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Linux ethertap and tun/tap device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
2001-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1488 2006-12-16 16:53:58Z guus $
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"
@ -34,6 +32,7 @@
#include "net.h"
#include "route.h"
#include "utils.h"
#include "xalloc.h"
typedef enum device_type_t {
DEVICE_TYPE_ETHERTAP,
@ -43,33 +42,31 @@ typedef enum device_type_t {
int device_fd = -1;
static device_type_t device_type;
char *device;
char *iface;
char ifrname[IFNAMSIZ];
char *device_info;
char *device = NULL;
char *iface = NULL;
static char ifrname[IFNAMSIZ];
static char *device_info;
static int device_total_in = 0;
static int device_total_out = 0;
bool setup_device(void)
{
bool setup_device(void) {
struct ifreq ifr;
cp();
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = DEFAULT_DEVICE;
device = xstrdup(DEFAULT_DEVICE);
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
#ifdef HAVE_LINUX_IF_TUN_H
iface = netname;
if (netname != NULL)
iface = xstrdup(netname);
#else
iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
#endif
device_fd = open(device, O_RDWR | O_NONBLOCK);
if(device_fd < 0) {
logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
return false;
}
@ -80,11 +77,11 @@ bool setup_device(void)
if(routing_mode == RMODE_ROUTER) {
ifr.ifr_flags = IFF_TUN;
device_type = DEVICE_TYPE_TUN;
device_info = _("Linux tun/tap device (tun mode)");
device_info = "Linux tun/tap device (tun mode)";
} else {
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
device_type = DEVICE_TYPE_TAP;
device_info = _("Linux tun/tap device (tap mode)");
device_info = "Linux tun/tap device (tap mode)";
}
if(iface)
@ -92,45 +89,46 @@ bool setup_device(void)
if(!ioctl(device_fd, TUNSETIFF, &ifr)) {
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
iface = ifrname;
if(iface) free(iface);
iface = xstrdup(ifrname);
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
logger(LOG_WARNING, _("Old ioctl() request was needed for %s"), device);
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
iface = ifrname;
if(iface) free(iface);
iface = xstrdup(ifrname);
} else
#endif
{
if(routing_mode == RMODE_ROUTER)
overwrite_mac = true;
device_info = _("Linux ethertap device");
device_info = "Linux ethertap device";
device_type = DEVICE_TYPE_ETHERTAP;
iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
if(iface)
free(iface);
iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
}
logger(LOG_INFO, _("%s is a %s"), device, device_info);
logger(LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
switch(device_type) {
case DEVICE_TYPE_TUN:
lenin = read(device_fd, packet->data + 10, MTU - 10);
if(lenin <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"),
logger(LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
@ -141,7 +139,7 @@ bool read_packet(vpn_packet_t *packet)
lenin = read(device_fd, packet->data, MTU);
if(lenin <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"),
logger(LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
@ -152,7 +150,7 @@ bool read_packet(vpn_packet_t *packet)
lenin = read(device_fd, packet->data - 2, MTU + 2);
if(lenin <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"),
logger(LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
@ -163,31 +161,28 @@ bool read_packet(vpn_packet_t *packet)
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
switch(device_type) {
case DEVICE_TYPE_TUN:
packet->data[10] = packet->data[11] = 0;
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -196,7 +191,7 @@ bool write_packet(vpn_packet_t *packet)
*(short int *)(packet->data - 2) = packet->len;
if(write(device_fd, packet->data - 2, packet->len + 2) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -208,11 +203,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: logger.c 1452 2006-04-26 13:52:58Z guus $
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"

View file

@ -1,7 +1,8 @@
/*
meta.c -- handle the meta communication
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
2006 Scott Lamb <slamb@slamb.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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: meta.c 1471 2006-11-14 12:28:04Z guus $
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"
@ -34,14 +33,16 @@
#include "utils.h"
#include "xalloc.h"
bool send_meta(connection_t *c, const char *buffer, int length)
{
bool send_meta(connection_t *c, const char *buffer, int length) {
int outlen;
int result;
cp();
if(!c) {
logger(LOG_ERR, "send_meta() called with NULL pointer!");
abort();
}
ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
c->name, c->hostname);
if(!c->outbuflen)
@ -63,11 +64,11 @@ bool send_meta(connection_t *c, const char *buffer, int length)
result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
&outlen, (unsigned char *)buffer, length);
if(!result || outlen < length) {
logger(LOG_ERR, _("Error while encrypting metadata to %s (%s): %s"),
logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
} else if(outlen > length) {
logger(LOG_EMERG, _("Encrypted data too long! Heap corrupted!"));
logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
abort();
}
c->outbuflen += outlen;
@ -79,29 +80,28 @@ bool send_meta(connection_t *c, const char *buffer, int length)
return true;
}
bool flush_meta(connection_t *c)
{
bool flush_meta(connection_t *c) {
int result;
ifdebug(META) logger(LOG_DEBUG, _("Flushing %d bytes to %s (%s)"),
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
c->outbuflen, c->name, c->hostname);
while(c->outbuflen) {
result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
if(result <= 0) {
if(!errno || errno == EPIPE) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection closed by %s (%s)"),
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
c->name, c->hostname);
} else if(errno == EINTR) {
continue;
#ifdef EWOULDBLOCK
} else if(errno == EWOULDBLOCK) {
ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Flushing %d bytes to %s (%s) would block"),
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
c->outbuflen, c->name, c->hostname);
return true;
#endif
} else {
logger(LOG_ERR, _("Flushing meta data to %s (%s) failed: %s"), c->name,
logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
c->hostname, strerror(errno));
}
@ -116,13 +116,10 @@ bool flush_meta(connection_t *c)
return true;
}
void broadcast_meta(connection_t *from, const char *buffer, int length)
{
void broadcast_meta(connection_t *from, const char *buffer, int length) {
avl_node_t *node;
connection_t *c;
cp();
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
@ -131,15 +128,12 @@ void broadcast_meta(connection_t *from, const char *buffer, int length)
}
}
bool receive_meta(connection_t *c)
{
bool receive_meta(connection_t *c) {
int oldlen, i, result;
int lenin, lenout, reqlen;
bool decrypted = false;
char inbuf[MAXBUFSIZE];
cp();
/* Strategy:
- Read as much as possible from the TCP socket in one go.
- Decrypt it.
@ -153,12 +147,12 @@ bool receive_meta(connection_t *c)
if(lenin <= 0) {
if(!lenin || !errno) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection closed by %s (%s)"),
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
c->name, c->hostname);
} else if(errno == EINTR)
return true;
else
logger(LOG_ERR, _("Metadata socket read error for %s (%s): %s"),
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
c->name, c->hostname, strerror(errno));
return false;
@ -173,7 +167,7 @@ bool receive_meta(connection_t *c)
if(c->status.decryptin && !decrypted) {
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
if(!result || lenout != lenin) {
logger(LOG_ERR, _("Error while decrypting metadata from %s (%s): %s"),
logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -226,12 +220,10 @@ bool receive_meta(connection_t *c)
}
if(c->buflen >= MAXBUFSIZE) {
logger(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"),
logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
c->name, c->hostname);
return false;
}
c->last_ping_time = now;
return true;
}

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: meta.h 1452 2006-04-26 13:52:58Z guus $
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_META_H__

View file

@ -21,10 +21,9 @@
* 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 (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* 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.
*/
//===============================================

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Windows tap driver in a MinGW environment
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2007 Guus Sliepen <guus@tinc-vpn.org>
2002-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1510 2007-05-16 14:46:25Z guus $
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"
@ -34,74 +32,35 @@
#include "mingw/common.h"
int device_fd = 0;
int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE;
char *device = NULL;
char *iface = NULL;
char *device_info = NULL;
static char *device_info = NULL;
static int device_total_in = 0;
static int device_total_out = 0;
extern char *myport;
static struct packetbuf {
uint8_t data[MTU];
length_t len;
} *bufs;
static int nbufs = 64;
DWORD WINAPI tapreader(void *bla) {
int sock, err, status;
struct addrinfo *ai;
struct addrinfo hint = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = 0,
};
unsigned char bufno = 0;
static DWORD WINAPI tapreader(void *bla) {
int status;
long len;
OVERLAPPED overlapped;
vpn_packet_t packet;
/* Open a socket to the parent process */
err = getaddrinfo(NULL, myport, &hint, &ai);
if(err || !ai) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
return -1;
}
sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
freeaddrinfo(ai);
return -1;
}
if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "connect", strerror(errno));
freeaddrinfo(ai);
return -1;
}
freeaddrinfo(ai);
logger(LOG_DEBUG, _("Tap reader running"));
logger(LOG_DEBUG, "Tap reader running");
/* Read from tap device and send to parent */
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
for(;;) {
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
ResetEvent(overlapped.hEvent);
status = ReadFile(device_handle, bufs[bufno].data, MTU, &len, &overlapped);
status = ReadFile(device_handle, packet.data, MTU, &len, &overlapped);
if(!status) {
if(GetLastError() == ERROR_IO_PENDING) {
@ -109,22 +68,21 @@ DWORD WINAPI tapreader(void *bla) {
if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
continue;
} else {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return -1;
}
}
bufs[bufno].len = len;
if(send(sock, &bufno, 1, 0) <= 0)
return -1;
if(++bufno >= nbufs)
bufno = 0;
EnterCriticalSection(&mutex);
packet.len = len;
packet.priority = 0;
route(myself, &packet);
LeaveCriticalSection(&mutex);
}
}
bool setup_device(void)
{
bool setup_device(void) {
HKEY key, key2;
int i;
@ -148,15 +106,13 @@ bool setup_device(void)
.ai_flags = 0,
};
cp();
get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
/* Open registry and look for network adapters */
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
return false;
}
@ -207,7 +163,7 @@ bool setup_device(void)
RegCloseKey(key);
if(!found) {
logger(LOG_ERR, _("No Windows tap device found!"));
logger(LOG_ERR, "No Windows tap device found!");
return false;
}
@ -225,14 +181,14 @@ bool setup_device(void)
}
if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, _("%s (%s) is not a usable Windows tap device: %s"), device, iface, winerror(GetLastError()));
logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
return false;
}
/* Get MAC address from tap device */
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
return false;
}
@ -240,116 +196,47 @@ bool setup_device(void)
overwrite_mac = 1;
}
/* Set up ringbuffer */
get_config_int(lookup_config(config_tree, "RingBufferSize"), &nbufs);
if(nbufs <= 1)
nbufs = 1;
else if(nbufs > 256)
nbufs = 256;
bufs = xmalloc_and_zero(nbufs * sizeof *bufs);
/* Create a listening socket */
err = getaddrinfo(NULL, myport, &hint, &ai);
if(err || !ai) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
return false;
}
sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
return false;
}
if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "bind", strerror(errno));
return false;
}
freeaddrinfo(ai);
if(listen(sock, 1)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno));
return false;
}
/* Start the tap reader */
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
if(!thread) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "CreateThread", winerror(GetLastError()));
logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
return false;
}
/* Wait for the tap reader to connect back to us */
if((device_fd = accept(sock, NULL, 0)) == -1) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "accept", strerror(errno));
return false;
}
closesocket(sock);
/* Set media status for newer TAP-Win32 devices */
status = true;
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
device_info = _("Windows tap device");
device_info = "Windows tap device";
logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
CloseHandle(device_handle);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
unsigned char bufno;
cp();
if((recv(device_fd, &bufno, 1, 0)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
device, strerror(errno));
return false;
}
packet->len = bufs[bufno].len;
memcpy(packet->data, bufs[bufno].data, bufs[bufno].len);
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
device_info);
return true;
bool read_packet(vpn_packet_t *packet) {
return false;
}
bool write_packet(vpn_packet_t *packet)
{
bool write_packet(vpn_packet_t *packet) {
long lenout;
OVERLAPPED overlapped = {0};
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
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()));
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false;
}
@ -358,11 +245,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

116
src/net.c
View file

@ -1,7 +1,8 @@
/*
net.c -- most of the network code
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2007 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.c 1595 2008-12-22 20:27:52Z guus $
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"
@ -48,16 +47,13 @@ time_t now = 0;
/* Purge edges and subnets of unreachable nodes. Use carefully. */
static void purge(void)
{
static void purge(void) {
avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
node_t *n;
edge_t *e;
subnet_t *s;
cp();
ifdebug(PROTOCOL) logger(LOG_DEBUG, _("Purging unreachable nodes"));
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
/* Remove all edges and subnets owned by unreachable nodes. */
@ -66,7 +62,7 @@ static void purge(void)
n = nnode->data;
if(!n->status.reachable) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Purging node %s (%s)"), n->name,
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
n->hostname);
for(snode = n->subnet_tree->head; snode; snode = snext) {
@ -112,14 +108,11 @@ static void purge(void)
put all file descriptors in an fd_set array
While we're at it, purge stuff that needs to be removed.
*/
static int build_fdset(fd_set *readset, fd_set *writeset)
{
static int build_fdset(fd_set *readset, fd_set *writeset) {
avl_node_t *node, *next;
connection_t *c;
int i, max = 0;
cp();
FD_ZERO(readset);
FD_ZERO(writeset);
@ -149,7 +142,8 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
max = listen_socket[i].udp;
}
FD_SET(device_fd, readset);
if(device_fd >= 0)
FD_SET(device_fd, readset);
if(device_fd > max)
max = device_fd;
@ -163,14 +157,11 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
- Check if we need to retry making an outgoing connection
- Deactivate the host
*/
void terminate_connection(connection_t *c, bool report)
{
cp();
void terminate_connection(connection_t *c, bool report) {
if(c->status.remove)
return;
ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Closing connection with %s (%s)"),
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
c->name, c->hostname);
c->status.remove = true;
@ -227,13 +218,10 @@ void terminate_connection(connection_t *c, bool report)
end does not reply in time, we consider them dead
and close the connection.
*/
static void check_dead_connections(void)
{
static void check_dead_connections(void) {
avl_node_t *node, *next;
connection_t *c;
cp();
for(node = connection_tree->head; node; node = next) {
next = node->next;
c = node->data;
@ -241,7 +229,7 @@ static void check_dead_connections(void)
if(c->last_ping_time + pingtimeout < now) {
if(c->status.active) {
if(c->status.pinged) {
ifdebug(CONNECTIONS) logger(LOG_INFO, _("%s (%s) didn't respond to PING in %ld seconds"),
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
c->name, c->hostname, now - c->last_ping_time);
c->status.timeout = true;
terminate_connection(c, true);
@ -250,12 +238,12 @@ static void check_dead_connections(void)
}
} else {
if(c->status.remove) {
logger(LOG_WARNING, _("Old connection_t for %s (%s) status %04x still lingering, deleting..."),
c->name, c->hostname, c->status.value);
logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status));
connection_del(c);
continue;
}
ifdebug(CONNECTIONS) logger(LOG_WARNING, _("Timeout from %s (%s) during authentication"),
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
c->name, c->hostname);
if(c->status.connecting) {
c->status.connecting = false;
@ -270,7 +258,7 @@ static void check_dead_connections(void)
if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) {
if(c->status.active) {
ifdebug(CONNECTIONS) logger(LOG_INFO,
_("%s (%s) could not flush for %ld seconds (%d bytes remaining)"),
"%s (%s) could not flush for %ld seconds (%d bytes remaining)",
c->name, c->hostname, now - c->last_flushed_time, c->outbuflen);
c->status.timeout = true;
terminate_connection(c, true);
@ -283,20 +271,19 @@ static void check_dead_connections(void)
check all connections to see if anything
happened on their sockets
*/
static void check_network_activity(fd_set * readset, fd_set * writeset)
{
static void check_network_activity(fd_set * readset, fd_set * writeset) {
connection_t *c;
avl_node_t *node;
int result, i;
socklen_t len = sizeof(result);
vpn_packet_t packet;
cp();
/* check input from kernel */
if(FD_ISSET(device_fd, readset)) {
if(read_packet(&packet))
if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
if(read_packet(&packet)) {
packet.priority = 0;
route(myself, &packet);
}
}
/* check meta connections */
@ -315,7 +302,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset)
finish_connecting(c);
else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
_("Error while connecting to %s (%s): %s"),
"Error while connecting to %s (%s): %s",
c->name, c->hostname, strerror(result));
closesocket(c->socket);
do_outgoing_connection(c);
@ -349,16 +336,13 @@ static void check_network_activity(fd_set * readset, fd_set * writeset)
/*
this is where it all happens...
*/
int main_loop(void)
{
int main_loop(void) {
fd_set readset, writeset;
struct timeval tv;
int r, maxfd;
time_t last_ping_check, last_config_check, last_graph_dump;
event_t *event;
cp();
last_ping_check = now;
last_config_check = now;
last_graph_dump = now;
@ -376,13 +360,18 @@ int main_loop(void)
maxfd = build_fdset(&readset, &writeset);
#ifdef HAVE_MINGW
LeaveCriticalSection(&mutex);
#endif
r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
#ifdef HAVE_MINGW
EnterCriticalSection(&mutex);
#endif
if(r < 0) {
if(errno != EINTR && errno != EAGAIN) {
logger(LOG_ERR, _("Error while waiting for input: %s"),
logger(LOG_ERR, "Error while waiting for input: %s",
strerror(errno));
cp_trace();
dump_connections();
return 1;
}
@ -411,28 +400,35 @@ int main_loop(void)
/* Should we regenerate our key? */
if(keyexpires < now) {
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
avl_node_t *node;
node_t *n;
ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
for(node = node_tree->head; node; node = node->next) {
n = node->data;
if(n->inkey) {
free(n->inkey);
n->inkey = NULL;
}
}
RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
if(myself->cipher)
EVP_DecryptInit_ex(&packet_ctx, myself->cipher, NULL, (unsigned char *)myself->key, (unsigned char *)myself->key + myself->cipher->key_len);
send_key_changed(broadcast, myself);
keyexpires = now + keylifetime;
}
}
if(sigalrm) {
logger(LOG_INFO, "Flushing event queue");
expire_events();
sigalrm = false;
}
while((event = get_expired_event())) {
event->handler(event->data);
free_event(event);
}
if(sigalrm) {
logger(LOG_INFO, _("Flushing event queue"));
flush_events();
sigalrm = false;
}
if(sighup) {
connection_t *c;
avl_node_t *node;
@ -447,7 +443,7 @@ int main_loop(void)
init_configuration(&config_tree);
if(!read_server_config()) {
logger(LOG_ERR, _("Unable to reread configuration file, exitting."));
logger(LOG_ERR, "Unable to reread configuration file, exitting.");
return 1;
}
@ -456,15 +452,7 @@ int main_loop(void)
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
if(c->outgoing) {
free(c->outgoing->name);
if(c->outgoing->ai)
freeaddrinfo(c->outgoing->ai);
free(c->outgoing);
c->outgoing = NULL;
}
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
if(stat(fname, &s) || s.st_mtime > last_config_check)
terminate_connection(c, c->status.active);
free(fname);

View file

@ -1,7 +1,7 @@
/*
net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans <zarq@iname.com>
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 1998-2005 Ivo Timmermans
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.h 1452 2006-04-26 13:52:58Z guus $
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_NET_H__
@ -38,8 +36,6 @@
#define MAXSOCKETS 128 /* Overkill... */
#define MAXQUEUELENGTH 8 /* Maximum number of packats in a single queue */
typedef struct mac_t {
uint8_t x[6];
} mac_t;
@ -87,17 +83,6 @@ typedef struct vpn_packet_t {
uint8_t data[MAXSIZE];
} vpn_packet_t;
typedef struct queue_element_t {
void *packet;
struct queue_element_t *prev;
struct queue_element_t *next;
} queue_element_t;
typedef struct packet_queue_t {
queue_element_t *head;
queue_element_t *tail;
} packet_queue_t;
typedef struct listen_socket_t {
int tcp;
int udp;
@ -105,6 +90,7 @@ typedef struct listen_socket_t {
} listen_socket_t;
#include "conf.h"
#include "list.h"
typedef struct outgoing_t {
char *name;
@ -114,6 +100,8 @@ typedef struct outgoing_t {
struct addrinfo *aip;
} outgoing_t;
extern list_t *outgoing_list;
extern int maxoutbufsize;
extern int seconds_till_retry;
extern int addressfamily;
@ -126,7 +114,6 @@ extern bool do_prune;
extern bool do_purge;
extern char *myport;
extern time_t now;
extern EVP_CIPHER_CTX packet_ctx;
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
#include "connection.h"
@ -142,7 +129,7 @@ extern int setup_vpn_in_socket(const sockaddr_t *);
extern void send_packet(const struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, char *, int);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
extern bool setup_network_connections(void);
extern bool setup_network(void);
extern void setup_outgoing_connection(struct outgoing_t *);
extern void try_outgoing_connections(void);
extern void close_network_connections(void);
@ -154,6 +141,8 @@ extern void send_mtu_probe(struct node_t *);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
#else
extern CRITICAL_SECTION mutex;
#endif
#endif /* __TINC_NET_H__ */

View file

@ -1,7 +1,7 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_packet.c 1474 2006-11-29 17:18:39Z guus $
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"
@ -54,69 +52,101 @@
int keylifetime = 0;
int keyexpires = 0;
EVP_CIPHER_CTX packet_ctx;
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
static void send_udppacket(node_t *, vpn_packet_t *);
#define MAX_SEQNO 1073741824
void send_mtu_probe(node_t *n)
{
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
// mtuprobes == 31: sleep pinginterval seconds
// mtuprobes == 32: send 1 burst, sleep pingtimeout second
// mtuprobes == 33: no response from other side, restart PMTU discovery process
void send_mtu_probe(node_t *n) {
vpn_packet_t packet;
int len, i;
int timeout = 1;
cp();
n->mtuprobes++;
n->mtuevent = NULL;
if(n->mtuprobes >= 10 && !n->minmtu) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("No response to MTU probes from %s (%s)"), n->name, n->hostname);
if(!n->status.reachable || !n->status.validkey) {
logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname);
n->mtuprobes = 0;
return;
}
for(i = 0; i < 3; i++) {
if(n->mtuprobes >= 30 || n->minmtu >= n->maxmtu) {
n->mtu = n->minmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Fixing MTU of %s (%s) to %d after %d probes"), n->name, n->hostname, n->mtu, n->mtuprobes);
return;
}
if(n->mtuprobes > 32) {
ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
n->mtuprobes = 1;
n->minmtu = 0;
n->maxmtu = MTU;
}
if(n->mtuprobes >= 10 && !n->minmtu) {
ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
n->mtuprobes = 0;
return;
}
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
n->mtu = n->minmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
n->mtuprobes = 31;
}
if(n->mtuprobes == 31) {
timeout = pinginterval;
goto end;
} else if(n->mtuprobes == 32) {
timeout = pingtimeout;
}
for(i = 0; i < 3; i++) {
if(n->maxmtu <= n->minmtu)
len = n->maxmtu;
else
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
len = n->minmtu + 1 + random() % (n->maxmtu - n->minmtu);
if(len < 64)
len = 64;
memset(packet.data, 0, 14);
RAND_pseudo_bytes(packet.data + 14, len - 14);
packet.len = len;
packet.priority = 0;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname);
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
send_udppacket(n, &packet);
}
end:
n->mtuevent = new_event();
n->mtuevent->handler = (event_handler_t)send_mtu_probe;
n->mtuevent->data = n;
n->mtuevent->time = now + 1;
n->mtuevent->time = now + timeout;
event_add(n->mtuevent);
}
void mtu_probe_h(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Got MTU probe length %d from %s (%s)"), packet->len, n->name, n->hostname);
void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
if(!packet->data[0]) {
packet->data[0] = 1;
send_packet(n, packet);
} else {
if(n->minmtu < packet->len)
n->minmtu = packet->len;
if(len > n->maxmtu)
len = n->maxmtu;
if(n->minmtu < len)
n->minmtu = len;
if(n->mtuprobes > 30)
n->mtuprobes = 30;
}
}
static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
{
static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
if(level == 10) {
lzo_uint lzolen = MAXSIZE;
lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
@ -136,8 +166,7 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l
return -1;
}
static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
{
static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
if(level > 9) {
lzo_uint lzolen = MAXSIZE;
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK)
@ -157,18 +186,25 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
/* VPN packet I/O */
static void receive_packet(node_t *n, vpn_packet_t *packet)
{
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"),
static void receive_packet(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
packet->len, n->name, n->hostname);
route(n, packet);
}
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
{
static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) {
unsigned char hmac[EVP_MAX_MD_SIZE];
if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
return false;
HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
return !memcmp(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
}
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;
@ -177,25 +213,29 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
unsigned char hmac[EVP_MAX_MD_SIZE];
int i;
cp();
if(!n->inkey) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
n->name, n->hostname);
return;
}
/* Check packet length */
if(inpkt->len < sizeof(inpkt->seqno) + myself->maclength) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname);
return;
}
/* Check the message authentication code */
if(myself->digest && myself->maclength) {
inpkt->len -= myself->maclength;
HMAC(myself->digest, myself->key, myself->keylength,
if(n->indigest && n->inmaclength) {
inpkt->len -= n->inmaclength;
HMAC(n->indigest, n->inkey, n->inkeylength,
(unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, myself->maclength)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)",
n->name, n->hostname);
return;
}
@ -203,14 +243,14 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
/* Decrypt the packet */
if(myself->cipher) {
if(n->incipher) {
outpkt = pkt[nextpkt++];
if(!EVP_DecryptInit_ex(&packet_ctx, NULL, NULL, NULL, NULL)
|| !EVP_DecryptUpdate(&packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
if(!EVP_DecryptInit_ex(&n->inctx, NULL, NULL, NULL, NULL)
|| !EVP_DecryptUpdate(&n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_DecryptFinal_ex(&packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s): %s"),
|| !EVP_DecryptFinal_ex(&n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
return;
}
@ -226,13 +266,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
if(inpkt->seqno != n->received_seqno + 1) {
if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) {
logger(LOG_WARNING, _("Lost %d packets from %s (%s)"),
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, sizeof(n->late));
} else if (inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= sizeof(n->late) * 8 && inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8) || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) {
logger(LOG_WARNING, _("Got late or replayed packet from %s (%s), seqno %d, last received %d"),
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
return;
}
@ -252,41 +292,44 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
/* Decompress the packet */
if(myself->compression) {
length_t origlen = inpkt->len;
if(n->incompression) {
outpkt = pkt[nextpkt++];
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, myself->compression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while uncompressing packet from %s (%s)"),
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname);
return;
}
inpkt = outpkt;
origlen -= MTU/64 + 20;
}
if(n->connection)
n->connection->last_ping_time = now;
inpkt->priority = 0;
if(!inpkt->data[12] && !inpkt->data[13])
mtu_probe_h(n, inpkt);
mtu_probe_h(n, inpkt, origlen);
else
receive_packet(n, inpkt);
}
void receive_tcppacket(connection_t *c, char *buffer, int len)
{
void receive_tcppacket(connection_t *c, char *buffer, int len) {
vpn_packet_t outpkt;
cp();
outpkt.len = len;
if(c->options & OPTION_TCPONLY)
outpkt.priority = 0;
else
outpkt.priority = -1;
memcpy(outpkt.data, buffer, len);
receive_packet(c->node, &outpkt);
}
static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
{
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
vpn_packet_t *inpkt = origpkt;
@ -294,34 +337,39 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
vpn_packet_t *outpkt;
int origlen;
int outlen, outpad;
vpn_packet_t *copy;
static int priority = 0;
int origpriority;
int sock;
cp();
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
return;
}
/* Make sure we have a valid key */
if(!n->status.validkey) {
ifdebug(TRAFFIC) logger(LOG_INFO,
_("No valid key known yet for %s (%s), queueing packet"),
"No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname);
/* Since packet is on the stack of handle_tap_input(), we have to make a copy of it first. */
*(copy = xmalloc(sizeof(*copy))) = *inpkt;
list_insert_tail(n->queue, copy);
if(n->queue->count > MAXQUEUELENGTH)
list_delete_head(n->queue);
if(!n->status.waitingforkey)
send_req_key(n->nexthop->connection, myself, n);
send_req_key(n);
n->status.waitingforkey = true;
send_tcppacket(n->nexthop->connection, origpkt);
return;
}
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
ifdebug(TRAFFIC) logger(LOG_INFO,
"Packet for %s (%s) larger than minimum MTU, forwarding via TCP",
n->name, n->hostname);
send_tcppacket(n->nexthop->connection, origpkt);
return;
}
@ -330,11 +378,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
/* Compress the packet */
if(n->compression) {
if(n->outcompression) {
outpkt = pkt[nextpkt++];
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->compression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while compressing packet to %s (%s)"),
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
n->name, n->hostname);
return;
}
@ -349,14 +397,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
/* Encrypt the packet */
if(n->cipher) {
if(n->outcipher) {
outpkt = pkt[nextpkt++];
if(!EVP_EncryptInit_ex(&n->packet_ctx, NULL, NULL, NULL, NULL)
|| !EVP_EncryptUpdate(&n->packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
if(!EVP_EncryptInit_ex(&n->outctx, NULL, NULL, NULL, NULL)
|| !EVP_EncryptUpdate(&n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_EncryptFinal_ex(&n->packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s): %s"),
|| !EVP_EncryptFinal_ex(&n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
goto end;
}
@ -367,10 +415,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
/* Add the message authentication code */
if(n->digest && n->maclength) {
HMAC(n->digest, n->key, n->keylength, (unsigned char *) &inpkt->seqno,
if(n->outdigest && n->outmaclength) {
HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
inpkt->len += n->maclength;
inpkt->len += n->outmaclength;
}
/* Determine which socket we have to use */
@ -388,9 +436,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
if(priorityinheritance && origpriority != priority
&& listen_socket[sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Setting outgoing packet priority to %d"), priority);
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, _("System call `%s' failed: %s"), "setsockopt", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
#endif
@ -401,7 +449,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
if(n->mtu >= origlen)
n->mtu = origlen - 1;
} else
logger(LOG_ERR, _("Error sending packet to %s (%s): %s"), n->name, n->hostname, strerror(errno));
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, strerror(errno));
}
end:
@ -411,12 +459,9 @@ end:
/*
send a packet to the given vpn ip.
*/
void send_packet(const node_t *n, vpn_packet_t *packet)
{
void send_packet(const node_t *n, vpn_packet_t *packet) {
node_t *via;
cp();
if(n == myself) {
if(overwrite_mac)
memcpy(packet->data, mymac.x, ETH_ALEN);
@ -424,22 +469,22 @@ void send_packet(const node_t *n, vpn_packet_t *packet)
return;
}
ifdebug(TRAFFIC) logger(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
packet->len, n->name, n->hostname);
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Node %s (%s) is not reachable"),
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
n->name, n->hostname);
return;
}
via = (n->via == myself) ? n->nexthop : n->via;
via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
if(via != n)
ifdebug(TRAFFIC) logger(LOG_ERR, _("Sending packet to %s via %s (%s)"),
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
n->name, via->name, n->via->hostname);
if((myself->options | via->options) & OPTION_TCPONLY) {
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
if(!send_tcppacket(via->connection, packet))
terminate_connection(via->connection, true);
} else
@ -448,19 +493,22 @@ void send_packet(const node_t *n, vpn_packet_t *packet)
/* Broadcast a packet using the minimum spanning tree */
void broadcast_packet(const node_t *from, vpn_packet_t *packet)
{
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
avl_node_t *node;
connection_t *c;
cp();
ifdebug(TRAFFIC) logger(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
if(from != myself)
if(from != myself) {
send_packet(myself, packet);
// In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops.
if(tunnelserver)
return;
}
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
@ -469,35 +517,42 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet)
}
}
void flush_queue(node_t *n)
{
list_node_t *node, *next;
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
avl_node_t *node;
edge_t *e;
node_t *n = NULL;
cp();
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Flushing queue for %s (%s)"), n->name, n->hostname);
if(sockaddrcmp_noport(from, &e->address))
continue;
for(node = n->queue->head; node; node = next) {
next = node->next;
send_udppacket(n, node->data);
list_delete_node(n->queue, node);
if(!n)
n = e->to;
if(!try_mac(e->to, pkt))
continue;
n = e->to;
break;
}
return n;
}
void handle_incoming_vpn_data(int sock)
{
void handle_incoming_vpn_data(int sock) {
vpn_packet_t pkt;
char *hostname;
sockaddr_t from;
socklen_t fromlen = sizeof(from);
node_t *n;
cp();
pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
if(pkt.len < 0) {
logger(LOG_ERR, _("Receiving packet failed: %s"), strerror(errno));
if(errno != EAGAIN && errno != EINTR)
logger(LOG_ERR, "Receiving packet failed: %s", strerror(errno));
return;
}
@ -506,11 +561,17 @@ void handle_incoming_vpn_data(int sock)
n = lookup_node_udp(&from);
if(!n) {
hostname = sockaddr2hostname(&from);
logger(LOG_WARNING, _("Received UDP packet from unknown source %s"),
hostname);
free(hostname);
return;
n = try_harder(&from, &pkt);
if(n)
update_node_udp(n, &from);
else ifdebug(PROTOCOL) {
hostname = sockaddr2hostname(&from);
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
return;
}
else
return;
}
receive_udppacket(n, &pkt);

View file

@ -1,7 +1,8 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_setup.c 1596 2008-12-22 20:35:45Z guus $
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"
@ -46,14 +45,11 @@
char *myport;
bool read_rsa_public_key(connection_t *c)
{
bool read_rsa_public_key(connection_t *c) {
FILE *fp;
char *fname;
char *key;
cp();
if(!c->rsa_key) {
c->rsa_key = RSA_new();
// RSA_blinding_on(c->rsa_key, NULL);
@ -74,7 +70,7 @@ bool read_rsa_public_key(connection_t *c)
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
fname, strerror(errno));
free(fname);
return false;
@ -91,7 +87,7 @@ bool read_rsa_public_key(connection_t *c)
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
fname, strerror(errno));
free(fname);
return false;
@ -106,14 +102,14 @@ bool read_rsa_public_key(connection_t *c)
return true;
}
logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"),
logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s",
fname, strerror(errno));
return false;
}
/* Else, check if a harnessed public key is in the config file */
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
fp = fopen(fname, "r");
if(fp) {
@ -128,7 +124,7 @@ bool read_rsa_public_key(connection_t *c)
/* Try again with PEM_read_RSA_PUBKEY. */
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
fp = fopen(fname, "r");
if(fp) {
@ -142,22 +138,19 @@ bool read_rsa_public_key(connection_t *c)
if(c->rsa_key)
return true;
logger(LOG_ERR, _("No public key for %s specified!"), c->name);
logger(LOG_ERR, "No public key for %s specified!", c->name);
return false;
}
bool read_rsa_private_key(void)
{
bool read_rsa_private_key(void) {
FILE *fp;
char *fname, *key, *pubkey;
struct stat s;
cp();
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) {
logger(LOG_ERR, _("PrivateKey used but no PublicKey found!"));
logger(LOG_ERR, "PrivateKey used but no PublicKey found!");
return false;
}
myself->connection->rsa_key = RSA_new();
@ -171,12 +164,12 @@ bool read_rsa_private_key(void)
}
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
asprintf(&fname, "%s/rsa_key.priv", confbase);
xasprintf(&fname, "%s/rsa_key.priv", confbase);
fp = fopen(fname, "r");
if(!fp) {
logger(LOG_ERR, _("Error reading RSA private key file `%s': %s"),
logger(LOG_ERR, "Error reading RSA private key file `%s': %s",
fname, strerror(errno));
free(fname);
return false;
@ -184,21 +177,21 @@ bool read_rsa_private_key(void)
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
if(fstat(fileno(fp), &s)) {
logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"),
logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'",
fname, strerror(errno));
free(fname);
return false;
}
if(s.st_mode & ~0100700)
logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
#endif
myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if(!myself->connection->rsa_key) {
logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"),
logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s",
fname, strerror(errno));
free(fname);
return false;
@ -211,8 +204,7 @@ bool read_rsa_private_key(void)
/*
Configure node_t myself and set up the local sockets (listen only)
*/
bool setup_myself(void)
{
bool setup_myself(void) {
config_t *cfg;
subnet_t *subnet;
char *name, *hostname, *mode, *afname, *cipher, *digest;
@ -222,25 +214,23 @@ bool setup_myself(void)
bool choice;
int i, err;
cp();
myself = new_node();
myself->connection = new_connection();
init_configuration(&myself->connection->config_tree);
asprintf(&myself->hostname, _("MYSELF"));
asprintf(&myself->connection->hostname, _("MYSELF"));
xasprintf(&myself->hostname, "MYSELF");
xasprintf(&myself->connection->hostname, "MYSELF");
myself->connection->options = 0;
myself->connection->protocol_version = PROT_CURRENT;
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */
logger(LOG_ERR, _("Name for tinc daemon required!"));
logger(LOG_ERR, "Name for tinc daemon required!");
return false;
}
if(!check_id(name)) {
logger(LOG_ERR, _("Invalid name for myself!"));
logger(LOG_ERR, "Invalid name for myself!");
free(name);
return false;
}
@ -249,7 +239,7 @@ bool setup_myself(void)
myself->connection->name = xstrdup(name);
if(!read_connection_config(myself->connection)) {
logger(LOG_ERR, _("Cannot open host configuration file for myself!"));
logger(LOG_ERR, "Cannot open host configuration file for myself!");
return false;
}
@ -257,7 +247,7 @@ bool setup_myself(void)
return false;
if(!get_config_string(lookup_config(myself->connection->config_tree, "Port"), &myport))
asprintf(&myport, "655");
xasprintf(&myport, "655");
/* Read in all the subnets specified in the host configuration file */
@ -286,9 +276,6 @@ bool setup_myself(void)
if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice) && choice)
myself->options |= OPTION_TCPONLY;
if(!get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice) || choice)
myself->options |= OPTION_PMTU_DISCOVERY;
if(myself->options & OPTION_TCPONLY)
myself->options |= OPTION_INDIRECT;
@ -302,18 +289,25 @@ bool setup_myself(void)
else if(!strcasecmp(mode, "hub"))
routing_mode = RMODE_HUB;
else {
logger(LOG_ERR, _("Invalid routing mode!"));
logger(LOG_ERR, "Invalid routing mode!");
return false;
}
free(mode);
} else
routing_mode = RMODE_ROUTER;
// Enable PMTUDiscovery by default if we are in router mode.
choice = routing_mode == RMODE_ROUTER;
get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice);
if(choice)
myself->options |= OPTION_PMTU_DISCOVERY;
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
#if !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance)
logger(LOG_WARNING, _("PriorityInheritance not supported on this platform"));
logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
#endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
@ -321,7 +315,7 @@ bool setup_myself(void)
if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
if(maxtimeout <= 0) {
logger(LOG_ERR, _("Bogus maximum timeout!"));
logger(LOG_ERR, "Bogus maximum timeout!");
return false;
}
} else
@ -335,7 +329,7 @@ bool setup_myself(void)
else if(!strcasecmp(afname, "any"))
addressfamily = AF_UNSPEC;
else {
logger(LOG_ERR, _("Invalid address family!"));
logger(LOG_ERR, "Invalid address family!");
return false;
}
free(afname);
@ -348,88 +342,72 @@ bool setup_myself(void)
if(get_config_string
(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
if(!strcasecmp(cipher, "none")) {
myself->cipher = NULL;
myself->incipher = NULL;
} else {
myself->cipher = EVP_get_cipherbyname(cipher);
myself->incipher = EVP_get_cipherbyname(cipher);
if(!myself->cipher) {
logger(LOG_ERR, _("Unrecognized cipher type!"));
if(!myself->incipher) {
logger(LOG_ERR, "Unrecognized cipher type!");
return false;
}
}
} else
myself->cipher = EVP_bf_cbc();
myself->incipher = EVP_bf_cbc();
if(myself->cipher)
myself->keylength = myself->cipher->key_len + myself->cipher->iv_len;
if(myself->incipher)
myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
else
myself->keylength = 1;
myself->inkeylength = 1;
myself->connection->outcipher = EVP_bf_ofb();
myself->key = xmalloc(myself->keylength);
RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600;
keyexpires = now + keylifetime;
if(myself->cipher) {
EVP_CIPHER_CTX_init(&packet_ctx);
if(!EVP_DecryptInit_ex(&packet_ctx, myself->cipher, NULL, (unsigned char *)myself->key, (unsigned char *)myself->key + myself->cipher->key_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
myself->name, myself->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
}
/* Check if we want to use message authentication codes... */
if(get_config_string
(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
if(!strcasecmp(digest, "none")) {
myself->digest = NULL;
myself->indigest = NULL;
} else {
myself->digest = EVP_get_digestbyname(digest);
myself->indigest = EVP_get_digestbyname(digest);
if(!myself->digest) {
logger(LOG_ERR, _("Unrecognized digest type!"));
if(!myself->indigest) {
logger(LOG_ERR, "Unrecognized digest type!");
return false;
}
}
} else
myself->digest = EVP_sha1();
myself->indigest = EVP_sha1();
myself->connection->outdigest = EVP_sha1();
if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"),
&myself->maclength)) {
if(myself->digest) {
if(myself->maclength > myself->digest->md_size) {
logger(LOG_ERR, _("MAC length exceeds size of digest!"));
if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength)) {
if(myself->indigest) {
if(myself->inmaclength > myself->indigest->md_size) {
logger(LOG_ERR, "MAC length exceeds size of digest!");
return false;
} else if(myself->maclength < 0) {
logger(LOG_ERR, _("Bogus MAC length!"));
} else if(myself->inmaclength < 0) {
logger(LOG_ERR, "Bogus MAC length!");
return false;
}
}
} else
myself->maclength = 4;
myself->inmaclength = 4;
myself->connection->outmaclength = 0;
/* Compression */
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"),
&myself->compression)) {
if(myself->compression < 0 || myself->compression > 11) {
logger(LOG_ERR, _("Bogus compression level!"));
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->incompression)) {
if(myself->incompression < 0 || myself->incompression > 11) {
logger(LOG_ERR, "Bogus compression level!");
return false;
}
} else
myself->compression = 0;
myself->incompression = 0;
myself->connection->outcompression = 0;
@ -448,10 +426,10 @@ bool setup_myself(void)
return false;
/* Run tinc-up script to further initialize the tap interface */
asprintf(&envp[0], "NETNAME=%s", netname ? : "");
asprintf(&envp[1], "DEVICE=%s", device ? : "");
asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
asprintf(&envp[3], "NAME=%s", myself->name);
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
xasprintf(&envp[3], "NAME=%s", myself->name);
envp[4] = NULL;
execute_script("tinc-up", envp);
@ -475,7 +453,7 @@ bool setup_myself(void)
err = getaddrinfo(address, myport, &hint, &ai);
if(err || !ai) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo",
logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
gai_strerror(err));
return false;
}
@ -497,7 +475,7 @@ bool setup_myself(void)
ifdebug(CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
logger(LOG_NOTICE, _("Listening on %s"), hostname);
logger(LOG_NOTICE, "Listening on %s", hostname);
free(hostname);
}
@ -508,9 +486,9 @@ bool setup_myself(void)
freeaddrinfo(ai);
if(listen_sockets)
logger(LOG_NOTICE, _("Ready"));
logger(LOG_NOTICE, "Ready");
else {
logger(LOG_ERR, _("Unable to create any listening socket!"));
logger(LOG_ERR, "Unable to create any listening socket!");
return false;
}
@ -518,12 +496,9 @@ bool setup_myself(void)
}
/*
setup all initial network connections
initialize network
*/
bool setup_network_connections(void)
{
cp();
bool setup_network(void) {
now = time(NULL);
init_events();
@ -546,46 +521,36 @@ bool setup_network_connections(void)
pingtimeout = pinginterval;
if(!get_config_int(lookup_config(config_tree, "MaxOutputBufferSize"), &maxoutbufsize))
maxoutbufsize = 4 * MTU;
maxoutbufsize = 10 * MTU;
if(!setup_myself())
return false;
try_outgoing_connections();
return true;
}
/*
close all open network connections
*/
void close_network_connections(void)
{
void close_network_connections(void) {
avl_node_t *node, *next;
connection_t *c;
char *envp[5];
int i;
cp();
for(node = connection_tree->head; node; node = next) {
next = node->next;
c = node->data;
if(c->outgoing) {
if(c->outgoing->ai)
freeaddrinfo(c->outgoing->ai);
free(c->outgoing->name);
free(c->outgoing);
c->outgoing = NULL;
}
c->outgoing = false;
terminate_connection(c, false);
}
list_delete_list(outgoing_list);
if(myself && myself->connection) {
subnet_update(myself, NULL, false);
terminate_connection(myself->connection, false);
free_connection(myself->connection);
}
for(i = 0; i < listen_sockets; i++) {
@ -593,10 +558,10 @@ void close_network_connections(void)
close(listen_socket[i].udp);
}
asprintf(&envp[0], "NETNAME=%s", netname ? : "");
asprintf(&envp[1], "DEVICE=%s", device ? : "");
asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
asprintf(&envp[3], "NAME=%s", myself->name);
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
xasprintf(&envp[3], "NAME=%s", myself->name);
envp[4] = NULL;
exit_requests();
@ -608,6 +573,8 @@ void close_network_connections(void)
execute_script("tinc-down", envp);
if(myport) free(myport);
for(i = 0; i < 4; i++)
free(envp[i]);

View file

@ -1,7 +1,9 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
2009 Florian Forster <octo@verplant.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
@ -13,11 +15,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_socket.c 1596 2008-12-22 20:35:45Z guus $
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"
@ -34,6 +34,8 @@
#include "utils.h"
#include "xalloc.h"
#include <assert.h>
#ifdef WSAEINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
#endif
@ -49,24 +51,24 @@ int seconds_till_retry = 5;
listen_socket_t listen_socket[MAXSOCKETS];
int listen_sockets;
list_t *outgoing_list = NULL;
/* Setup sockets */
static void configure_tcp(connection_t *c)
{
static void configure_tcp(connection_t *c) {
int option;
#ifdef O_NONBLOCK
int flags = fcntl(c->socket, F_GETFL);
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
logger(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno));
logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
}
#elif defined(WIN32)
unsigned long arg = 1;
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
logger(LOG_ERR, _("ioctlsocket for %s: WSA error %d"), c->hostname, WSAGetLastError());
logger(LOG_ERR, "ioctlsocket for %s: WSA error %d", c->hostname, WSAGetLastError());
}
#endif
@ -81,19 +83,103 @@ static void configure_tcp(connection_t *c)
#endif
}
int setup_listen_socket(const sockaddr_t *sa)
{
static bool bind_to_interface(int sd) {
char *iface;
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
struct ifreq ifr;
int status;
#endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */
if(!get_config_string (lookup_config (config_tree, "BindToInterface"), &iface))
return true;
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = 0;
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
if(status) {
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
strerror(errno));
return false;
}
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
#endif
return true;
}
static bool bind_to_address(connection_t *c) {
char *node;
struct addrinfo *ai_list;
struct addrinfo *ai_ptr;
struct addrinfo ai_hints;
int status;
assert(c != NULL);
assert(c->socket >= 0);
node = NULL;
if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
&node))
return true;
assert(node != NULL);
memset(&ai_hints, 0, sizeof(ai_hints));
ai_hints.ai_family = c->address.sa.sa_family;
/* We're called from `do_outgoing_connection' only. */
ai_hints.ai_socktype = SOCK_STREAM;
ai_hints.ai_protocol = IPPROTO_TCP;
ai_list = NULL;
status = getaddrinfo(node, /* service = */ NULL,
&ai_hints, &ai_list);
if(status) {
free(node);
logger(LOG_WARNING, "Error looking up %s port %s: %s",
node, "any", gai_strerror(status));
return false;
}
assert(ai_list != NULL);
status = -1;
for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
status = bind(c->socket,
ai_list->ai_addr, ai_list->ai_addrlen);
if(!status)
break;
}
if(status) {
logger(LOG_ERR, "Can't bind to %s/tcp: %s", node,
strerror(errno));
} else ifdebug(CONNECTIONS) {
logger(LOG_DEBUG, "Successfully bound outgoing "
"TCP socket to %s", node);
}
free(node);
freeaddrinfo(ai_list);
return status ? false : true;
}
int setup_listen_socket(const sockaddr_t *sa) {
int nfd;
char *addrstr;
int option;
char *iface;
cp();
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(nfd < 0) {
ifdebug(STATUS) logger(LOG_ERR, _("Creating metasocket failed: %s"), strerror(errno));
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", strerror(errno));
return -1;
}
@ -117,19 +203,19 @@ int setup_listen_socket(const sockaddr_t *sa)
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
closesocket(nfd);
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
strerror(errno));
return -1;
}
#else
logger(LOG_WARNING, _("BindToInterface not supported on this platform"));
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
#endif
}
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd);
addrstr = sockaddr2hostname(sa);
logger(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr,
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr,
strerror(errno));
free(addrstr);
return -1;
@ -137,7 +223,7 @@ int setup_listen_socket(const sockaddr_t *sa)
if(listen(nfd, 3)) {
closesocket(nfd);
logger(LOG_ERR, _("System call `%s' failed: %s"), "listen",
logger(LOG_ERR, "System call `%s' failed: %s", "listen",
strerror(errno));
return -1;
}
@ -145,18 +231,15 @@ int setup_listen_socket(const sockaddr_t *sa)
return nfd;
}
int setup_vpn_in_socket(const sockaddr_t *sa)
{
int setup_vpn_in_socket(const sockaddr_t *sa) {
int nfd;
char *addrstr;
int option;
cp();
nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
if(nfd < 0) {
logger(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno));
logger(LOG_ERR, "Creating UDP socket failed: %s", strerror(errno));
return -1;
}
@ -166,7 +249,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno));
return -1;
}
@ -176,7 +259,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
unsigned long arg = 1;
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
closesocket(nfd);
logger(LOG_ERR, _("Call to `%s' failed: WSA error %d"), "ioctlsocket",
logger(LOG_ERR, "Call to `%s' failed: WSA error %d", "ioctlsocket",
WSAGetLastError());
return -1;
}
@ -192,64 +275,39 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
#endif
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
{
bool choice;
if(!get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice) || choice) {
option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option));
}
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option));
}
#endif
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
{
bool choice;
if(!get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice) || choice) {
option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, &option, sizeof(option));
}
if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, &option, sizeof(option));
}
#endif
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
{
char *iface;
struct ifreq ifr;
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
closesocket(nfd);
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
strerror(errno));
return -1;
}
}
if (!bind_to_interface(nfd)) {
closesocket(nfd);
return -1;
}
#endif
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
closesocket(nfd);
addrstr = sockaddr2hostname(sa);
logger(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr,
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr,
strerror(errno));
free(addrstr);
return -1;
}
return nfd;
}
} /* int setup_vpn_in_socket */
void retry_outgoing(outgoing_t *outgoing)
{
void retry_outgoing(outgoing_t *outgoing) {
event_t *event;
cp();
outgoing->timeout += 5;
if(outgoing->timeout > maxtimeout)
@ -262,15 +320,12 @@ void retry_outgoing(outgoing_t *outgoing)
event_add(event);
ifdebug(CONNECTIONS) logger(LOG_NOTICE,
_("Trying to re-establish outgoing connection in %d seconds"),
"Trying to re-establish outgoing connection in %d seconds",
outgoing->timeout);
}
void finish_connecting(connection_t *c)
{
cp();
ifdebug(CONNECTIONS) logger(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
void finish_connecting(connection_t *c) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
configure_tcp(c);
@ -279,17 +334,14 @@ void finish_connecting(connection_t *c)
send_id(c);
}
void do_outgoing_connection(connection_t *c)
{
void do_outgoing_connection(connection_t *c) {
char *address, *port;
int result;
cp();
begin:
if(!c->outgoing->ai) {
if(!c->outgoing->cfg) {
ifdebug(CONNECTIONS) logger(LOG_ERR, _("Could not set up a meta connection to %s"),
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
c->name);
c->status.remove = true;
retry_outgoing(c->outgoing);
@ -299,7 +351,7 @@ begin:
get_config_string(c->outgoing->cfg, &address);
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
asprintf(&port, "655");
xasprintf(&port, "655");
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
free(address);
@ -324,13 +376,13 @@ begin:
c->hostname = sockaddr2hostname(&c->address);
ifdebug(CONNECTIONS) logger(LOG_INFO, _("Trying to connect to %s (%s)"), c->name,
ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
c->hostname);
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(c->socket == -1) {
ifdebug(CONNECTIONS) logger(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname,
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname,
strerror(errno));
goto begin;
@ -342,6 +394,9 @@ begin:
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, &option, sizeof option);
#endif
bind_to_interface(c->socket);
bind_to_address(c);
/* Optimize TCP settings */
configure_tcp(c);
@ -362,7 +417,7 @@ begin:
closesocket(c->socket);
ifdebug(CONNECTIONS) logger(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, strerror(errno));
goto begin;
}
@ -372,18 +427,15 @@ begin:
return;
}
void setup_outgoing_connection(outgoing_t *outgoing)
{
void setup_outgoing_connection(outgoing_t *outgoing) {
connection_t *c;
node_t *n;
cp();
n = lookup_node(outgoing->name);
if(n)
if(n->connection) {
ifdebug(CONNECTIONS) logger(LOG_INFO, _("Already connected to %s"), outgoing->name);
ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);
n->connection->outgoing = outgoing;
return;
@ -402,10 +454,8 @@ void setup_outgoing_connection(outgoing_t *outgoing)
outgoing->cfg = lookup_config(c->config_tree, "Address");
if(!outgoing->cfg) {
logger(LOG_ERR, _("No address specified for %s"), c->name);
logger(LOG_ERR, "No address specified for %s", c->name);
free_connection(c);
free(outgoing->name);
free(outgoing);
return;
}
@ -421,19 +471,16 @@ void setup_outgoing_connection(outgoing_t *outgoing)
accept a new tcp connect and create a
new connection
*/
bool handle_new_meta_connection(int sock)
{
bool handle_new_meta_connection(int sock) {
connection_t *c;
sockaddr_t sa;
int fd;
socklen_t len = sizeof(sa);
cp();
fd = accept(sock, &sa.sa, &len);
if(fd < 0) {
logger(LOG_ERR, _("Accepting a new connection failed: %s"),
logger(LOG_ERR, "Accepting a new connection failed: %s",
strerror(errno));
return false;
}
@ -452,7 +499,7 @@ bool handle_new_meta_connection(int sock)
c->socket = fd;
c->last_ping_time = now;
ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname);
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname);
configure_tcp(c);
@ -464,20 +511,40 @@ bool handle_new_meta_connection(int sock)
return true;
}
void try_outgoing_connections(void)
{
void free_outgoing(outgoing_t *outgoing) {
if(outgoing->ai)
freeaddrinfo(outgoing->ai);
if(outgoing->name)
free(outgoing->name);
free(outgoing);
}
void try_outgoing_connections(void) {
static config_t *cfg = NULL;
char *name;
outgoing_t *outgoing;
connection_t *c;
avl_node_t *node;
if(outgoing_list) {
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
c->outgoing = NULL;
}
cp();
list_delete_list(outgoing_list);
}
outgoing_list = list_alloc((list_action_t)free_outgoing);
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
get_config_string(cfg, &name);
if(!check_id(name)) {
logger(LOG_ERR,
_("Invalid name for outgoing connection in %s line %d"),
"Invalid name for outgoing connection in %s line %d",
cfg->file, cfg->line);
free(name);
continue;
@ -485,6 +552,7 @@ void try_outgoing_connections(void)
outgoing = xmalloc_and_zero(sizeof(*outgoing));
outgoing->name = name;
list_insert_tail(outgoing_list, outgoing);
setup_outgoing_connection(outgoing);
}
}

View file

@ -1,7 +1,7 @@
/*
netutl.c -- some supporting network utility code
Copyright (C) 1998-2005 Ivo Timmermans
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.c 1459 2006-08-08 13:44:37Z guus $
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"
@ -34,20 +32,17 @@ bool hostnames = false;
Turn a string into a struct addrinfo.
Return NULL on failure.
*/
struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype)
{
struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) {
struct addrinfo *ai, hint = {0};
int err;
cp();
hint.ai_family = addressfamily;
hint.ai_socktype = socktype;
err = getaddrinfo(address, service, &hint, &ai);
if(err) {
logger(LOG_WARNING, _("Error looking up %s port %s: %s"), address,
logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
service, gai_strerror(err));
return NULL;
}
@ -55,14 +50,11 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
return ai;
}
sockaddr_t str2sockaddr(const char *address, const char *port)
{
sockaddr_t str2sockaddr(const char *address, const char *port) {
struct addrinfo *ai, hint = {0};
sockaddr_t result;
int err;
cp();
hint.ai_family = AF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
hint.ai_socktype = SOCK_STREAM;
@ -84,15 +76,12 @@ sockaddr_t str2sockaddr(const char *address, const char *port)
return result;
}
void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
{
void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
char address[NI_MAXHOST];
char port[NI_MAXSERV];
char *scopeid;
int err;
cp();
if(sa->sa.sa_family == AF_UNKNOWN) {
*addrstr = xstrdup(sa->unknown.address);
*portstr = xstrdup(sa->unknown.port);
@ -102,9 +91,8 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
if(err) {
logger(LOG_ERR, _("Error while translating addresses: %s"),
logger(LOG_ERR, "Error while translating addresses: %s",
gai_strerror(err));
cp_trace();
raise(SIGFPE);
exit(0);
}
@ -118,37 +106,60 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr)
*portstr = xstrdup(port);
}
char *sockaddr2hostname(const sockaddr_t *sa)
{
char *sockaddr2hostname(const sockaddr_t *sa) {
char *str;
char address[NI_MAXHOST] = "unknown";
char port[NI_MAXSERV] = "unknown";
int err;
cp();
if(sa->sa.sa_family == AF_UNKNOWN) {
asprintf(&str, _("%s port %s"), sa->unknown.address, sa->unknown.port);
xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port);
return str;
}
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
if(err) {
logger(LOG_ERR, _("Error while looking up hostname: %s"),
logger(LOG_ERR, "Error while looking up hostname: %s",
gai_strerror(err));
}
asprintf(&str, _("%s port %s"), address, port);
xasprintf(&str, "%s port %s", address, port);
return str;
}
int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
{
int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
int result;
cp();
result = a->sa.sa_family - b->sa.sa_family;
if(result)
return result;
switch (a->sa.sa_family) {
case AF_UNSPEC:
return 0;
case AF_UNKNOWN:
return strcmp(a->unknown.address, b->unknown.address);
case AF_INET:
return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
case AF_INET6:
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
default:
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family);
raise(SIGFPE);
exit(0);
}
}
int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
int result;
result = a->sa.sa_family - b->sa.sa_family;
@ -184,17 +195,14 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
default:
logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family);
cp_trace();
raise(SIGFPE);
exit(0);
}
}
void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
cp();
if(b->sa.sa_family != AF_UNKNOWN) {
*a = *b;
} else {
@ -205,18 +213,13 @@ void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
}
void sockaddrfree(sockaddr_t *a) {
cp();
if(a->sa.sa_family == AF_UNKNOWN) {
free(a->unknown.address);
free(a->unknown.port);
}
}
void sockaddrunmap(sockaddr_t *sa)
{
cp();
void sockaddrunmap(sockaddr_t *sa) {
if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
sa->in.sin_family = AF_INET;
@ -225,14 +228,11 @@ void sockaddrunmap(sockaddr_t *sa)
/* Subnet mask handling */
int maskcmp(const void *va, const void *vb, int masklen)
{
int maskcmp(const void *va, const void *vb, int masklen) {
int i, m, result;
const char *a = va;
const char *b = vb;
cp();
for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
result = a[i] - b[i];
if(result)
@ -246,13 +246,10 @@ int maskcmp(const void *va, const void *vb, int masklen)
return 0;
}
void mask(void *va, int masklen, int len)
{
void mask(void *va, int masklen, int len) {
int i;
char *a = va;
cp();
i = masklen / 8;
masklen %= 8;
@ -263,14 +260,11 @@ void mask(void *va, int masklen, int len)
a[i] = 0;
}
void maskcpy(void *va, const void *vb, int masklen, int len)
{
void maskcpy(void *va, const void *vb, int masklen, int len) {
int i, m;
char *a = va;
const char *b = vb;
cp();
for(m = masklen, i = 0; m >= 8; m -= 8, i++)
a[i] = b[i];
@ -283,13 +277,10 @@ void maskcpy(void *va, const void *vb, int masklen, int len)
a[i] = 0;
}
bool maskcheck(const void *va, int masklen, int len)
{
bool maskcheck(const void *va, int masklen, int len) {
int i;
const char *a = va;
cp();
i = masklen / 8;
masklen %= 8;

View file

@ -1,7 +1,7 @@
/*
netutl.h -- header file for netutl.c
Copyright (C) 1998-2005 Ivo Timmermans <zarq@iname.com>
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
Copyright (C) 1998-2005 Ivo Timmermans
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.h 1459 2006-08-08 13:44:37Z guus $
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_NETUTL_H__
@ -32,6 +30,7 @@ extern sockaddr_t str2sockaddr(const char *, const char *);
extern void sockaddr2str(const sockaddr_t *, char **, char **);
extern char *sockaddr2hostname(const sockaddr_t *);
extern int sockaddrcmp(const sockaddr_t *, const sockaddr_t *);
extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
extern void sockaddrunmap(sockaddr_t *);
extern void sockaddrfree(sockaddr_t *);
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *);

View file

@ -1,6 +1,6 @@
/*
node.c -- node tree management
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2009 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.c 1469 2006-11-11 22:44:15Z guus $
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"
@ -35,66 +33,43 @@ avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */
node_t *myself;
static int node_compare(const node_t *a, const node_t *b)
{
static int node_compare(const node_t *a, const node_t *b) {
return strcmp(a->name, b->name);
}
static int node_udp_compare(const node_t *a, const node_t *b)
{
int result;
cp();
result = sockaddrcmp(&a->address, &b->address);
if(result)
return result;
return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
static int node_udp_compare(const node_t *a, const node_t *b) {
return sockaddrcmp(&a->address, &b->address);
}
void init_nodes(void)
{
cp();
void init_nodes(void) {
node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node);
node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL);
}
void exit_nodes(void)
{
cp();
void exit_nodes(void) {
avl_delete_tree(node_udp_tree);
avl_delete_tree(node_tree);
}
node_t *new_node(void)
{
node_t *new_node(void) {
node_t *n = xmalloc_and_zero(sizeof(*n));
cp();
n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree();
n->queue = list_alloc((list_action_t) free);
EVP_CIPHER_CTX_init(&n->packet_ctx);
EVP_CIPHER_CTX_init(&n->inctx);
EVP_CIPHER_CTX_init(&n->outctx);
n->mtu = MTU;
n->maxmtu = MTU;
return n;
}
void free_node(node_t *n)
{
cp();
void free_node(node_t *n) {
if(n->inkey)
free(n->inkey);
if(n->queue)
list_delete_list(n->queue);
if(n->key)
free(n->key);
if(n->outkey)
free(n->outkey);
if(n->subnet_tree)
free_subnet_tree(n->subnet_tree);
@ -104,12 +79,11 @@ void free_node(node_t *n)
sockaddrfree(&n->address);
EVP_CIPHER_CTX_cleanup(&n->packet_ctx);
EVP_CIPHER_CTX_cleanup(&n->inctx);
EVP_CIPHER_CTX_cleanup(&n->outctx);
if(n->mtuevent) {
if(n->mtuevent)
event_del(n->mtuevent);
free_event(n->mtuevent);
}
if(n->hostname)
free(n->hostname);
@ -120,21 +94,15 @@ void free_node(node_t *n)
free(n);
}
void node_add(node_t *n)
{
cp();
void node_add(node_t *n) {
avl_insert(node_tree, n);
}
void node_del(node_t *n)
{
void node_del(node_t *n) {
avl_node_t *node, *next;
edge_t *e;
subnet_t *s;
cp();
for(node = n->subnet_tree->head; node; node = next) {
next = node->next;
s = node->data;
@ -147,49 +115,59 @@ void node_del(node_t *n)
edge_del(e);
}
avl_delete(node_udp_tree, n);
avl_delete(node_tree, n);
}
node_t *lookup_node(char *name)
{
node_t *lookup_node(char *name) {
node_t n = {0};
cp();
n.name = name;
return avl_search(node_tree, &n);
}
node_t *lookup_node_udp(const sockaddr_t *sa)
{
node_t *lookup_node_udp(const sockaddr_t *sa) {
node_t n = {0};
cp();
n.address = *sa;
n.name = NULL;
return avl_search(node_udp_tree, &n);
}
void dump_nodes(void)
{
void update_node_udp(node_t *n, const sockaddr_t *sa) {
avl_delete(node_udp_tree, n);
if(n->hostname)
free(n->hostname);
if(sa) {
n->address = *sa;
n->hostname = sockaddr2hostname(&n->address);
avl_insert(node_udp_tree, n);
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
} else {
memset(&n->address, 0, sizeof n->address);
n->hostname = 0;
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
}
}
void dump_nodes(void) {
avl_node_t *node;
node_t *n;
cp();
logger(LOG_DEBUG, _("Nodes:"));
logger(LOG_DEBUG, "Nodes:");
for(node = node_tree->head; node; node = node->next) {
n = node->data;
logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"),
n->name, n->hostname, n->cipher ? n->cipher->nid : 0,
n->digest ? n->digest->type : 0, n->maclength, n->compression,
n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)",
n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0,
n->outdigest ? n->outdigest->type : 0, n->outmaclength, n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
}
logger(LOG_DEBUG, _("End of nodes."));
logger(LOG_DEBUG, "End of nodes.");
}

View file

@ -1,6 +1,6 @@
/*
node.h -- header for node.c
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2001-2009 Guus Sliepen <guus@tinc-vpn.org>,
2001-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.h 1462 2006-11-11 13:43:00Z guus $
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_NODE_H__
@ -29,17 +27,14 @@
#include "list.h"
#include "subnet.h"
typedef union node_status_t {
struct {
int unused_active:1; /* 1 if active (not used for nodes) */
int validkey:1; /* 1 if we currently have a valid key for him */
int waitingforkey:1; /* 1 if we already sent out a request */
int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
int reachable:1; /* 1 if this node is reachable in the graph */
int indirect:1; /* 1 if this node is not directly reachable by us */
int unused:26;
};
uint32_t value;
typedef struct node_status_t {
int unused_active:1; /* 1 if active (not used for nodes) */
int validkey:1; /* 1 if we currently have a valid key for him */
int waitingforkey:1; /* 1 if we already sent out a request */
int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
int reachable:1; /* 1 if this node is reachable in the graph */
int indirect:1; /* 1 if this node is not directly reachable by us */
int unused:26;
} node_status_t;
typedef struct node_t {
@ -51,17 +46,24 @@ typedef struct node_t {
node_status_t status;
const EVP_CIPHER *cipher; /* Cipher type for UDP packets */
char *key; /* Cipher key and iv */
int keylength; /* Cipher key and iv length */
EVP_CIPHER_CTX packet_ctx; /* Cipher context */
const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */
char *inkey; /* Cipher key and iv */
int inkeylength; /* Cipher key and iv length */
EVP_CIPHER_CTX inctx; /* Cipher context */
const EVP_MD *digest; /* Digest type for MAC */
int maclength; /* Length of MAC */
const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/
char *outkey; /* Cipher key and iv */
int outkeylength; /* Cipher key and iv length */
EVP_CIPHER_CTX outctx; /* Cipher context */
const EVP_MD *indigest; /* Digest type for MAC of packets received from him */
int inmaclength; /* Length of MAC */
int compression; /* Compressionlevel, 0 = no compression */
const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/
int outmaclength; /* Length of MAC */
list_t *queue; /* Queue for packets awaiting to be encrypted */
int incompression; /* Compressionlevel, 0 = no compression */
int outcompression; /* Compressionlevel, 0 = no compression */
struct node_t *nexthop; /* nearest node from us to him */
struct node_t *via; /* next hop for UDP packets */
@ -95,6 +97,7 @@ extern void node_add(node_t *);
extern void node_del(node_t *);
extern node_t *lookup_node(char *);
extern node_t *lookup_node_udp(const sockaddr_t *);
extern void update_node_udp(node_t *, const sockaddr_t *);
extern void dump_nodes(void);
#endif /* __TINC_NODE_H__ */

View file

@ -1,7 +1,7 @@
/*
process.c -- process management functions
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2007 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: process.c 1595 2008-12-22 20:27:52Z guus $
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"
@ -49,10 +47,8 @@ sigset_t emptysigset;
static int saved_debug_level = -1;
static void memory_full(int size)
{
logger(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exitting."), size);
cp_trace();
static void memory_full(int size) {
logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size);
exit(1);
}
@ -76,7 +72,7 @@ bool install_service(void) {
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) {
logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
return false;
}
@ -107,18 +103,18 @@ bool install_service(void) {
command, NULL, NULL, NULL, NULL, NULL);
if(!service) {
logger(LOG_ERR, _("Could not create %s service: %s"), identname, winerror(GetLastError()));
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(GetLastError()));
return false;
}
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
logger(LOG_INFO, _("%s service installed"), identname);
logger(LOG_INFO, "%s service installed", identname);
if(!StartService(service, 0, NULL))
logger(LOG_WARNING, _("Could not start %s service: %s"), identname, winerror(GetLastError()));
logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
else
logger(LOG_INFO, _("%s service started"), identname);
logger(LOG_INFO, "%s service started", identname);
return true;
}
@ -126,28 +122,28 @@ bool install_service(void) {
bool remove_service(void) {
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) {
logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
return false;
}
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
if(!service) {
logger(LOG_ERR, _("Could not open %s service: %s"), identname, winerror(GetLastError()));
logger(LOG_ERR, "Could not open %s service: %s", identname, winerror(GetLastError()));
return false;
}
if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
logger(LOG_ERR, _("Could not stop %s service: %s"), identname, winerror(GetLastError()));
logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
else
logger(LOG_INFO, _("%s service stopped"), identname);
logger(LOG_INFO, "%s service stopped", identname);
if(!DeleteService(service)) {
logger(LOG_ERR, _("Could not remove %s service: %s"), identname, winerror(GetLastError()));
logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
return false;
}
logger(LOG_INFO, _("%s service removed"), identname);
logger(LOG_INFO, "%s service removed", identname);
return true;
}
@ -158,13 +154,13 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
SetServiceStatus(statushandle, &status);
return NO_ERROR;
case SERVICE_CONTROL_STOP:
logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_STOP");
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
break;
case SERVICE_CONTROL_SHUTDOWN:
logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_SHUTDOWN");
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
break;
default:
logger(LOG_WARNING, _("Got unexpected request %d"), request);
logger(LOG_WARNING, "Got unexpected request %d", request);
return ERROR_CALL_NOT_IMPLEMENTED;
}
@ -183,8 +179,7 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
}
VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
{
VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
int err = 1;
extern int main2(int argc, char **argv);
@ -198,7 +193,7 @@ VOID WINAPI run_service(DWORD argc, LPTSTR* argv)
statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
if (!statushandle) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
err = 1;
} else {
status.dwWaitHint = 30000;
@ -231,7 +226,7 @@ bool init_service(void) {
return false;
}
else
logger(LOG_ERR, _("System call `%s' failed: %s"), "StartServiceCtrlDispatcher", winerror(GetLastError()));
logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
}
return true;
@ -242,26 +237,23 @@ bool init_service(void) {
/*
check for an existing tinc for this net, and write pid to pidfile
*/
static bool write_pidfile(void)
{
static bool write_pidfile(void) {
pid_t pid;
cp();
pid = check_pid(pidfilename);
if(pid) {
if(netname)
fprintf(stderr, _("A tincd is already running for net `%s' with pid %ld.\n"),
fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
netname, (long)pid);
else
fprintf(stderr, _("A tincd is already running with pid %ld.\n"), (long)pid);
fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
return false;
}
/* if it's locked, write-protected, or whatever */
if(!write_pid(pidfilename)) {
fprintf(stderr, _("Could write pid file %s: %s\n"), pidfilename, strerror(errno));
fprintf(stderr, "Could write pid file %s: %s\n", pidfilename, strerror(errno));
return false;
}
@ -272,21 +264,18 @@ static bool write_pidfile(void)
/*
kill older tincd for this net
*/
bool kill_other(int signal)
{
bool kill_other(int signal) {
#ifndef HAVE_MINGW
pid_t pid;
cp();
pid = read_pid(pidfilename);
if(!pid) {
if(netname)
fprintf(stderr, _("No other tincd is running for net `%s'.\n"),
fprintf(stderr, "No other tincd is running for net `%s'.\n",
netname);
else
fprintf(stderr, _("No other tincd is running.\n"));
fprintf(stderr, "No other tincd is running.\n");
return false;
}
@ -295,12 +284,12 @@ bool kill_other(int signal)
/* ESRCH is returned when no process with that pid is found */
if(kill(pid, signal) && errno == ESRCH) {
if(netname)
fprintf(stderr, _("The tincd for net `%s' is no longer running. "),
fprintf(stderr, "The tincd for net `%s' is no longer running. ",
netname);
else
fprintf(stderr, _("The tincd is no longer running. "));
fprintf(stderr, "The tincd is no longer running. ");
fprintf(stderr, _("Removing stale lock file.\n"));
fprintf(stderr, "Removing stale lock file.\n");
remove_pid(pidfilename);
}
@ -313,10 +302,7 @@ bool kill_other(int signal)
/*
Detach from current terminal, write pidfile, kill parent
*/
bool detach(void)
{
cp();
bool detach(void) {
setup_signals();
/* First check if we can open a fresh new pidfile */
@ -333,7 +319,7 @@ bool detach(void)
if(do_detach) {
#ifndef HAVE_MINGW
if(daemon(0, 0)) {
fprintf(stderr, _("Couldn't detach from terminal: %s"),
fprintf(stderr, "Couldn't detach from terminal: %s",
strerror(errno));
return false;
}
@ -341,7 +327,7 @@ bool detach(void)
/* Now UPDATE the pid in the pidfile, because we changed it... */
if(!write_pid(pidfilename)) {
fprintf(stderr, _("Could not write pid file %s: %s\n"), pidfilename, strerror(errno));
fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
return false;
}
#else
@ -352,7 +338,7 @@ bool detach(void)
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
logger(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
logger(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
VERSION, __DATE__, __TIME__, debug_level);
xalloc_fail_func = memory_full;
@ -360,34 +346,32 @@ bool detach(void)
return true;
}
bool execute_script(const char *name, char **envp)
{
bool execute_script(const char *name, char **envp) {
#ifdef HAVE_SYSTEM
int status, len;
struct stat s;
char *scriptname, *p;
int i;
cp();
#ifndef HAVE_MINGW
len = asprintf(&scriptname, "\"%s/%s\"", confbase, name);
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
#else
len = asprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
#endif
if(len < 0)
return false;
scriptname[len - 1] = '\0';
#ifndef HAVE_TUNEMU
/* First check if there is a script */
if(stat(scriptname + 1, &s)) {
if(access(scriptname + 1, F_OK)) {
free(scriptname);
return true;
}
#endif
ifdebug(STATUS) logger(LOG_INFO, _("Executing script %s"), name);
ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
#ifdef HAVE_PUTENV
/* Set environment */
@ -417,20 +401,20 @@ bool execute_script(const char *name, char **envp)
if(status != -1) {
if(WIFEXITED(status)) { /* Child exited by itself */
if(WEXITSTATUS(status)) {
logger(LOG_ERR, _("Script %s exited with non-zero status %d"),
logger(LOG_ERR, "Script %s exited with non-zero status %d",
name, WEXITSTATUS(status));
return false;
}
} else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
logger(LOG_ERR, _("Script %s was killed by signal %d (%s)"),
logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
name, WTERMSIG(status), strsignal(WTERMSIG(status)));
return false;
} else { /* Something strange happened */
logger(LOG_ERR, _("Script %s terminated abnormally"), name);
logger(LOG_ERR, "Script %s terminated abnormally", name);
return false;
}
} else {
logger(LOG_ERR, _("System call `%s' failed: %s"), "system", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
return false;
}
#endif
@ -444,40 +428,34 @@ bool execute_script(const char *name, char **envp)
*/
#ifndef HAVE_MINGW
static RETSIGTYPE sigterm_handler(int a)
{
logger(LOG_NOTICE, _("Got %s signal"), "TERM");
static RETSIGTYPE sigterm_handler(int a) {
logger(LOG_NOTICE, "Got %s signal", "TERM");
if(running)
running = false;
else
exit(1);
}
static RETSIGTYPE sigquit_handler(int a)
{
logger(LOG_NOTICE, _("Got %s signal"), "QUIT");
static RETSIGTYPE sigquit_handler(int a) {
logger(LOG_NOTICE, "Got %s signal", "QUIT");
if(running)
running = false;
else
exit(1);
}
static RETSIGTYPE fatal_signal_square(int a)
{
logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a,
static RETSIGTYPE fatal_signal_square(int a) {
logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
strsignal(a));
cp_trace();
exit(1);
}
static RETSIGTYPE fatal_signal_handler(int a)
{
static RETSIGTYPE fatal_signal_handler(int a) {
struct sigaction act;
logger(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
cp_trace();
logger(LOG_ERR, "Got fatal signal %d (%s)", a, strsignal(a));
if(do_detach) {
logger(LOG_NOTICE, _("Trying to re-execute in 5 seconds..."));
logger(LOG_NOTICE, "Trying to re-execute in 5 seconds...");
act.sa_handler = fatal_signal_square;
act.sa_mask = emptysigset;
@ -489,68 +467,59 @@ static RETSIGTYPE fatal_signal_handler(int a)
remove_pid(pidfilename);
execvp(g_argv[0], g_argv);
} else {
logger(LOG_NOTICE, _("Not restarting."));
logger(LOG_NOTICE, "Not restarting.");
exit(1);
}
}
static RETSIGTYPE sighup_handler(int a)
{
logger(LOG_NOTICE, _("Got %s signal"), "HUP");
static RETSIGTYPE sighup_handler(int a) {
logger(LOG_NOTICE, "Got %s signal", "HUP");
sighup = true;
}
static RETSIGTYPE sigint_handler(int a)
{
logger(LOG_NOTICE, _("Got %s signal"), "INT");
static RETSIGTYPE sigint_handler(int a) {
logger(LOG_NOTICE, "Got %s signal", "INT");
if(saved_debug_level != -1) {
logger(LOG_NOTICE, _("Reverting to old debug level (%d)"),
logger(LOG_NOTICE, "Reverting to old debug level (%d)",
saved_debug_level);
debug_level = saved_debug_level;
saved_debug_level = -1;
} else {
logger(LOG_NOTICE,
_("Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d."),
"Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.",
debug_level);
saved_debug_level = debug_level;
debug_level = 5;
}
}
static RETSIGTYPE sigalrm_handler(int a)
{
logger(LOG_NOTICE, _("Got %s signal"), "ALRM");
static RETSIGTYPE sigalrm_handler(int a) {
logger(LOG_NOTICE, "Got %s signal", "ALRM");
sigalrm = true;
}
static RETSIGTYPE sigusr1_handler(int a)
{
static RETSIGTYPE sigusr1_handler(int a) {
dump_connections();
}
static RETSIGTYPE sigusr2_handler(int a)
{
static RETSIGTYPE sigusr2_handler(int a) {
dump_device_stats();
dump_nodes();
dump_edges();
dump_subnets();
}
static RETSIGTYPE sigwinch_handler(int a)
{
static RETSIGTYPE sigwinch_handler(int a) {
do_purge = true;
}
static RETSIGTYPE unexpected_signal_handler(int a)
{
logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
cp_trace();
static RETSIGTYPE unexpected_signal_handler(int a) {
logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
}
static RETSIGTYPE ignore_signal_handler(int a)
{
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
static RETSIGTYPE ignore_signal_handler(int a) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
}
static struct {
@ -574,8 +543,7 @@ static struct {
};
#endif
void setup_signals(void)
{
void setup_signals(void) {
#ifndef HAVE_MINGW
int i;
struct sigaction act;
@ -587,7 +555,7 @@ void setup_signals(void)
/* Set a default signal handler for every signal, errors will be
ignored. */
for(i = 0; i < NSIG; i++) {
for(i = 1; i < NSIG; i++) {
if(!do_detach)
act.sa_handler = SIG_DFL;
else
@ -604,7 +572,7 @@ void setup_signals(void)
for(i = 0; sighandlers[i].signal; i++) {
act.sa_handler = sighandlers[i].handler;
if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"),
fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
sighandlers[i].signal, strsignal(sighandlers[i].signal),
strerror(errno));
}

View file

@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: process.h 1452 2006-04-26 13:52:58Z guus $
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_PROCESS_H__

View file

@ -1,7 +1,7 @@
/*
protocol.c -- handle the meta-protocol, basic functions
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -55,8 +53,7 @@ static char (*request_name[]) = {
static avl_tree_t *past_request_tree;
bool check_id(const char *id)
{
bool check_id(const char *id) {
for(; *id; id++)
if(!isalnum(*id) && *id != '_')
return false;
@ -67,15 +64,12 @@ bool check_id(const char *id)
/* Generic request routines - takes care of logging and error
detection as well */
bool send_request(connection_t *c, const char *format, ...)
{
bool send_request(connection_t *c, const char *format, ...) {
va_list args;
char buffer[MAXBUFSIZE];
int len, request;
cp();
/* Use vsnprintf instead of vasprintf: faster, no memory
/* Use vsnprintf instead of vxasprintf: faster, no memory
fragmentation, cleanup is automatic, and there is a limit on the
input buffer anyway */
@ -84,7 +78,7 @@ bool send_request(connection_t *c, const char *format, ...)
va_end(args);
if(len < 0 || len > MAXBUFSIZE - 1) {
logger(LOG_ERR, _("Output buffer overflow while sending request to %s (%s)"),
logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
c->name, c->hostname);
return false;
}
@ -92,10 +86,10 @@ bool send_request(connection_t *c, const char *format, ...)
ifdebug(PROTOCOL) {
sscanf(buffer, "%d", &request);
ifdebug(META)
logger(LOG_DEBUG, _("Sending %s to %s (%s): %s"),
logger(LOG_DEBUG, "Sending %s to %s (%s): %s",
request_name[request], c->name, c->hostname, buffer);
else
logger(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request],
logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request],
c->name, c->hostname);
}
@ -108,20 +102,17 @@ bool send_request(connection_t *c, const char *format, ...)
return send_meta(c, buffer, len);
}
void forward_request(connection_t *from)
{
void forward_request(connection_t *from) {
int request;
cp();
ifdebug(PROTOCOL) {
sscanf(from->buffer, "%d", &request);
ifdebug(META)
logger(LOG_DEBUG, _("Forwarding %s from %s (%s): %s"),
logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s",
request_name[request], from->name, from->hostname,
from->buffer);
else
logger(LOG_DEBUG, _("Forwarding %s from %s (%s)"),
logger(LOG_DEBUG, "Forwarding %s from %s (%s)",
request_name[request], from->name, from->hostname);
}
@ -130,36 +121,33 @@ void forward_request(connection_t *from)
broadcast_meta(from, from->buffer, from->reqlen);
}
bool receive_request(connection_t *c)
{
bool receive_request(connection_t *c) {
int request;
cp();
if(sscanf(c->buffer, "%d", &request) == 1) {
if((request < 0) || (request >= LAST) || !request_handlers[request]) {
ifdebug(META)
logger(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
logger(LOG_DEBUG, "Unknown request from %s (%s): %s",
c->name, c->hostname, c->buffer);
else
logger(LOG_ERR, _("Unknown request from %s (%s)"),
logger(LOG_ERR, "Unknown request from %s (%s)",
c->name, c->hostname);
return false;
} else {
ifdebug(PROTOCOL) {
ifdebug(META)
logger(LOG_DEBUG, _("Got %s from %s (%s): %s"),
logger(LOG_DEBUG, "Got %s from %s (%s): %s",
request_name[request], c->name, c->hostname,
c->buffer);
else
logger(LOG_DEBUG, _("Got %s from %s (%s)"),
logger(LOG_DEBUG, "Got %s from %s (%s)",
request_name[request], c->name, c->hostname);
}
}
if((c->allow_request != ALL) && (c->allow_request != request)) {
logger(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name,
logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name,
c->hostname);
return false;
}
@ -167,12 +155,12 @@ bool receive_request(connection_t *c)
if(!request_handlers[request](c)) {
/* Something went wrong. Probably scriptkiddies. Terminate. */
logger(LOG_ERR, _("Error while processing %s from %s (%s)"),
logger(LOG_ERR, "Error while processing %s from %s (%s)",
request_name[request], c->name, c->hostname);
return false;
}
} else {
logger(LOG_ERR, _("Bogus data received from %s (%s)"),
logger(LOG_ERR, "Bogus data received from %s (%s)",
c->name, c->hostname);
return false;
}
@ -180,45 +168,32 @@ bool receive_request(connection_t *c)
return true;
}
static int past_request_compare(const past_request_t *a, const past_request_t *b)
{
static int past_request_compare(const past_request_t *a, const past_request_t *b) {
return strcmp(a->request, b->request);
}
static void free_past_request(past_request_t *r)
{
cp();
static void free_past_request(past_request_t *r) {
if(r->request)
free(r->request);
free(r);
}
void init_requests(void)
{
cp();
void init_requests(void) {
past_request_tree = avl_alloc_tree((avl_compare_t) past_request_compare, (avl_action_t) free_past_request);
}
void exit_requests(void)
{
cp();
void exit_requests(void) {
avl_delete_tree(past_request_tree);
}
bool seen_request(char *request)
{
bool seen_request(char *request) {
past_request_t *new, p = {0};
cp();
p.request = request;
if(avl_search(past_request_tree, &p)) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Already seen request"));
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Already seen request");
return true;
} else {
new = xmalloc(sizeof(*new));
@ -229,14 +204,11 @@ bool seen_request(char *request)
}
}
void age_past_requests(void)
{
void age_past_requests(void) {
avl_node_t *node, *next;
past_request_t *p;
int left = 0, deleted = 0;
cp();
for(node = past_request_tree->head; node; node = next) {
next = node->next;
p = node->data;
@ -248,6 +220,6 @@ void age_past_requests(void)
}
if(left || deleted)
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Aging past requests: deleted %d, left %d"),
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d",
deleted, left);
}

View file

@ -1,7 +1,7 @@
/*
protocol.h -- header for protocol.c
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol.h 1452 2006-04-26 13:52:58Z guus $
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_PROTOCOL_H__
@ -97,9 +95,9 @@ extern bool send_add_subnet(struct connection_t *, const struct subnet_t *);
extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
extern bool send_add_edge(struct connection_t *, const struct edge_t *);
extern bool send_del_edge(struct connection_t *, const struct edge_t *);
extern bool send_key_changed(struct connection_t *, const struct node_t *);
extern bool send_req_key(struct connection_t *, const struct node_t *, const struct node_t *);
extern bool send_ans_key(struct connection_t *, const struct node_t *, const struct node_t *);
extern bool send_key_changed();
extern bool send_req_key(struct node_t *);
extern bool send_ans_key(struct node_t *);
extern bool send_tcppacket(struct connection_t *, struct vpn_packet_t *);
/* Request handlers */

View file

@ -1,7 +1,7 @@
/*
protocol_auth.c -- handle the meta-protocol, authentication
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_auth.c 1596 2008-12-22 20:35:45Z guus $
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"
@ -40,22 +38,16 @@
#include "utils.h"
#include "xalloc.h"
bool send_id(connection_t *c)
{
cp();
bool send_id(connection_t *c) {
return send_request(c, "%d %s %d", ID, myself->connection->name,
myself->connection->protocol_version);
}
bool id_h(connection_t *c)
{
bool id_h(connection_t *c) {
char name[MAX_STRING_SIZE];
cp();
if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name,
c->hostname);
return false;
}
@ -63,7 +55,7 @@ bool id_h(connection_t *c)
/* Check if identity is a valid name */
if(!check_id(name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ID", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name,
c->hostname, "invalid name");
return false;
}
@ -72,7 +64,7 @@ bool id_h(connection_t *c)
if(c->outgoing) {
if(strcmp(c->name, name)) {
logger(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name,
logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name,
c->name);
return false;
}
@ -85,7 +77,7 @@ bool id_h(connection_t *c)
/* Check if version matches */
if(c->protocol_version != myself->connection->protocol_version) {
logger(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d",
c->name, c->hostname, c->protocol_version);
return false;
}
@ -101,7 +93,7 @@ bool id_h(connection_t *c)
init_configuration(&c->config_tree);
if(!read_connection_config(c)) {
logger(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname,
logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname,
c->name);
return false;
}
@ -116,26 +108,22 @@ bool id_h(connection_t *c)
return send_metakey(c);
}
bool send_metakey(connection_t *c)
{
bool send_metakey(connection_t *c) {
char *buffer;
int len;
bool x;
cp();
len = RSA_size(c->rsa_key);
/* Allocate buffers for the meta key */
buffer = alloca(2 * len + 1);
if(!c->outkey)
c->outkey = xmalloc(len);
c->outkey = xrealloc(c->outkey, len);
if(!c->outctx)
c->outctx = xmalloc_and_zero(sizeof(*c->outctx));
cp();
/* Copy random data to the buffer */
RAND_pseudo_bytes((unsigned char *)c->outkey, len);
@ -155,7 +143,7 @@ bool send_metakey(connection_t *c)
ifdebug(SCARY_THINGS) {
bin2hex(c->outkey, buffer, len);
buffer[len * 2] = '\0';
logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"),
logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s",
buffer);
}
@ -167,7 +155,7 @@ bool send_metakey(connection_t *c)
*/
if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"),
logger(LOG_ERR, "Error during encryption of meta key for %s (%s)",
c->name, c->hostname);
return false;
}
@ -191,7 +179,7 @@ bool send_metakey(connection_t *c)
(unsigned char *)c->outkey + len - c->outcipher->key_len,
(unsigned char *)c->outkey + len - c->outcipher->key_len -
c->outcipher->iv_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -202,16 +190,13 @@ bool send_metakey(connection_t *c)
return x;
}
bool metakey_h(connection_t *c)
{
bool metakey_h(connection_t *c) {
char buffer[MAX_STRING_SIZE];
int cipher, digest, maclength, compression;
int len;
cp();
if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name,
c->hostname);
return false;
}
@ -221,14 +206,13 @@ bool metakey_h(connection_t *c)
/* Check if the length of the meta key is all right */
if(strlen(buffer) != len * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength");
return false;
}
/* Allocate buffers for the meta key */
if(!c->inkey)
c->inkey = xmalloc(len);
c->inkey = xrealloc(c->inkey, len);
if(!c->inctx)
c->inctx = xmalloc_and_zero(sizeof(*c->inctx));
@ -240,7 +224,7 @@ bool metakey_h(connection_t *c)
/* Decrypt the meta key */
if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */
logger(LOG_ERR, _("Error during decryption of meta key for %s (%s)"),
logger(LOG_ERR, "Error during decryption of meta key for %s (%s)",
c->name, c->hostname);
return false;
}
@ -248,7 +232,7 @@ bool metakey_h(connection_t *c)
ifdebug(SCARY_THINGS) {
bin2hex(c->inkey, buffer, len);
buffer[len * 2] = '\0';
logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", buffer);
}
/* All incoming requests will now be encrypted. */
@ -259,7 +243,7 @@ bool metakey_h(connection_t *c)
c->incipher = EVP_get_cipherbynid(cipher);
if(!c->incipher) {
logger(LOG_ERR, _("%s (%s) uses unknown cipher!"), c->name, c->hostname);
logger(LOG_ERR, "%s (%s) uses unknown cipher!", c->name, c->hostname);
return false;
}
@ -267,7 +251,7 @@ bool metakey_h(connection_t *c)
(unsigned char *)c->inkey + len - c->incipher->key_len,
(unsigned char *)c->inkey + len - c->incipher->key_len -
c->incipher->iv_len)) {
logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s): %s"),
logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -283,12 +267,12 @@ bool metakey_h(connection_t *c)
c->indigest = EVP_get_digestbynid(digest);
if(!c->indigest) {
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), c->name, c->hostname);
logger(LOG_ERR, "Node %s (%s) uses unknown digest!", c->name, c->hostname);
return false;
}
if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) {
logger(LOG_ERR, _("%s (%s) uses bogus MAC length!"), c->name, c->hostname);
logger(LOG_ERR, "%s (%s) uses bogus MAC length!", c->name, c->hostname);
return false;
}
} else {
@ -302,13 +286,10 @@ bool metakey_h(connection_t *c)
return send_challenge(c);
}
bool send_challenge(connection_t *c)
{
bool send_challenge(connection_t *c) {
char *buffer;
int len;
cp();
/* CHECKME: what is most reasonable value for len? */
len = RSA_size(c->rsa_key);
@ -317,8 +298,7 @@ bool send_challenge(connection_t *c)
buffer = alloca(2 * len + 1);
if(!c->hischallenge)
c->hischallenge = xmalloc(len);
c->hischallenge = xrealloc(c->hischallenge, len);
/* Copy random data to the buffer */
@ -334,15 +314,12 @@ bool send_challenge(connection_t *c)
return send_request(c, "%d %s", CHALLENGE, buffer);
}
bool challenge_h(connection_t *c)
{
bool challenge_h(connection_t *c) {
char buffer[MAX_STRING_SIZE];
int len;
cp();
if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name,
c->hostname);
return false;
}
@ -352,15 +329,14 @@ bool challenge_h(connection_t *c)
/* Check if the length of the challenge is all right */
if(strlen(buffer) != len * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge length");
return false;
}
/* Allocate buffers for the challenge */
if(!c->mychallenge)
c->mychallenge = xmalloc(len);
c->mychallenge = xrealloc(c->mychallenge, len);
/* Convert the challenge from hexadecimal back to binary */
@ -373,19 +349,16 @@ bool challenge_h(connection_t *c)
return send_chal_reply(c);
}
bool send_chal_reply(connection_t *c)
{
bool send_chal_reply(connection_t *c) {
char hash[EVP_MAX_MD_SIZE * 2 + 1];
EVP_MD_CTX ctx;
cp();
/* Calculate the hash from the challenge we received */
if(!EVP_DigestInit(&ctx, c->indigest)
|| !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
|| !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) {
logger(LOG_ERR, _("Error during calculation of response for %s (%s): %s"),
logger(LOG_ERR, "Error during calculation of response for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -400,16 +373,13 @@ bool send_chal_reply(connection_t *c)
return send_request(c, "%d %s", CHAL_REPLY, hash);
}
bool chal_reply_h(connection_t *c)
{
bool chal_reply_h(connection_t *c) {
char hishash[MAX_STRING_SIZE];
char myhash[EVP_MAX_MD_SIZE];
EVP_MD_CTX ctx;
cp();
if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name,
c->hostname);
return false;
}
@ -417,8 +387,8 @@ bool chal_reply_h(connection_t *c)
/* Check if the length of the hash is all right */
if(strlen(hishash) != c->outdigest->md_size * 2) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
c->hostname, _("wrong challenge reply length"));
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge reply length");
return false;
}
@ -431,7 +401,7 @@ bool chal_reply_h(connection_t *c)
if(!EVP_DigestInit(&ctx, c->outdigest)
|| !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key))
|| !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) {
logger(LOG_ERR, _("Error during calculation of response from %s (%s): %s"),
logger(LOG_ERR, "Error during calculation of response from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
@ -439,13 +409,13 @@ bool chal_reply_h(connection_t *c)
/* Verify the incoming hash with the calculated hash */
if(memcmp(hishash, myhash, c->outdigest->md_size)) {
logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name,
c->hostname, _("wrong challenge reply"));
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge reply");
ifdebug(SCARY_THINGS) {
bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
hishash[SHA_DIGEST_LENGTH * 2] = '\0';
logger(LOG_DEBUG, _("Expected challenge reply: %s"), hishash);
logger(LOG_DEBUG, "Expected challenge reply: %s", hishash);
}
return false;
@ -460,16 +430,13 @@ bool chal_reply_h(connection_t *c)
return send_ack(c);
}
bool send_ack(connection_t *c)
{
bool send_ack(connection_t *c) {
/* ACK message contains rest of the information the other end needs
to create node_t and edge_t structures. */
struct timeval now;
bool choice;
cp();
/* Estimate weight */
gettimeofday(&now, NULL);
@ -483,7 +450,7 @@ bool send_ack(connection_t *c)
if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY)
c->options |= OPTION_TCPONLY | OPTION_INDIRECT;
if((!get_config_bool(lookup_config(c->config_tree, "PMTUDiscovery"), &choice) || choice) || myself->options & OPTION_PMTU_DISCOVERY)
if(myself->options & OPTION_PMTU_DISCOVERY)
c->options |= OPTION_PMTU_DISCOVERY;
get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
@ -491,8 +458,7 @@ bool send_ack(connection_t *c)
return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options);
}
static void send_everything(connection_t *c)
{
static void send_everything(connection_t *c) {
avl_node_t *node, *node2;
node_t *n;
subnet_t *s;
@ -524,18 +490,15 @@ static void send_everything(connection_t *c)
}
}
bool ack_h(connection_t *c)
{
bool ack_h(connection_t *c) {
char hisport[MAX_STRING_SIZE];
char *hisaddress, *dummy;
int weight, mtu;
long int options;
node_t *n;
cp();
if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
c->hostname);
return false;
}
@ -551,7 +514,7 @@ bool ack_h(connection_t *c)
} else {
if(n->connection) {
/* Oh dear, we already have a connection to this node. */
ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"),
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection",
n->name, n->hostname);
terminate_connection(n->connection, false);
/* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
@ -561,6 +524,10 @@ bool ack_h(connection_t *c)
n->connection = c;
c->node = n;
if(!(c->options & options & OPTION_PMTU_DISCOVERY)) {
c->options &= ~OPTION_PMTU_DISCOVERY;
options &= ~OPTION_PMTU_DISCOVERY;
}
c->options |= options;
if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
@ -574,7 +541,7 @@ bool ack_h(connection_t *c)
c->allow_request = ALL;
c->status.active = true;
ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name,
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name,
c->hostname);
/* Send him everything we know */
@ -584,7 +551,6 @@ bool ack_h(connection_t *c)
/* Create an edge_t for this connection */
c->edge = new_edge();
cp();
c->edge->from = myself;
c->edge->to = n;
sockaddr2str(&c->address, &hisaddress, &dummy);

View file

@ -1,7 +1,8 @@
/*
protocol_edge.c -- handle the meta-protocol, edges
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2009 Michael Tokarev <mjt@corpit.ru>
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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_edge.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -36,16 +35,13 @@
#include "utils.h"
#include "xalloc.h"
bool send_add_edge(connection_t *c, const edge_t *e)
{
bool send_add_edge(connection_t *c, const edge_t *e) {
bool x;
char *address, *port;
cp();
sockaddr2str(&e->address, &address, &port);
x = send_request(c, "%d %lx %s %s %s %s %lx %d", ADD_EDGE, random(),
x = send_request(c, "%d %x %s %s %s %s %lx %d", ADD_EDGE, rand(),
e->from->name, e->to->name, address, port,
e->options, e->weight);
free(address);
@ -54,8 +50,7 @@ bool send_add_edge(connection_t *c, const edge_t *e)
return x;
}
bool add_edge_h(connection_t *c)
{
bool add_edge_h(connection_t *c) {
edge_t *e;
node_t *from, *to;
char from_name[MAX_STRING_SIZE];
@ -66,26 +61,18 @@ bool add_edge_h(connection_t *c)
long int options;
int weight;
cp();
if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
from_name, to_name, to_address, to_port, &options, &weight) != 6) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
c->hostname);
return false;
}
/* Check if names are valid */
if(!check_id(from_name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
c->hostname, _("invalid name"));
return false;
}
if(!check_id(to_name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
c->hostname, _("invalid name"));
if(!check_id(from_name) || !check_id(to_name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
c->hostname, "invalid name");
return false;
}
@ -95,6 +82,17 @@ bool add_edge_h(connection_t *c)
/* Lookup nodes */
from = lookup_node(from_name);
to = lookup_node(to_name);
if(tunnelserver &&
from != myself && from != c->node &&
to != myself && to != c->node) {
/* ignore indirect edge registrations for tunnelserver */
ifdebug(PROTOCOL) logger(LOG_WARNING,
"Ignoring indirect %s from %s (%s)",
"ADD_EDGE", c->name, c->hostname);
return true;
}
if(!from) {
from = new_node();
@ -102,16 +100,12 @@ bool add_edge_h(connection_t *c)
node_add(from);
}
to = lookup_node(to_name);
if(!to) {
to = new_node();
to->name = xstrdup(to_name);
node_add(to);
}
if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node)
return false;
/* Convert addresses */
@ -124,12 +118,12 @@ bool add_edge_h(connection_t *c)
if(e) {
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
if(from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
"ADD_EDGE", c->name, c->hostname);
send_add_edge(c, e);
return true;
} else {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"),
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();
@ -137,7 +131,7 @@ bool add_edge_h(connection_t *c)
} else
return true;
} else if(from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist",
"ADD_EDGE", c->name, c->hostname);
e = new_edge();
e->from = from;
@ -167,40 +161,28 @@ bool add_edge_h(connection_t *c)
return true;
}
bool send_del_edge(connection_t *c, const edge_t *e)
{
cp();
return send_request(c, "%d %lx %s %s", DEL_EDGE, random(),
bool send_del_edge(connection_t *c, const edge_t *e) {
return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
e->from->name, e->to->name);
}
bool del_edge_h(connection_t *c)
{
bool del_edge_h(connection_t *c) {
edge_t *e;
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
node_t *from, *to;
cp();
if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name,
c->hostname);
return false;
}
/* Check if names are valid */
if(!check_id(from_name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
c->hostname, _("invalid name"));
return false;
}
if(!check_id(to_name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
c->hostname, _("invalid name"));
if(!check_id(from_name) || !check_id(to_name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
c->hostname, "invalid name");
return false;
}
@ -210,36 +192,42 @@ bool del_edge_h(connection_t *c)
/* Lookup nodes */
from = lookup_node(from_name);
if(!from) {
ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
"DEL_EDGE", c->name, c->hostname);
return true;
}
to = lookup_node(to_name);
if(!to) {
ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
if(tunnelserver &&
from != myself && from != c->node &&
to != myself && to != c->node) {
/* ignore indirect edge registrations for tunnelserver */
ifdebug(PROTOCOL) logger(LOG_WARNING,
"Ignoring indirect %s from %s (%s)",
"DEL_EDGE", c->name, c->hostname);
return true;
}
if(!from) {
ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname);
return true;
}
if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node)
return false;
if(!to) {
ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname);
return true;
}
/* Check if edge exists */
e = lookup_edge(from, to);
if(!e) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname);
return true;
}
if(e->from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"DEL_EDGE", c->name, c->hostname);
send_add_edge(c, e); /* Send back a correction */
return true;

View file

@ -1,7 +1,7 @@
/*
protocol_key.c -- handle the meta-protocol, key exchange
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,17 +13,16 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_key.c 1595 2008-12-22 20:27:52Z guus $
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "avl_tree.h"
#include "connection.h"
@ -37,29 +36,23 @@
bool mykeyused = false;
bool send_key_changed(connection_t *c, const node_t *n)
{
cp();
bool send_key_changed() {
/* Only send this message if some other daemon requested our key previously.
This reduces unnecessary key_changed broadcasts.
*/
if(n == myself && !mykeyused)
if(!mykeyused)
return true;
return send_request(c, "%d %lx %s", KEY_CHANGED, random(), n->name);
return send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
}
bool key_changed_h(connection_t *c)
{
bool key_changed_h(connection_t *c) {
char name[MAX_STRING_SIZE];
node_t *n;
cp();
if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED",
logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
c->name, c->hostname);
return false;
}
@ -70,7 +63,7 @@ bool key_changed_h(connection_t *c)
n = lookup_node(name);
if(!n) {
logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist"),
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
"KEY_CHANGED", c->name, c->hostname, name);
return false;
}
@ -86,23 +79,17 @@ bool key_changed_h(connection_t *c)
return true;
}
bool send_req_key(connection_t *c, const node_t *from, const node_t *to)
{
cp();
return send_request(c, "%d %s %s", REQ_KEY, from->name, to->name);
bool send_req_key(node_t *to) {
return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
}
bool req_key_h(connection_t *c)
{
bool req_key_h(connection_t *c) {
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
node_t *from, *to;
cp();
if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
c->hostname);
return false;
}
@ -110,7 +97,7 @@ bool req_key_h(connection_t *c)
from = lookup_node(from_name);
if(!from) {
logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
"REQ_KEY", c->name, c->hostname, from_name);
return false;
}
@ -118,7 +105,7 @@ bool req_key_h(connection_t *c)
to = lookup_node(to_name);
if(!to) {
logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
"REQ_KEY", c->name, c->hostname, to_name);
return false;
}
@ -126,57 +113,69 @@ bool req_key_h(connection_t *c)
/* Check if this key request is for us */
if(to == myself) { /* Yes, send our own key back */
mykeyused = true;
from->received_seqno = 0;
memset(from->late, 0, sizeof(from->late));
send_ans_key(c, myself, from);
send_ans_key(from);
} else {
if(tunnelserver)
return false;
if(!to->status.reachable) {
logger(LOG_WARNING, _("Got %s from %s (%s) destination %s which is not reachable"),
logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
"REQ_KEY", c->name, c->hostname, to_name);
return true;
}
send_req_key(to->nexthop->connection, from, to);
send_request(to->nexthop->connection, "%s", c->buffer);
}
return true;
}
bool send_ans_key(connection_t *c, const node_t *from, const node_t *to)
{
bool send_ans_key(node_t *to) {
char *key;
cp();
// Set key parameters
to->incipher = myself->incipher;
to->inkeylength = myself->inkeylength;
to->indigest = myself->indigest;
to->inmaclength = myself->inmaclength;
to->incompression = myself->incompression;
key = alloca(2 * from->keylength + 1);
bin2hex(from->key, key, from->keylength);
key[from->keylength * 2] = '\0';
// Allocate memory for key
to->inkey = xrealloc(to->inkey, to->inkeylength);
return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
from->name, to->name, key,
from->cipher ? from->cipher->nid : 0,
from->digest ? from->digest->type : 0, from->maclength,
from->compression);
// Create a new key
RAND_pseudo_bytes((unsigned char *)to->inkey, to->inkeylength);
if(to->incipher)
EVP_DecryptInit_ex(&to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + to->incipher->key_len);
// Reset sequence number and late packet window
mykeyused = true;
to->received_seqno = 0;
memset(to->late, 0, sizeof(to->late));
// Convert to hexadecimal and send
key = alloca(2 * to->inkeylength + 1);
bin2hex(to->inkey, key, to->inkeylength);
key[to->inkeylength * 2] = '\0';
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
myself->name, to->name, key,
to->incipher ? to->incipher->nid : 0,
to->indigest ? to->indigest->type : 0, to->inmaclength,
to->incompression);
}
bool ans_key_h(connection_t *c)
{
bool ans_key_h(connection_t *c) {
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
char key[MAX_STRING_SIZE];
int cipher, digest, maclength, compression;
node_t *from, *to;
cp();
if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
from_name, to_name, key, &cipher, &digest, &maclength,
&compression) != 7) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
c->hostname);
return false;
}
@ -184,7 +183,7 @@ bool ans_key_h(connection_t *c)
from = lookup_node(from_name);
if(!from) {
logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
"ANS_KEY", c->name, c->hostname, from_name);
return false;
}
@ -192,7 +191,7 @@ bool ans_key_h(connection_t *c)
to = lookup_node(to_name);
if(!to) {
logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
"ANS_KEY", c->name, c->hostname, to_name);
return false;
}
@ -204,7 +203,7 @@ bool ans_key_h(connection_t *c)
return false;
if(!to->status.reachable) {
logger(LOG_WARNING, _("Got %s from %s (%s) destination %s which is not reachable"),
logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
"ANS_KEY", c->name, c->hostname, to_name);
return true;
}
@ -213,77 +212,72 @@ bool ans_key_h(connection_t *c)
}
/* Update our copy of the origin's packet key */
from->outkey = xrealloc(from->outkey, strlen(key) / 2);
if(from->key)
free(from->key);
from->outkey = xstrdup(key);
from->outkeylength = strlen(key) / 2;
hex2bin(key, from->outkey, from->outkeylength);
from->key = xstrdup(key);
from->keylength = strlen(key) / 2;
hex2bin(from->key, from->key, from->keylength);
from->key[from->keylength] = '\0';
from->status.validkey = true;
from->status.waitingforkey = false;
from->sent_seqno = 0;
/* Check and lookup cipher and digest algorithms */
if(cipher) {
from->cipher = EVP_get_cipherbynid(cipher);
from->outcipher = EVP_get_cipherbynid(cipher);
if(!from->cipher) {
logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
if(!from->outcipher) {
logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name,
from->hostname);
return false;
}
if(from->keylength != from->cipher->key_len + from->cipher->iv_len) {
logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name,
if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) {
logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name,
from->hostname);
return false;
}
} else {
from->cipher = NULL;
from->outcipher = NULL;
}
from->maclength = maclength;
from->outmaclength = maclength;
if(digest) {
from->digest = EVP_get_digestbynid(digest);
from->outdigest = EVP_get_digestbynid(digest);
if(!from->digest) {
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
if(!from->outdigest) {
logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name,
from->hostname);
return false;
}
if(from->maclength > from->digest->md_size || from->maclength < 0) {
logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"),
if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) {
logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!",
from->name, from->hostname);
return false;
}
} else {
from->digest = NULL;
from->outdigest = NULL;
}
if(compression < 0 || compression > 11) {
logger(LOG_ERR, _("Node %s (%s) uses bogus compression level!"), from->name, from->hostname);
logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
return false;
}
from->compression = compression;
from->outcompression = compression;
if(from->cipher)
if(!EVP_EncryptInit_ex(&from->packet_ctx, from->cipher, NULL, (unsigned char *)from->key, (unsigned char *)from->key + from->cipher->key_len)) {
logger(LOG_ERR, _("Error during initialisation of key from %s (%s): %s"),
if(from->outcipher)
if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) {
logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s",
from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
return false;
}
from->status.validkey = true;
from->sent_seqno = 0;
if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
send_mtu_probe(from);
flush_queue(from);
return true;
}

View file

@ -1,7 +1,7 @@
/*
protocol_misc.c -- handle the meta-protocol, miscellaneous functions
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_misc.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -35,59 +33,47 @@ int maxoutbufsize = 0;
/* Status and error notification routines */
bool send_status(connection_t *c, int statusno, const char *statusstring)
{
cp();
bool send_status(connection_t *c, int statusno, const char *statusstring) {
if(!statusstring)
statusstring = "Status";
return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
}
bool status_h(connection_t *c)
{
bool status_h(connection_t *c) {
int statusno;
char statusstring[MAX_STRING_SIZE];
cp();
if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS",
logger(LOG_ERR, "Got bad %s from %s (%s)", "STATUS",
c->name, c->hostname);
return false;
}
ifdebug(STATUS) logger(LOG_NOTICE, _("Status message from %s (%s): %d: %s"),
ifdebug(STATUS) logger(LOG_NOTICE, "Status message from %s (%s): %d: %s",
c->name, c->hostname, statusno, statusstring);
return true;
}
bool send_error(connection_t *c, int err, const char *errstring)
{
cp();
bool send_error(connection_t *c, int err, const char *errstring) {
if(!errstring)
errstring = "Error";
return send_request(c, "%d %d %s", ERROR, err, errstring);
}
bool error_h(connection_t *c)
{
bool error_h(connection_t *c) {
int err;
char errorstring[MAX_STRING_SIZE];
cp();
if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR",
logger(LOG_ERR, "Got bad %s from %s (%s)", "ERROR",
c->name, c->hostname);
return false;
}
ifdebug(ERROR) logger(LOG_NOTICE, _("Error message from %s (%s): %d: %s"),
ifdebug(ERROR) logger(LOG_NOTICE, "Error message from %s (%s): %d: %s",
c->name, c->hostname, err, errorstring);
terminate_connection(c, c->status.active);
@ -95,50 +81,32 @@ bool error_h(connection_t *c)
return true;
}
bool send_termreq(connection_t *c)
{
cp();
bool send_termreq(connection_t *c) {
return send_request(c, "%d", TERMREQ);
}
bool termreq_h(connection_t *c)
{
cp();
bool termreq_h(connection_t *c) {
terminate_connection(c, c->status.active);
return true;
}
bool send_ping(connection_t *c)
{
cp();
bool send_ping(connection_t *c) {
c->status.pinged = true;
c->last_ping_time = now;
return send_request(c, "%d", PING);
}
bool ping_h(connection_t *c)
{
cp();
bool ping_h(connection_t *c) {
return send_pong(c);
}
bool send_pong(connection_t *c)
{
cp();
bool send_pong(connection_t *c) {
return send_request(c, "%d", PONG);
}
bool pong_h(connection_t *c)
{
cp();
bool pong_h(connection_t *c) {
c->status.pinged = false;
/* Succesful connection, reset timeout if this is an outgoing connection. */
@ -151,13 +119,11 @@ bool pong_h(connection_t *c)
/* Sending and receiving packets via TCP */
bool send_tcppacket(connection_t *c, vpn_packet_t *packet)
{
cp();
bool send_tcppacket(connection_t *c, vpn_packet_t *packet) {
/* If there already is a lot of data in the outbuf buffer, discard this packet.
We use a very simple Random Early Drop algorithm. */
/* If there already is a lot of data in the outbuf buffer, discard this packet. */
if(c->outbuflen > maxoutbufsize)
if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
return true;
if(!send_request(c, "%d %hd", PACKET, packet->len))
@ -166,14 +132,11 @@ bool send_tcppacket(connection_t *c, vpn_packet_t *packet)
return send_meta(c, (char *)packet->data, packet->len);
}
bool tcppacket_h(connection_t *c)
{
bool tcppacket_h(connection_t *c) {
short int len;
cp();
if(sscanf(c->buffer, "%*d %hd", &len) != 1) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "PACKET", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name,
c->hostname);
return false;
}

View file

@ -1,7 +1,8 @@
/*
protocol_subnet.c -- handle the meta-protocol, subnets
Copyright (C) 1999-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2009 Michael Tokarev <mjt@tls.msk.ru>
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
@ -13,11 +14,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_subnet.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -33,46 +32,40 @@
#include "utils.h"
#include "xalloc.h"
bool send_add_subnet(connection_t *c, const subnet_t *subnet)
{
bool send_add_subnet(connection_t *c, const subnet_t *subnet) {
char netstr[MAXNETSTR];
cp();
if(!net2str(netstr, sizeof netstr, subnet))
return false;
return send_request(c, "%d %lx %s %s", ADD_SUBNET, random(), subnet->owner->name, netstr);
return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr);
}
bool add_subnet_h(connection_t *c)
{
bool add_subnet_h(connection_t *c) {
char subnetstr[MAX_STRING_SIZE];
char name[MAX_STRING_SIZE];
node_t *owner;
subnet_t s = {0}, *new;
cp();
if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
c->hostname);
return false;
}
/* Check if owner name is a valid */
/* Check if owner name is valid */
if(!check_id(name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
c->hostname, _("invalid name"));
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
c->hostname, "invalid name");
return false;
}
/* Check if subnet string is valid */
if(!str2net(&s, subnetstr)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
c->hostname, _("invalid subnet string"));
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
c->hostname, "invalid subnet string");
return false;
}
@ -83,15 +76,19 @@ bool add_subnet_h(connection_t *c)
owner = lookup_node(name);
if(tunnelserver && owner != myself && owner != c->node) {
/* in case of tunnelserver, ignore indirect subnet registrations */
ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
"ADD_SUBNET", c->name, c->hostname, subnetstr);
return true;
}
if(!owner) {
owner = new_node();
owner->name = xstrdup(name);
node_add(owner);
}
if(tunnelserver && owner != myself && owner != c->node)
return false;
/* Check if we already know this subnet */
if(lookup_subnet(owner, &s))
@ -100,7 +97,7 @@ bool add_subnet_h(connection_t *c)
/* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
if(owner == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"ADD_SUBNET", c->name, c->hostname);
s.owner = myself;
send_del_subnet(c, &s);
@ -115,7 +112,7 @@ bool add_subnet_h(connection_t *c)
for(cfg = lookup_config(c->config_tree, "Subnet"); cfg; cfg = lookup_config_next(c->config_tree, cfg)) {
if(!get_config_subnet(cfg, &allowed))
return false;
continue;
if(!subnet_compare(&s, allowed))
break;
@ -123,8 +120,11 @@ bool add_subnet_h(connection_t *c)
free_subnet(allowed);
}
if(!cfg)
return false;
if(!cfg) {
logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
"ADD_SUBNET", c->name, c->hostname, subnetstr);
return true;
}
free_subnet(allowed);
}
@ -145,65 +145,63 @@ bool add_subnet_h(connection_t *c)
return true;
}
bool send_del_subnet(connection_t *c, const subnet_t *s)
{
bool send_del_subnet(connection_t *c, const subnet_t *s) {
char netstr[MAXNETSTR];
cp();
if(!net2str(netstr, sizeof netstr, s))
return false;
return send_request(c, "%d %lx %s %s", DEL_SUBNET, random(), s->owner->name, netstr);
return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr);
}
bool del_subnet_h(connection_t *c)
{
bool del_subnet_h(connection_t *c) {
char subnetstr[MAX_STRING_SIZE];
char name[MAX_STRING_SIZE];
node_t *owner;
subnet_t s = {0}, *find;
cp();
if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name,
logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name,
c->hostname);
return false;
}
/* Check if owner name is a valid */
/* Check if owner name is valid */
if(!check_id(name)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
c->hostname, _("invalid name"));
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
c->hostname, "invalid name");
return false;
}
/* Check if the owner of the new subnet is in the connection list */
owner = lookup_node(name);
if(!owner) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
"DEL_SUBNET", c->name, c->hostname, name);
return true;
}
if(tunnelserver && owner != myself && owner != c->node)
return false;
/* Check if subnet string is valid */
if(!str2net(&s, subnetstr)) {
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
c->hostname, _("invalid subnet string"));
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
c->hostname, "invalid subnet string");
return false;
}
if(seen_request(c->buffer))
return true;
/* Check if the owner of the subnet being deleted is in the connection list */
owner = lookup_node(name);
if(tunnelserver && owner != myself && owner != c->node) {
/* in case of tunnelserver, ignore indirect subnet deletion */
ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
"DEL_SUBNET", c->name, c->hostname, subnetstr);
return true;
}
if(!owner) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree",
"DEL_SUBNET", c->name, c->hostname, name);
return true;
}
/* If everything is correct, delete the subnet from the list of the owner */
s.owner = owner;
@ -211,7 +209,7 @@ bool del_subnet_h(connection_t *c)
find = lookup_subnet(owner, &s);
if(!find) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree",
"DEL_SUBNET", c->name, c->hostname, name);
return true;
}
@ -219,7 +217,7 @@ bool del_subnet_h(connection_t *c)
/* If we are the owner of this subnet, retaliate with an ADD_SUBNET */
if(owner == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"DEL_SUBNET", c->name, c->hostname);
send_add_subnet(c, find);
return true;

View file

@ -1,7 +1,7 @@
/*
device.c -- raw socket
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2006 Guus Sliepen <guus@tinc-vpn.org>
2002-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1452 2006-04-26 13:52:58Z guus $
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"
@ -29,34 +27,31 @@
#include "logger.h"
#include "utils.h"
#include "route.h"
#include "xalloc.h"
int device_fd = -1;
char *device;
char *iface;
char ifrname[IFNAMSIZ];
char *device_info;
char *device = NULL;
char *iface = NULL;
static char ifrname[IFNAMSIZ];
static char *device_info;
static int device_total_in = 0;
static int device_total_out = 0;
bool setup_device(void)
{
bool setup_device(void) {
struct ifreq ifr;
struct sockaddr_ll sa;
cp();
if(!get_config_string
(lookup_config(config_tree, "Interface"), &iface))
iface = "eth0";
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
iface = xstrdup("eth0");
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = iface;
device = xstrdup(iface);
device_info = _("raw socket");
device_info = "raw socket";
if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
logger(LOG_ERR, _("Could not open %s: %s"), device_info,
logger(LOG_ERR, "Could not open %s: %s", device_info,
strerror(errno));
return false;
}
@ -65,7 +60,7 @@ bool setup_device(void)
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
close(device_fd);
logger(LOG_ERR, _("Can't find interface %s: %s"), iface,
logger(LOG_ERR, "Can't find interface %s: %s", iface,
strerror(errno));
return false;
}
@ -76,30 +71,27 @@ bool setup_device(void)
sa.sll_ifindex = ifr.ifr_ifindex;
if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) {
logger(LOG_ERR, _("Could not bind %s to %s: %s"), device, iface, strerror(errno));
logger(LOG_ERR, "Could not bind %s to %s: %s", device, iface, strerror(errno));
return false;
}
logger(LOG_INFO, _("%s is a %s"), device, device_info);
logger(LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -108,21 +100,18 @@ bool read_packet(vpn_packet_t *packet)
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
@ -132,11 +121,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

View file

@ -1,7 +1,7 @@
/*
route.c -- routing
Copyright (C) 2000-2005 Ivo Timmermans,
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: route.c 1601 2008-12-26 12:46:45Z guus $
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"
@ -53,8 +51,7 @@ static const size_t opt_size = sizeof(struct nd_opt_hdr);
/* RFC 1071 */
static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
{
static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
uint16_t *p = data;
uint32_t checksum = prevsum ^ 0xFFFF;
@ -89,26 +86,30 @@ static bool ratelimit(int frequency) {
static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
if(packet->len < length) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got too short packet from %s (%s)"), source->name, source->hostname);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got too short packet from %s (%s)", source->name, source->hostname);
return false;
} else
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);
}
static void learn_mac(mac_t *address)
{
static void learn_mac(mac_t *address) {
subnet_t *subnet;
avl_node_t *node;
connection_t *c;
cp();
subnet = lookup_subnet_mac(address);
/* If we don't know this MAC address yet, store it */
if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
ifdebug(TRAFFIC) logger(LOG_INFO, "Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx",
address->x[0], address->x[1], address->x[2], address->x[3],
address->x[4], address->x[5]);
@ -131,14 +132,11 @@ static void learn_mac(mac_t *address)
subnet->expires = now + macexpire;
}
void age_subnets(void)
{
void age_subnets(void) {
subnet_t *s;
connection_t *c;
avl_node_t *node, *next, *node2;
cp();
for(node = myself->subnet_tree->head; node; node = next) {
next = node->next;
s = node->data;
@ -146,7 +144,7 @@ void age_subnets(void)
ifdebug(TRAFFIC) {
char netstr[MAXNETSTR];
if(net2str(netstr, sizeof netstr, s))
logger(LOG_INFO, _("Subnet %s expired"), netstr);
logger(LOG_INFO, "Subnet %s expired", netstr);
}
for(node2 = connection_tree->head; node2; node2 = node2->next) {
@ -160,44 +158,9 @@ void age_subnets(void)
}
}
static void route_mac(node_t *source, vpn_packet_t *packet)
{
subnet_t *subnet;
mac_t dest;
cp();
/* Learn source address */
if(source == myself) {
mac_t src;
memcpy(&src, &packet->data[6], sizeof src);
learn_mac(&src);
}
/* Lookup destination address */
memcpy(&dest, &packet->data[0], sizeof dest);
subnet = lookup_subnet_mac(&dest);
if(!subnet) {
broadcast_packet(source, packet);
return;
}
if(subnet->owner == source) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
return;
}
send_packet(subnet->owner, packet);
}
/* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
{
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
struct ip ip = {0};
struct icmp icmp = {0};
@ -208,7 +171,9 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
if(ratelimit(3))
return;
cp();
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet into properly aligned structs on the stack */
@ -275,8 +240,6 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) {
uint8_t *offset;
uint16_t ip_off, origf;
cp();
memcpy(&ip, packet->data + ether_size, ip_size);
fragment.priority = packet->priority;
@ -286,11 +249,11 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) {
todo = ntohs(ip.ip_len) - ip_size;
if(ether_size + ip_size + todo != packet->len) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Length of packet (%d) doesn't match length in IPv4 header (%zd)"), packet->len, ether_size + ip_size + todo);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%zd)", packet->len, ether_size + ip_size + todo);
return;
}
ifdebug(TRAFFIC) logger(LOG_INFO, _("Fragmenting packet of %d bytes to %s (%s)"), packet->len, dest->name, dest->hostname);
ifdebug(TRAFFIC) logger(LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname);
offset = packet->data + ether_size + ip_size;
maxlen = (dest->mtu - ether_size - ip_size) & ~0x7;
@ -318,19 +281,16 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) {
}
}
static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
{
static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
subnet_t *subnet;
node_t *via;
ipv4_t dest;
cp();
memcpy(&dest, &packet->data[30], sizeof dest);
subnet = lookup_subnet_ipv4(&dest);
if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d"),
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d",
source->name, source->hostname,
dest.x[0],
dest.x[1],
@ -342,7 +302,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
}
if(subnet->owner == source) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
return;
}
@ -355,7 +315,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via && packet->len > via->mtu && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
if(packet->data[20] & 0x40) {
packet->len = via->mtu;
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
@ -369,18 +329,15 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
send_packet(subnet->owner, packet);
}
static void route_ipv4(node_t *source, vpn_packet_t *packet)
{
cp();
static void route_ipv4(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size + ip_size))
return;
if(((packet->data[30] & 0xf0) == 0xe0) ||
if(((packet->data[30] & 0xf0) == 0xe0) || (
packet->data[30] == 255 &&
packet->data[31] == 255 &&
packet->data[32] == 255 &&
packet->data[33] == 255)
packet->data[33] == 255))
broadcast_packet(source, packet);
else
route_ipv4_unicast(source, packet);
@ -388,8 +345,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet)
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
{
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
uint16_t checksum;
@ -404,7 +360,9 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
if(ratelimit(3))
return;
cp();
/* Swap Ethernet source and destination addresses */
swap_mac_addresses(packet);
/* Copy headers from packet to structs on the stack */
@ -465,19 +423,16 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
send_packet(source, packet);
}
static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
{
static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
subnet_t *subnet;
node_t *via;
ipv6_t dest;
cp();
memcpy(&dest, &packet->data[38], sizeof dest);
subnet = lookup_subnet_ipv6(&dest);
if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
source->name, source->hostname,
ntohs(dest.x[0]),
ntohs(dest.x[1]),
@ -493,7 +448,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
}
if(subnet->owner == source) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
return;
}
@ -503,7 +458,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via && packet->len > via->mtu && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
packet->len = via->mtu;
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
return;
@ -514,13 +469,13 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
/* RFC 2461 */
static void route_neighborsol(node_t *source, vpn_packet_t *packet)
{
static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
struct ip6_hdr ip6;
struct nd_neighbor_solicit ns;
struct nd_opt_hdr opt;
subnet_t *subnet;
uint16_t checksum;
bool has_opt;
struct {
struct in6_addr ip6_src; /* source address */
@ -529,13 +484,13 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
uint32_t next;
} pseudo;
cp();
if(!checklength(source, packet, ether_size + ip6_size + ns_size + opt_size + ETH_ALEN))
if(!checklength(source, packet, ether_size + ip6_size + ns_size))
return;
has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN;
if(source != myself) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got neighbor solicitation request from %s (%s) while in router mode!"), source->name, source->hostname);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got neighbor solicitation request from %s (%s) while in router mode!", source->name, source->hostname);
return;
}
@ -543,7 +498,8 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
memcpy(&ip6, packet->data + ether_size, ip6_size);
memcpy(&ns, packet->data + ether_size + ip6_size, ns_size);
memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size);
if(has_opt)
memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size);
/* First, snatch the source address from the neighbor solicitation packet */
@ -553,8 +509,8 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
/* Check if this is a valid neighbor solicitation request */
if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
(has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request");
return;
}
@ -562,18 +518,23 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
pseudo.ip6_src = ip6.ip6_src;
pseudo.ip6_dst = ip6.ip6_dst;
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
if(has_opt)
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
else
pseudo.length = htonl(ns_size);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
checksum = inet_checksum(&ns, ns_size, checksum);
checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
}
if(checksum) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: checksum error for neighbor solicitation request");
return;
}
@ -582,7 +543,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
subnet = lookup_subnet_ipv6((ipv6_t *) &ns.nd_ns_target);
if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
ntohs(((uint16_t *) &ns.nd_ns_target)[0]),
ntohs(((uint16_t *) &ns.nd_ns_target)[1]),
ntohs(((uint16_t *) &ns.nd_ns_target)[2]),
@ -608,7 +569,8 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */
ip6.ip6_src = ns.nd_ns_target;
memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
if(has_opt)
memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
ns.nd_ns_cksum = 0;
ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
@ -619,15 +581,20 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
pseudo.ip6_src = ip6.ip6_src;
pseudo.ip6_dst = ip6.ip6_dst;
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
if(has_opt)
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
else
pseudo.length = htonl(ns_size);
pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
checksum = inet_checksum(&ns, ns_size, checksum);
checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
}
ns.nd_ns_hdr.icmp6_cksum = checksum;
@ -635,15 +602,13 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet)
memcpy(packet->data + ether_size, &ip6, ip6_size);
memcpy(packet->data + ether_size + ip6_size, &ns, ns_size);
memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
if(has_opt)
memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
send_packet(source, packet);
}
static void route_ipv6(node_t *source, vpn_packet_t *packet)
{
cp();
static void route_ipv6(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size + ip6_size))
return;
@ -660,19 +625,16 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet)
/* RFC 826 */
static void route_arp(node_t *source, vpn_packet_t *packet)
{
static void route_arp(node_t *source, vpn_packet_t *packet) {
struct ether_arp arp;
subnet_t *subnet;
struct in_addr addr;
cp();
if(!checklength(source, packet, ether_size + arp_size))
return;
if(source != myself) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got ARP request from %s (%s) while in router mode!"), source->name, source->hostname);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname);
return;
}
@ -689,7 +651,7 @@ static void route_arp(node_t *source, vpn_packet_t *packet)
if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request");
return;
}
@ -698,7 +660,7 @@ static void route_arp(node_t *source, vpn_packet_t *packet)
subnet = lookup_subnet_ipv4((ipv4_t *) &arp.arp_tpa);
if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d",
arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2],
arp.arp_tpa[3]);
return;
@ -727,19 +689,67 @@ static void route_arp(node_t *source, vpn_packet_t *packet)
send_packet(source, packet);
}
void route(node_t *source, vpn_packet_t *packet)
{
cp();
static void route_mac(node_t *source, vpn_packet_t *packet) {
subnet_t *subnet;
mac_t dest;
/* Learn source address */
if(source == myself) {
mac_t src;
memcpy(&src, &packet->data[6], sizeof src);
learn_mac(&src);
}
/* Lookup destination address */
memcpy(&dest, &packet->data[0], sizeof dest);
subnet = lookup_subnet_mac(&dest);
if(!subnet) {
broadcast_packet(source, packet);
return;
}
if(subnet->owner == source) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
return;
}
// Handle packets larger than PMTU
node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(via && packet->len > via->mtu && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
uint16_t type = packet->data[12] << 8 | packet->data[13];
if(type == ETH_P_IP) {
if(packet->data[20] & 0x40) {
packet->len = via->mtu;
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
} else {
fragment_ipv4_packet(via, packet);
}
return;
} else if(type == ETH_P_IPV6) {
packet->len = via->mtu;
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
return;
}
}
send_packet(subnet->owner, packet);
}
void route(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size))
return;
switch (routing_mode) {
case RMODE_ROUTER:
{
uint16_t type;
uint16_t type = packet->data[12] << 8 | packet->data[13];
type = ntohs(*((uint16_t *)(&packet->data[12])));
switch (type) {
case ETH_P_ARP:
route_arp(source, packet);
@ -754,7 +764,7 @@ void route(node_t *source, vpn_packet_t *packet)
break;
default:
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown type %hx"), source->name, source->hostname, type);
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type);
break;
}
}

View file

@ -1,6 +1,6 @@
/*
route.h -- header file for route.c
Copyright (C) 2000-2005 Ivo Timmermans <zarq@iname.com>
Copyright (C) 2000-2005 Ivo Timmermans
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: route.h 1452 2006-04-26 13:52:58Z guus $
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_ROUTE_H__

View file

@ -1,7 +1,7 @@
/*
device.c -- Interaction with Solaris tun device
Copyright (C) 2001-2005 Ivo Timmermans,
2001-2006 Guus Sliepen <guus@tinc-vpn.org>
2001-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1452 2006-04-26 13:52:58Z guus $
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.
*/
@ -31,30 +29,28 @@
#include "logger.h"
#include "net.h"
#include "utils.h"
#include "xalloc.h"
#define DEFAULT_DEVICE "/dev/tun"
int device_fd = -1;
char *device = NULL;
char *iface = NULL;
char *device_info = NULL;
static char *device_info = NULL;
static int device_total_in = 0;
static int device_total_out = 0;
bool setup_device(void)
{
bool setup_device(void) {
int ip_fd = -1, if_fd = -1;
int ppa;
char *ptr;
cp();
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
device = DEFAULT_DEVICE;
device = xstrdup(DEFAULT_DEVICE);
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
return false;
}
@ -66,63 +62,60 @@ bool setup_device(void)
ppa = atoi(ptr);
if((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
logger(LOG_ERR, _("Could not open /dev/ip: %s"), strerror(errno));
logger(LOG_ERR, "Could not open /dev/ip: %s", strerror(errno));
return false;
}
/* Assign a new PPA and get its unit number. */
if((ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0) {
logger(LOG_ERR, _("Can't assign new interface: %s"), strerror(errno));
logger(LOG_ERR, "Can't assign new interface: %s", strerror(errno));
return false;
}
if((if_fd = open(device, O_RDWR, 0)) < 0) {
logger(LOG_ERR, _("Could not open %s twice: %s"), device,
logger(LOG_ERR, "Could not open %s twice: %s", device,
strerror(errno));
return false;
}
if(ioctl(if_fd, I_PUSH, "ip") < 0) {
logger(LOG_ERR, _("Can't push IP module: %s"), strerror(errno));
logger(LOG_ERR, "Can't push IP module: %s", strerror(errno));
return false;
}
/* Assign ppa according to the unit number returned by tun device */
if(ioctl(if_fd, IF_UNITSEL, (char *) &ppa) < 0) {
logger(LOG_ERR, _("Can't set PPA %d: %s"), ppa, strerror(errno));
logger(LOG_ERR, "Can't set PPA %d: %s", ppa, strerror(errno));
return false;
}
if(ioctl(ip_fd, I_LINK, if_fd) < 0) {
logger(LOG_ERR, _("Can't link TUN device to IP: %s"), strerror(errno));
logger(LOG_ERR, "Can't link TUN device to IP: %s", strerror(errno));
return false;
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
asprintf(&iface, "tun%d", ppa);
xasprintf(&iface, "tun%d", ppa);
device_info = _("Solaris tun device");
device_info = "Solaris tun device";
logger(LOG_INFO, _("%s is a %s"), device, device_info);
logger(LOG_INFO, "%s is a %s", device, device_info);
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
close(device_fd);
free(device);
free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -138,7 +131,7 @@ bool read_packet(vpn_packet_t *packet)
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
_ ("Unknown IP version %d while reading packet from %s %s"),
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
@ -147,21 +140,18 @@ bool read_packet(vpn_packet_t *packet)
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
}
bool write_packet(vpn_packet_t *packet)
{
cp();
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info,
logger(LOG_ERR, "Can't write to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
@ -171,11 +161,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}

View file

@ -1,6 +1,6 @@
/*
subnet.c -- handle subnet lookups and lists
Copyright (C) 2000-2007 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: subnet.c 1595 2008-12-22 20:27:52Z guus $
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"
@ -37,30 +35,55 @@
avl_tree_t *subnet_tree;
/* Subnet lookup cache */
static ipv4_t cache_ipv4_address[2];
static subnet_t *cache_ipv4_subnet[2];
static bool cache_ipv4_valid[2];
static int cache_ipv4_slot;
static ipv6_t cache_ipv6_address[2];
static subnet_t *cache_ipv6_subnet[2];
static bool cache_ipv6_valid[2];
static int cache_ipv6_slot;
void subnet_cache_flush() {
cache_ipv4_valid[0] = cache_ipv4_valid[1] = false;
cache_ipv6_valid[0] = cache_ipv6_valid[1] = false;
}
/* Subnet comparison */
static int subnet_compare_mac(const subnet_t *a, const subnet_t *b)
{
static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
int result;
result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
if(result)
return result;
result = a->weight - b->weight;
if(result || !a->owner || !b->owner)
return result;
return strcmp(a->owner->name, b->owner->name);
}
static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b)
{
static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
int result;
result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength;
if(result)
return result;
result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
if(result)
return result;
result = a->net.ipv4.prefixlength - b->net.ipv4.prefixlength;
result = a->weight - b->weight;
if(result || !a->owner || !b->owner)
return result;
@ -68,16 +91,20 @@ static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b)
return strcmp(a->owner->name, b->owner->name);
}
static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b)
{
static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
int result;
result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength;
if(result)
return result;
result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
if(result)
return result;
result = a->net.ipv6.prefixlength - b->net.ipv6.prefixlength;
result = a->weight - b->weight;
if(result || !a->owner || !b->owner)
return result;
@ -85,8 +112,7 @@ static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b)
return strcmp(a->owner->name, b->owner->name);
}
int subnet_compare(const subnet_t *a, const subnet_t *b)
{
int subnet_compare(const subnet_t *a, const subnet_t *b) {
int result;
result = a->type - b->type;
@ -102,9 +128,8 @@ int subnet_compare(const subnet_t *a, const subnet_t *b)
case SUBNET_IPV6:
return subnet_compare_ipv6(a, b);
default:
logger(LOG_ERR, _("subnet_compare() was called with unknown subnet type %d, exitting!"),
logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!",
a->type);
cp_trace();
exit(0);
}
@ -113,86 +138,67 @@ int subnet_compare(const subnet_t *a, const subnet_t *b)
/* Initialising trees */
void init_subnets(void)
{
cp();
void init_subnets(void) {
subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
subnet_cache_flush();
}
void exit_subnets(void)
{
cp();
void exit_subnets(void) {
avl_delete_tree(subnet_tree);
}
avl_tree_t *new_subnet_tree(void)
{
cp();
avl_tree_t *new_subnet_tree(void) {
return avl_alloc_tree((avl_compare_t) subnet_compare, NULL);
}
void free_subnet_tree(avl_tree_t *subnet_tree)
{
cp();
void free_subnet_tree(avl_tree_t *subnet_tree) {
avl_delete_tree(subnet_tree);
}
/* Allocating and freeing space for subnets */
subnet_t *new_subnet(void)
{
cp();
subnet_t *new_subnet(void) {
return xmalloc_and_zero(sizeof(subnet_t));
}
void free_subnet(subnet_t *subnet)
{
cp();
void free_subnet(subnet_t *subnet) {
free(subnet);
}
/* Adding and removing subnets */
void subnet_add(node_t *n, subnet_t *subnet)
{
cp();
void subnet_add(node_t *n, subnet_t *subnet) {
subnet->owner = n;
avl_insert(subnet_tree, subnet);
avl_insert(n->subnet_tree, subnet);
subnet_cache_flush();
}
void subnet_del(node_t *n, subnet_t *subnet)
{
cp();
void subnet_del(node_t *n, subnet_t *subnet) {
avl_delete(n->subnet_tree, subnet);
avl_delete(subnet_tree, subnet);
subnet_cache_flush();
}
/* Ascii representation of subnets */
bool str2net(subnet_t *subnet, const char *subnetstr)
{
bool str2net(subnet_t *subnet, const char *subnetstr) {
int i, l;
uint16_t x[8];
int weight = 10;
cp();
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
&x[0], &x[1], &x[2], &x[3], &l) == 5) {
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
&x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
if(l < 0 || l > 32)
return false;
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.prefixlength = l;
subnet->weight = weight;
for(i = 0; i < 4; i++) {
if(x[i] > 255)
@ -203,14 +209,15 @@ bool str2net(subnet_t *subnet, const char *subnetstr)
return true;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
&l) == 9) {
&l, &weight) >= 9) {
if(l < 0 || l > 128)
return false;
subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = l;
subnet->weight = weight;
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
@ -218,9 +225,10 @@ bool str2net(subnet_t *subnet, const char *subnetstr)
return true;
}
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu", &x[0], &x[1], &x[2], &x[3]) == 4) {
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu#%d", &x[0], &x[1], &x[2], &x[3], &weight) >= 4) {
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.prefixlength = 32;
subnet->weight = weight;
for(i = 0; i < 4; i++) {
if(x[i] > 255)
@ -231,10 +239,11 @@ bool str2net(subnet_t *subnet, const char *subnetstr)
return true;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8) {
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) {
subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = 128;
subnet->weight = weight;
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
@ -242,9 +251,10 @@ bool str2net(subnet_t *subnet, const char *subnetstr)
return true;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6) {
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) {
subnet->type = SUBNET_MAC;
subnet->weight = weight;
for(i = 0; i < 6; i++)
subnet->net.mac.address.x[i] = x[i];
@ -255,35 +265,36 @@ bool str2net(subnet_t *subnet, const char *subnetstr)
return false;
}
bool net2str(char *netstr, int len, const subnet_t *subnet)
{
cp();
bool net2str(char *netstr, int len, const subnet_t *subnet) {
if(!netstr || !subnet) {
logger(LOG_ERR, _("net2str() was called with netstr=%p, subnet=%p!\n"), netstr, subnet);
logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!\n", netstr, subnet);
return false;
}
switch (subnet->type) {
case SUBNET_MAC:
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx",
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
subnet->net.mac.address.x[0],
subnet->net.mac.address.x[1],
subnet->net.mac.address.x[2],
subnet->net.mac.address.x[3],
subnet->net.mac.address.x[4], subnet->net.mac.address.x[5]);
subnet->net.mac.address.x[4],
subnet->net.mac.address.x[5],
subnet->weight);
break;
case SUBNET_IPV4:
snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d",
snprintf(netstr, len, "%hu.%hu.%hu.%hu/%d#%d",
subnet->net.ipv4.address.x[0],
subnet->net.ipv4.address.x[1],
subnet->net.ipv4.address.x[2],
subnet->net.ipv4.address.x[3], subnet->net.ipv4.prefixlength);
subnet->net.ipv4.address.x[3],
subnet->net.ipv4.prefixlength,
subnet->weight);
break;
case SUBNET_IPV6:
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
snprintf(netstr, len, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
ntohs(subnet->net.ipv6.address.x[0]),
ntohs(subnet->net.ipv6.address.x[1]),
ntohs(subnet->net.ipv6.address.x[2]),
@ -292,14 +303,14 @@ bool net2str(char *netstr, int len, const subnet_t *subnet)
ntohs(subnet->net.ipv6.address.x[5]),
ntohs(subnet->net.ipv6.address.x[6]),
ntohs(subnet->net.ipv6.address.x[7]),
subnet->net.ipv6.prefixlength);
subnet->net.ipv6.prefixlength,
subnet->weight);
break;
default:
logger(LOG_ERR,
_("net2str() was called with unknown subnet type %d, exiting!"),
"net2str() was called with unknown subnet type %d, exiting!",
subnet->type);
cp_trace();
exit(0);
}
@ -308,19 +319,13 @@ bool net2str(char *netstr, int len, const subnet_t *subnet)
/* Subnet lookup routines */
subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet)
{
cp();
subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
return avl_search(owner->subnet_tree, subnet);
}
subnet_t *lookup_subnet_mac(const mac_t *address)
{
subnet_t *lookup_subnet_mac(const mac_t *address) {
subnet_t *p, subnet = {0};
cp();
subnet.type = SUBNET_MAC;
subnet.net.mac.address = *address;
subnet.owner = NULL;
@ -330,105 +335,114 @@ subnet_t *lookup_subnet_mac(const mac_t *address)
return p;
}
subnet_t *lookup_subnet_ipv4(const ipv4_t *address)
{
subnet_t *p, subnet = {0};
subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
subnet_t *p, *r = NULL, subnet = {0};
avl_node_t *n;
int i;
cp();
// Check if this address is cached
for(i = 0; i < 2; i++) {
if(!cache_ipv4_valid[i])
continue;
if(!memcmp(address, &cache_ipv4_address[i], sizeof *address))
return cache_ipv4_subnet[i];
}
// Search all subnets for a matching one
subnet.type = SUBNET_IPV4;
subnet.net.ipv4.address = *address;
subnet.net.ipv4.prefixlength = 32;
subnet.owner = NULL;
do {
/* Go find subnet */
for(n = subnet_tree->head; n; n = n->next) {
p = n->data;
if(!p || p->type != subnet.type)
continue;
p = avl_search_closest_smaller(subnet_tree, &subnet);
/* Check if the found subnet REALLY matches */
if(p) {
if(p->type != SUBNET_IPV4) {
p = NULL;
if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
r = p;
if(p->owner->status.reachable)
break;
}
if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength))
break;
else {
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv4.prefixlength = p->net.ipv4.prefixlength - 1;
if(subnet.net.ipv4.prefixlength < 0 || subnet.net.ipv4.prefixlength > 32)
return NULL;
maskcpy(&subnet.net.ipv4.address, &p->net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t));
}
}
} while(p);
}
return p;
// Cache the result
cache_ipv4_slot = !cache_ipv4_slot;
memcpy(&cache_ipv4_address[cache_ipv4_slot], address, sizeof *address);
cache_ipv4_subnet[cache_ipv4_slot] = r;
cache_ipv4_valid[cache_ipv4_slot] = true;
return r;
}
subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
{
subnet_t *p, subnet = {0};
subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
subnet_t *p, *r = NULL, subnet = {0};
avl_node_t *n;
int i;
cp();
// Check if this address is cached
for(i = 0; i < 2; i++) {
if(!cache_ipv6_valid[i])
continue;
if(!memcmp(address, &cache_ipv6_address[i], sizeof *address))
return cache_ipv6_subnet[i];
}
// Search all subnets for a matching one
subnet.type = SUBNET_IPV6;
subnet.net.ipv6.address = *address;
subnet.net.ipv6.prefixlength = 128;
subnet.owner = NULL;
do {
/* Go find subnet */
for(n = subnet_tree->head; n; n = n->next) {
p = n->data;
if(!p || p->type != subnet.type)
continue;
p = avl_search_closest_smaller(subnet_tree, &subnet);
/* Check if the found subnet REALLY matches */
if(p) {
if(p->type != SUBNET_IPV6)
return NULL;
if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength))
if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
r = p;
if(p->owner->status.reachable)
break;
else {
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv6.prefixlength = p->net.ipv6.prefixlength - 1;
if(subnet.net.ipv6.prefixlength < 0 || subnet.net.ipv6.prefixlength > 128)
return NULL;
maskcpy(&subnet.net.ipv6.address, &p->net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t));
}
}
} while(p);
}
return p;
// Cache the result
cache_ipv6_slot = !cache_ipv6_slot;
memcpy(&cache_ipv6_address[cache_ipv6_slot], address, sizeof *address);
cache_ipv6_subnet[cache_ipv6_slot] = r;
cache_ipv6_valid[cache_ipv6_slot] = true;
return r;
}
void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
avl_node_t *node;
int i;
char *envp[8];
char netstr[MAXNETSTR + 7] = "SUBNET=";
char *envp[9] = {0};
char netstr[MAXNETSTR];
char *name, *address, *port;
char empty[] = "";
asprintf(&envp[0], "NETNAME=%s", netname ? : "");
asprintf(&envp[1], "DEVICE=%s", device ? : "");
asprintf(&envp[2], "INTERFACE=%s", iface ? : "");
asprintf(&envp[3], "NODE=%s", owner->name);
// Prepare environment variables to be passed to the script
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
xasprintf(&envp[3], "NODE=%s", owner->name);
if(owner != myself) {
sockaddr2str(&owner->address, &address, &port);
asprintf(&envp[4], "REMOTEADDRESS=%s", address);
asprintf(&envp[5], "REMOTEPORT=%s", port);
envp[6] = netstr;
envp[7] = NULL;
} else {
envp[4] = netstr;
envp[5] = NULL;
// 4 and 5 are reserved for SUBNET and WEIGHT
xasprintf(&envp[6], "REMOTEADDRESS=%s", address);
xasprintf(&envp[7], "REMOTEPORT=%s", port);
}
name = up ? "subnet-up" : "subnet-down";
@ -436,40 +450,59 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
if(!subnet) {
for(node = owner->subnet_tree->head; node; node = node->next) {
subnet = node->data;
if(!net2str(netstr + 7, sizeof netstr - 7, subnet))
if(!net2str(netstr, sizeof netstr, subnet))
continue;
// Strip the weight from the subnet, and put it in its own environment variable
char *weight = strchr(netstr + 7, '#');
if(weight)
*weight++ = 0;
else
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);
execute_script(name, envp);
}
} else {
if(net2str(netstr + 7, sizeof netstr - 7, subnet))
if(net2str(netstr + 7, sizeof netstr - 7, subnet)) {
// Strip the weight from the subnet, and put it in its own environment variable
char *weight = strchr(netstr + 7, '#');
if(weight)
*weight++ = 0;
else
weight = empty;
// Prepare the SUBNET and WEIGHT variables
xasprintf(&envp[4], "SUBNET=%s", netstr);
xasprintf(&envp[5], "WEIGHT=%s", weight);
execute_script(name, envp);
}
}
for(i = 0; i < (owner != myself ? 6 : 4); i++)
for(i = 0; envp[i] && i < 9; i++)
free(envp[i]);
if(owner != myself) {
free(address);
free(port);
}
}
void dump_subnets(void)
{
void dump_subnets(void) {
char netstr[MAXNETSTR];
subnet_t *subnet;
avl_node_t *node;
cp();
logger(LOG_DEBUG, _("Subnet list:"));
logger(LOG_DEBUG, "Subnet list:");
for(node = subnet_tree->head; node; node = node->next) {
subnet = node->data;
if(!net2str(netstr, sizeof netstr, subnet))
continue;
logger(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name);
logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
}
logger(LOG_DEBUG, _("End of subnet list."));
logger(LOG_DEBUG, "End of subnet list.");
}

View file

@ -1,6 +1,6 @@
/*
subnet.h -- header for subnet.c
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
2000-2005 Ivo Timmermans
This program is free software; you can redistribute it and/or modify
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: subnet.h 1452 2006-04-26 13:52:58Z guus $
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_SUBNET_H__
@ -53,6 +51,7 @@ typedef struct subnet_t {
subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */
time_t expires; /* expiry time */
int weight; /* weight (higher value is higher priority) */
/* And now for the actual subnet: */
@ -82,5 +81,6 @@ extern subnet_t *lookup_subnet_mac(const mac_t *);
extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
extern void dump_subnets(void);
extern void subnet_cache_flush(void);
#endif /* __TINC_SUBNET_H__ */

View file

@ -1,7 +1,9 @@
/*
tincd.c -- the main file for tincd
Copyright (C) 1998-2005 Ivo Timmermans
2000-2008 Guus Sliepen <guus@tinc-vpn.org>
2000-2009 Guus Sliepen <guus@tinc-vpn.org>
2008 Max Rijevski <maksuf@gmail.com>
2009 Michael Tokarev <mjt@tls.msk.ru>
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
@ -13,11 +15,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: tincd.c 1600 2008-12-23 23:14:37Z guus $
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"
@ -39,6 +39,12 @@
#include LZO1X_H
#ifndef HAVE_MINGW
#include <pwd.h>
#include <grp.h>
#include <time.h>
#endif
#include <getopt.h>
#include "pidfile.h"
@ -73,6 +79,12 @@ bool bypass_security = false;
/* If nonzero, disable swapping for this process. */
bool do_mlock = false;
/* If nonzero, chroot to netdir after startup. */
static bool do_chroot = false;
/* If !NULL, do setuid to given user after startup */
static const char *switchuser = NULL;
/* If nonzero, write log entries to a separate file. */
bool use_logfile = false;
@ -94,6 +106,8 @@ static struct option const long_options[] = {
{"debug", optional_argument, NULL, 'd'},
{"bypass-security", no_argument, NULL, 3},
{"mlock", no_argument, NULL, 'L'},
{"chroot", no_argument, NULL, 'R'},
{"user", required_argument, NULL, 'U'},
{"logfile", optional_argument, NULL, 4},
{"pidfile", required_argument, NULL, 5},
{NULL, 0, NULL, 0}
@ -101,16 +115,16 @@ static struct option const long_options[] = {
#ifdef HAVE_MINGW
static struct WSAData wsa_state;
CRITICAL_SECTION mutex;
#endif
static void usage(bool status)
{
static void usage(bool status) {
if(status)
fprintf(stderr, _("Try `%s --help\' for more information.\n"),
fprintf(stderr, "Try `%s --help\' for more information.\n",
program_name);
else {
printf(_("Usage: %s [option]...\n\n"), program_name);
printf(_(" -c, --config=DIR Read configuration options from DIR.\n"
printf("Usage: %s [option]...\n\n", program_name);
printf(" -c, --config=DIR Read configuration options from DIR.\n"
" -D, --no-detach Don't fork and detach.\n"
" -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n"
" -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\n"
@ -119,18 +133,19 @@ static void usage(bool status)
" -L, --mlock Lock tinc into main memory.\n"
" --logfile[=FILENAME] Write log entries to a logfile.\n"
" --pidfile=FILENAME Write PID to FILENAME.\n"
" -R, --chroot chroot to NET dir at startup.\n"
" -U, --user=USER setuid to given USER at startup.\n"
" --help Display this help and exit.\n"
" --version Output version information and exit.\n\n"));
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
" --version Output version information and exit.\n\n");
printf("Report bugs to tinc@tinc-vpn.org.\n");
}
}
static bool parse_options(int argc, char **argv)
{
static bool parse_options(int argc, char **argv) {
int r;
int option_index = 0;
while((r = getopt_long(argc, argv, "c:DLd::k::n:K::", long_options, &option_index)) != EOF) {
while((r = getopt_long(argc, argv, "c:DLd::k::n:K::RU:", long_options, &option_index)) != EOF) {
switch (r) {
case 0: /* long option */
break;
@ -144,8 +159,13 @@ static bool parse_options(int argc, char **argv)
break;
case 'L': /* no detach */
#ifndef HAVE_MLOCKALL
logger(LOG_ERR, "%s not supported on this platform", "mlockall()");
return false;
#else
do_mlock = true;
break;
#endif
case 'd': /* inc debug level */
if(optarg)
@ -177,7 +197,7 @@ static bool parse_options(int argc, char **argv)
kill_tincd = atoi(optarg);
if(!kill_tincd) {
fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"),
fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n",
optarg);
usage(true);
return false;
@ -199,7 +219,7 @@ static bool parse_options(int argc, char **argv)
generate_keys = atoi(optarg);
if(generate_keys < 512) {
fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"),
fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n",
optarg);
usage(true);
return false;
@ -207,7 +227,15 @@ static bool parse_options(int argc, char **argv)
generate_keys &= ~7; /* Round it to bytes */
} else
generate_keys = 1024;
generate_keys = 2048;
break;
case 'R': /* chroot to NETNAME dir */
do_chroot = true;
break;
case 'U': /* setuid to USER */
switchuser = optarg;
break;
case 1: /* show help */
@ -246,8 +274,7 @@ static bool parse_options(int argc, char **argv)
/* This function prettyprints the key generation process */
static void indicator(int a, int b, void *p)
{
static void indicator(int a, int b, void *p) {
switch (a) {
case 0:
fprintf(stderr, ".");
@ -285,58 +312,64 @@ static void indicator(int a, int b, void *p)
Generate a public/private RSA keypair, and ask for a file to store
them in.
*/
static bool keygen(int bits)
{
static bool keygen(int bits) {
RSA *rsa_key;
FILE *f;
char *name = NULL;
char *filename;
fprintf(stderr, _("Generating %d bits keys:\n"), bits);
get_config_string(lookup_config(config_tree, "Name"), &name);
if(name && !check_id(name)) {
fprintf(stderr, "Invalid name for myself!\n");
return false;
}
fprintf(stderr, "Generating %d bits keys:\n", bits);
rsa_key = RSA_generate_key(bits, 0x10001, indicator, NULL);
if(!rsa_key) {
fprintf(stderr, _("Error during key generation!\n"));
fprintf(stderr, "Error during key generation!\n");
return false;
} else
fprintf(stderr, _("Done.\n"));
fprintf(stderr, "Done.\n");
asprintf(&filename, "%s/rsa_key.priv", confbase);
f = ask_and_open(filename, _("private RSA key"), "a");
xasprintf(&filename, "%s/rsa_key.priv", confbase);
f = ask_and_open(filename, "private RSA key");
if(!f)
return false;
if(disable_old_keys(f))
fprintf(stderr, "Warning: old key(s) found and disabled.\n");
#ifdef HAVE_FCHMOD
/* Make it unreadable for others. */
fchmod(fileno(f), 0600);
#endif
if(ftell(f))
fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL);
fclose(f);
free(filename);
get_config_string(lookup_config(config_tree, "Name"), &name);
if(name)
asprintf(&filename, "%s/hosts/%s", confbase, name);
xasprintf(&filename, "%s/hosts/%s", confbase, name);
else
asprintf(&filename, "%s/rsa_key.pub", confbase);
xasprintf(&filename, "%s/rsa_key.pub", confbase);
f = ask_and_open(filename, _("public RSA key"), "a");
f = ask_and_open(filename, "public RSA key");
if(!f)
return false;
if(ftell(f))
fprintf(stderr, _("Appending key to existing contents.\nMake sure only one key is stored in the file.\n"));
if(disable_old_keys(f))
fprintf(stderr, "Warning: old key(s) found and disabled.\n");
PEM_write_RSAPublicKey(f, rsa_key);
fclose(f);
free(filename);
if(name)
free(name);
return true;
}
@ -344,8 +377,7 @@ static bool keygen(int bits)
/*
Set all files and paths according to netname
*/
static void make_names(void)
{
static void make_names(void) {
#ifdef HAVE_MINGW
HKEY key;
char installdir[1024] = "";
@ -353,7 +385,7 @@ static void make_names(void)
#endif
if(netname)
asprintf(&identname, "tinc.%s", netname);
xasprintf(&identname, "tinc.%s", netname);
else
identname = xstrdup("tinc");
@ -361,12 +393,12 @@ static void make_names(void)
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) {
if(!logfilename)
asprintf(&logfilename, "%s/log/%s.log", identname);
xasprintf(&logfilename, "%s/log/%s.log", identname);
if(!confbase) {
if(netname)
asprintf(&confbase, "%s/%s", installdir, netname);
xasprintf(&confbase, "%s/%s", installdir, netname);
else
asprintf(&confbase, "%s", installdir);
xasprintf(&confbase, "%s", installdir);
}
}
RegCloseKey(key);
@ -376,29 +408,89 @@ static void make_names(void)
#endif
if(!pidfilename)
asprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname);
xasprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname);
if(!logfilename)
asprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname);
xasprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname);
if(netname) {
if(!confbase)
asprintf(&confbase, CONFDIR "/tinc/%s", netname);
xasprintf(&confbase, CONFDIR "/tinc/%s", netname);
else
logger(LOG_INFO, _("Both netname and configuration directory given, using the latter..."));
logger(LOG_INFO, "Both netname and configuration directory given, using the latter...");
} else {
if(!confbase)
asprintf(&confbase, CONFDIR "/tinc");
xasprintf(&confbase, CONFDIR "/tinc");
}
}
int main(int argc, char **argv)
{
program_name = argv[0];
static void free_names() {
if (identname) free(identname);
if (netname) free(netname);
if (pidfilename) free(pidfilename);
if (logfilename) free(logfilename);
if (confbase) free(confbase);
}
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
static bool drop_privs() {
#ifdef HAVE_MINGW
if (switchuser) {
logger(LOG_ERR, "%s not supported on this platform", "-U");
return false;
}
if (do_chroot) {
logger(LOG_ERR, "%s not supported on this platform", "-R");
return false;
}
#else
uid_t uid = 0;
if (switchuser) {
struct passwd *pw = getpwnam(switchuser);
if (!pw) {
logger(LOG_ERR, "unknown user `%s'", switchuser);
return false;
}
uid = pw->pw_uid;
if (initgroups(switchuser, pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0) {
logger(LOG_ERR, "System call `%s' failed: %s",
"initgroups", strerror(errno));
return false;
}
endgrent();
endpwent();
}
if (do_chroot) {
tzset(); /* for proper timestamps in logs */
if (chroot(confbase) != 0 || chdir("/") != 0) {
logger(LOG_ERR, "System call `%s' failed: %s",
"chroot", strerror(errno));
return false;
}
free(confbase);
confbase = xstrdup("");
}
if (switchuser)
if (setuid(uid) != 0) {
logger(LOG_ERR, "System call `%s' failed: %s",
"setuid", strerror(errno));
return false;
}
#endif
return true;
}
#ifdef HAVE_MINGW
# define setpriority(level) SetPriorityClass(GetCurrentProcess(), level)
#else
# define NORMAL_PRIORITY_CLASS 0
# define BELOW_NORMAL_PRIORITY_CLASS 10
# define HIGH_PRIORITY_CLASS -10
# define setpriority(level) nice(level)
#endif
int main(int argc, char **argv) {
program_name = argv[0];
if(!parse_options(argc, argv))
return 1;
@ -406,13 +498,13 @@ int main(int argc, char **argv)
make_names();
if(show_version) {
printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE,
printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE,
VERSION, __DATE__, __TIME__, PROT_CURRENT);
printf(_("Copyright (C) 1998-2008 Ivo Timmermans, Guus Sliepen and others.\n"
printf("Copyright (C) 1998-2009 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"
"see the file COPYING for details.\n"));
"see the file COPYING for details.\n");
return 0;
}
@ -427,20 +519,6 @@ int main(int argc, char **argv)
openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
/* Lock all pages into memory if requested */
if(do_mlock)
#ifdef HAVE_MLOCKALL
if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
strerror(errno));
#else
{
logger(LOG_ERR, _("mlockall() not supported on this platform!"));
#endif
return -1;
}
g_argv = argv;
init_configuration(&config_tree);
@ -463,13 +541,13 @@ int main(int argc, char **argv)
return 1;
if(lzo_init() != LZO_E_OK) {
logger(LOG_ERR, _("Error initializing LZO compressor!"));
logger(LOG_ERR, "Error initializing LZO compressor!");
return 1;
}
#ifdef HAVE_MINGW
if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
logger(LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
return 1;
}
@ -479,17 +557,53 @@ int main(int argc, char **argv)
return 1;
}
int main2(int argc, char **argv)
{
int main2(int argc, char **argv) {
InitializeCriticalSection(&mutex);
EnterCriticalSection(&mutex);
#endif
if(!detach())
return 1;
#ifdef HAVE_MLOCKALL
/* Lock all pages into memory if requested.
* This has to be done after daemon()/fork() so it works for child.
* No need to do that in parent as it's very short-lived. */
if(do_mlock && mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
logger(LOG_ERR, "System call `%s' failed: %s", "mlockall",
strerror(errno));
return 1;
}
#endif
/* Setup sockets and open device. */
if(!setup_network_connections())
if(!setup_network())
goto end;
/* Initiate all outgoing connections. */
try_outgoing_connections();
/* Change process priority */
char *priority = 0;
if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) {
if(!strcasecmp(priority, "Normal"))
setpriority(NORMAL_PRIORITY_CLASS);
else if(!strcasecmp(priority, "Low"))
setpriority(BELOW_NORMAL_PRIORITY_CLASS);
else if(!strcasecmp(priority, "High"))
setpriority(HIGH_PRIORITY_CLASS);
else {
logger(LOG_ERR, "Invalid priority `%s`!", priority);
goto end;
}
}
/* drop privileges */
if (!drop_privs())
goto end;
/* Start main loop. It only exits when tinc is killed. */
@ -498,31 +612,26 @@ int main2(int argc, char **argv)
/* Shutdown properly. */
close_network_connections();
ifdebug(CONNECTIONS)
dump_device_stats();
close_network_connections();
end:
logger(LOG_NOTICE, _("Terminating"));
logger(LOG_NOTICE, "Terminating");
#ifndef HAVE_MINGW
remove_pid(pidfilename);
#endif
if (identname) free(identname);
if (netname) free(netname);
if (pidfilename) free(pidfilename);
if (logfilename) free(logfilename);
if (myport) free(myport);
if (device) free(device);
if (confbase) free(confbase);
EVP_cleanup();
ENGINE_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_free_strings();
exit_configuration(&config_tree);
free_names();
return status;
}

View file

@ -1,7 +1,7 @@
/*
device.c -- UML network socket
Copyright (C) 2002-2005 Ivo Timmermans,
2002-2006 Guus Sliepen <guus@tinc-vpn.org>
2002-2009 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
@ -13,11 +13,9 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c 1374 2004-03-21 14:21:22Z guus $
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"
@ -36,9 +34,9 @@ static int request_fd = -1;
static int data_fd = -1;
static int write_fd = -1;
static int state = 0;
char *device;
char *device = NULL;
char *iface = NULL;
char *device_info;
static char *device_info;
extern char *identname;
extern bool running;
@ -57,8 +55,7 @@ static struct request {
static struct sockaddr_un data_sun;
bool setup_device(void)
{
bool setup_device(void) {
struct sockaddr_un listen_sun;
static const int one = 1;
struct {
@ -68,17 +65,15 @@ bool setup_device(void)
} name;
struct timeval tv;
cp();
if(!get_config_string(lookup_config(config_tree, "Device"), &device))
asprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname);
xasprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname);
get_config_string(lookup_config(config_tree, "Interface"), &iface);
device_info = _("UML network socket");
device_info = "UML network socket";
if((write_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
logger(LOG_ERR, _("Could not open write %s: %s"), device_info, strerror(errno));
logger(LOG_ERR, "Could not open write %s: %s", device_info, strerror(errno));
running = false;
return false;
}
@ -86,13 +81,13 @@ bool setup_device(void)
setsockopt(write_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(write_fd, F_SETFL, O_NONBLOCK) < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
running = false;
return false;
}
if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
logger(LOG_ERR, _("Could not open data %s: %s"), device_info, strerror(errno));
logger(LOG_ERR, "Could not open data %s: %s", device_info, strerror(errno));
running = false;
return false;
}
@ -100,7 +95,7 @@ bool setup_device(void)
setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
running = false;
return false;
}
@ -113,13 +108,13 @@ bool setup_device(void)
memcpy(&data_sun.sun_path, &name, sizeof name);
if(bind(data_fd, (struct sockaddr *)&data_sun, sizeof data_sun) < 0) {
logger(LOG_ERR, _("Could not bind data %s: %s"), device_info, strerror(errno));
logger(LOG_ERR, "Could not bind data %s: %s", device_info, strerror(errno));
running = false;
return false;
}
if((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
logger(LOG_ERR, _("Could not open %s: %s"), device_info,
logger(LOG_ERR, "Could not open %s: %s", device_info,
strerror(errno));
return false;
}
@ -127,26 +122,26 @@ bool setup_device(void)
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
return false;
}
listen_sun.sun_family = AF_UNIX;
strncpy(listen_sun.sun_path, device, sizeof listen_sun.sun_path);
if(bind(listen_fd, (struct sockaddr *)&listen_sun, sizeof listen_sun) < 0) {
logger(LOG_ERR, _("Could not bind %s to %s: %s"), device_info, device, strerror(errno));
logger(LOG_ERR, "Could not bind %s to %s: %s", device_info, device, strerror(errno));
return false;
}
if(listen(listen_fd, 1) < 0) {
logger(LOG_ERR, _("Could not listen on %s %s: %s"), device_info, device, strerror(errno));
logger(LOG_ERR, "Could not listen on %s %s: %s", device_info, device, strerror(errno));
return false;
}
device_fd = listen_fd;
state = 0;
logger(LOG_INFO, _("%s is a %s"), device, device_info);
logger(LOG_INFO, "%s is a %s", device, device_info);
if(routing_mode == RMODE_ROUTER)
overwrite_mac = true;
@ -154,10 +149,7 @@ bool setup_device(void)
return true;
}
void close_device(void)
{
cp();
void close_device(void) {
if(listen_fd >= 0)
close(listen_fd);
@ -171,14 +163,14 @@ void close_device(void)
close(write_fd);
unlink(device);
free(device);
if(iface) free(iface);
}
bool read_packet(vpn_packet_t *packet)
{
bool read_packet(vpn_packet_t *packet) {
int lenin;
cp();
switch(state) {
case 0: {
struct sockaddr sa;
@ -186,12 +178,12 @@ bool read_packet(vpn_packet_t *packet)
request_fd = accept(listen_fd, &sa, &salen);
if(request_fd < 0) {
logger(LOG_ERR, _("Could not accept connection to %s %s: %s"), device_info, device, strerror(errno));
logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno));
return false;
}
if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
running = false;
return false;
}
@ -206,21 +198,21 @@ bool read_packet(vpn_packet_t *packet)
case 1: {
if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) {
logger(LOG_ERR, _("Error while reading request from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info,
device, strerror(errno));
running = false;
return false;
}
if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) {
logger(LOG_ERR, _("Unknown magic %x, version %d, request type %d from %s %s"),
logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s",
request.magic, request.version, request.type, device_info, device);
running = false;
return false;
}
if(connect(write_fd, &request.sock, sizeof request.sock) < 0) {
logger(LOG_ERR, _("Could not bind write %s: %s"), device_info, strerror(errno));
logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno));
running = false;
return false;
}
@ -228,7 +220,7 @@ bool read_packet(vpn_packet_t *packet)
write(request_fd, &data_sun, sizeof data_sun);
device_fd = data_fd;
logger(LOG_INFO, _("Connection with UML established"));
logger(LOG_INFO, "Connection with UML established");
state = 2;
return false;
@ -236,7 +228,7 @@ bool read_packet(vpn_packet_t *packet)
case 2: {
if((lenin = read(data_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
running = false;
return false;
@ -246,7 +238,7 @@ bool read_packet(vpn_packet_t *packet)
device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info);
return true;
@ -254,22 +246,19 @@ bool read_packet(vpn_packet_t *packet)
}
}
bool write_packet(vpn_packet_t *packet)
{
cp();
bool write_packet(vpn_packet_t *packet) {
if(state != 2) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Dropping packet of %d bytes to %s: not connected to UML yet"),
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet",
packet->len, device_info);
return false;
}
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info);
if(write(write_fd, packet->data, packet->len) < 0) {
if(errno != EINTR && errno != EAGAIN) {
logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
running = false;
}
@ -281,11 +270,8 @@ bool write_packet(vpn_packet_t *packet)
return true;
}
void dump_device_stats(void)
{
cp();
logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
void dump_device_stats(void) {
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
}