diff -u /dev/null openvpn-2/CHANGES.IPv6:1.1.10.14 --- /dev/null Wed Jun 22 13:01:24 2005 +++ CHANGES.IPv6 Wed Jun 22 13:01:10 2005 @@ -0,0 +1,71 @@ +# $Id: CHANGES.IPv6,v 1.1.10.14 2005/06/22 16:01:10 jjo Exp $ # +* v0.3.12 + . merged payload conntrack fixes (EXPERIMENTAL code, disabled by default), + almost no ipv6 related code changes. + +* v0.3.11 + . woaooHOO: fixed udp6 MULTI (TLS server) ! + +* v0.3.10 + . stupid typo .... GRR + +* v0.3.9 + . some MH code reorg., allow compilation with ./configure --disable-multihome + +* v0.3.8 + . udp6 --multihome (MH) support fixed, tested OK! on GNU/Linux + +* v0.3.7 + . udp6 MH support: compiles, not tested. + +* v0.3.6 + . tested UDPv4 MH on GNU/Linux: works ok + . fix incorrect addr printing in print_link_sockaddr() + +* v0.3.5 + . internals: kill print_link_sockaddr_ex(), just use print_propiate flags + (just ~10lines change at all !) + +* v0.3.4 + . make tcp4-client work against tcp6-server + +* v0.3.3 + . freebsd: compute true addrlen for sendto() with af_addr_size() + +* v0.3.2 + . minor changes to socket.[ch] (MH merge) + +* v0.3.1 + . syshead.h MH changes were missing ; now it actually compiles MH support + +* v0.3.0 + - tcp6-client, tcp6-server + - MH patch included by default from now on + +* v0.2.4-MH-0.0.6 + - account for !AF_INET in addr_host() + - removed S_IN, S_IN6 and S_UN casts; migrate last functions to openvpn_sockaddr: print*sockaddr* + - more openvpn_sockaddr migration (polishing), almost ready + - 3rd MH integration round + +* v0.2.4 + - fix --route usage for udp6 (redirect-default-gateway semantics) + +* v0.2.3 + - udp6 "correct" support for freebsd and openbsd + cc and tested OK: freebsd-5.3,openbsd-3.6 against GNU/Linux + +* v0.2.2 + - IPv6 (--proto udp6), unix-socket support selectable at configure-time + (all 4 combinations tested) + ./configure --disable-ipv6 (enabled by default) + ./configure --enable-unix-sockets (disabled by default) + (internal) USE_PF_INET6, USE_PF_UNIX from autoconf + - Change PROTO_x from #define to enum, to allow easier/cleaner support for + optional protocols + - Added IPV6_xxxx_HEADER_SIZE + +* v0.2.1 + First public release, see README.IPv6 + +# vim: sw=2 diff -u openvpn-2/ChangeLog:1.4 openvpn-2/ChangeLog:1.4.4.1 --- ChangeLog:1.4 Tue Apr 19 15:16:50 2005 +++ ChangeLog Mon May 2 10:33:48 2005 @@ -312,6 +312,9 @@ * openvpn.spec workaround for SuSE confusion regarding /etc/init.d vs. /etc/rc.d/init.d (Stefan Engel). +* Added IPv6 support (--udp6) and PF_UNIX (--unix-dgram) + See README.IPv6 and CHANGES.IPv6 for details (Juanjo Ciarlante) + 2004.12.05 -- Version 2.0-beta20 * The ability to read --askpass and --auth-user-pass --- Makefile.am:1.4 Tue Apr 19 15:16:50 2005 +++ Makefile.am Mon May 2 10:33:48 2005 @@ -86,7 +86,9 @@ status.c status.h \ syshead.h \ thread.c thread.h \ - tun.c tun.h + tun.c tun.h \ + payload.c payload.h + LDADD = @LIBOBJS@ --- Makefile.in:1.2 Tue Apr 19 15:16:50 2005 +++ Makefile.in Wed May 11 15:17:50 2005 @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.8.3 from Makefile.am. +# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -79,7 +79,7 @@ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno -mkinstalldirs = $(mkdir_p) +mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = openvpn.spec config-win32.h \ install-win32/openvpn.nsi @@ -101,7 +101,7 @@ route.$(OBJEXT) schedule.$(OBJEXT) session_id.$(OBJEXT) \ shaper.$(OBJEXT) sig.$(OBJEXT) socket.$(OBJEXT) \ socks.$(OBJEXT) ssl.$(OBJEXT) status.$(OBJEXT) \ - thread.$(OBJEXT) tun.$(OBJEXT) + thread.$(OBJEXT) tun.$(OBJEXT) payload.$(OBJEXT) nodist_openvpn_OBJECTS = openvpn_OBJECTS = $(am_openvpn_OBJECTS) $(nodist_openvpn_OBJECTS) openvpn_LDADD = $(LDADD) @@ -109,31 +109,6 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I. depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles -@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/memcmp.Po ./$(DEPDIR)/base64.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/crypto.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/error.Po ./$(DEPDIR)/event.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/fdmisc.Po ./$(DEPDIR)/forward.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/fragment.Po ./$(DEPDIR)/gremlin.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/helper.Po ./$(DEPDIR)/init.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/interval.Po ./$(DEPDIR)/list.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/lzo.Po ./$(DEPDIR)/manage.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mbuf.Po ./$(DEPDIR)/misc.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mroute.Po ./$(DEPDIR)/mss.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mtcp.Po ./$(DEPDIR)/mtu.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mudp.Po ./$(DEPDIR)/multi.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ntlm.Po ./$(DEPDIR)/occ.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/openvpn.Po ./$(DEPDIR)/options.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/otime.Po ./$(DEPDIR)/packet_id.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/perf.Po ./$(DEPDIR)/ping.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/plugin.Po ./$(DEPDIR)/pool.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/proto.Po ./$(DEPDIR)/proxy.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/push.Po ./$(DEPDIR)/reliable.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/route.Po ./$(DEPDIR)/schedule.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/session_id.Po ./$(DEPDIR)/shaper.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/sig.Po ./$(DEPDIR)/socket.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/socks.Po ./$(DEPDIR)/ssl.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/status.Po ./$(DEPDIR)/thread.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/tun.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -211,6 +186,8 @@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -304,7 +281,8 @@ status.c status.h \ syshead.h \ thread.c thread.h \ - tun.c tun.h + tun.c tun.h \ + payload.c payload.h LDADD = @LIBOBJS@ man_MANS = openvpn.8 @@ -461,6 +439,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/otime.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ping.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Po@am__quote@ @@ -485,16 +464,14 @@ @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` uninstall-info-am: install-man8: $(man8_MANS) $(man_MANS) @@ -563,9 +540,11 @@ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$tags$$unique" \ - || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) @@ -628,15 +607,15 @@ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir - $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir - $(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2 + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-tarZ: distdir - $(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir @@ -649,7 +628,7 @@ $(am__remove_distdir) dist dist-all: distdir - $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then @@ -658,13 +637,13 @@ distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ;;\ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ - bunzip2 -c $(distdir).tar.bz2 | $(AMTAR) xf - ;;\ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(AMTAR) xf - ;;\ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ - GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | unshar ;;\ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac @@ -745,7 +724,7 @@ clean-generic: distclean-generic: - -rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -806,13 +785,13 @@ .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ clean clean-generic clean-sbinPROGRAMS ctags dist dist-all \ - dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \ - distclean distclean-compile distclean-generic distclean-hdr \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-exec install-exec-am \ - install-info install-info-am install-man install-man8 \ - install-sbinPROGRAMS install-strip installcheck \ + dist-bzip2 dist-gzip dist-hook dist-shar dist-tarZ dist-zip \ + distcheck distclean distclean-compile distclean-generic \ + distclean-hdr distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-man8 install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ Index: openvpn-2/README.IPv6 diff -u /dev/null openvpn-2/README.IPv6:1.1.10.5 --- /dev/null Wed Jun 22 13:01:24 2005 +++ README.IPv6 Wed Jun 22 12:57:51 2005 @@ -0,0 +1,157 @@ +# $Id: README.IPv6,v 1.1.10.5 2005/06/22 15:57:51 jjo Exp $ # + +This README covers UDP/IPv6 v0.3.x ( --udp6 and --tcp6-xxxxxx ) support for openvpn-2.0. + +Also, with address family "generalization" changes came local AF_UNIX socket +support. + +Available under GPLv2 from + http://www.irrigacion.gov.ar/juanjo/openvpn/ + +See "Examples" section below for usage. + +* Working: + - tcp6->tcp6; tested on GNU/Linux + - upd6->upd6; tested on GNU/Linux, FreeBSD-5.3 and OpenBSD-3.6. + - upd4->upd6 (ipv6 bound); shows correctly mapped address (requires --float for now) + - unix-dgram->unix-dgram [AF_UNIX] + useful for implementing local proxies that can take full advantage + of POSIX filesystem permissions ( more powerfull access mechanisms + than inet, even for localhost) + - multihome [MH] for IPv4 and IPv6; compiles and works OK GNU/Linux + ipv4 MH support taken and adapted from James' original MH patch + +* Experimental code (correctly #ifdef'd out): + - payload conntrack: intended for filtering TCP retransmissions over reliable links + 1st tests indicate aprox ~20% speedups (very coarsly tested) + +* Setup: + ./configure --disable-ipv6 (enabled by default) + ./configure --enable-unix-sockets (disabled by default) + ./configure --enable-payload-conntrack (experimental code, not for production usage) + : + +* Usage: + For IPv6 just specify "-p upd6" an proper IPv6 hostnames, adapting the example + from man page ... + + On may: + openvpn --proto udp6 --remote --dev tun1 --ifconfig 10.4.0.1 10.4.0.2 + --verb 5 --secret key + + On june: + openvpn --proto udp6 --remote --dev tun1 --ifconfig 10.4.0.2 10.4.0.1 + --verb 5 --secret key + + Same for --proto tcp6-client, tcp6-server. + +* Examples: some succesfully tested command lines + BTW did you know that openvpn can succesfully negotiate to self + with --remote localhost ? VERY useful for fast testing. + + - IPv6 "normal" usage (+succesfully tested tunnel traffic) + server# openvpn --proto udp6 ... + : + Thu Sep 23 22:15:48 2004 Peer Connection Initiated with [AF_INET6]fe80::205:5dff:fef1:1ceb%wlan0wds1:5000 + : + client# openvpn --proto udp6 --remote fe80::240:5ff:feae:c851 ... + : + Thu Sep 23 22:13:19 2004 Peer Connection Initiated with [AF_INET6]fe80::240:5ff:feae:c851%wlan0wds0:5000 + : + + - IPv6 server, IPv4 client (more detailed) + server# openvpn --proto udp6 ... + : + Thu Sep 23 22:28:36 2004 UDPv6 link local (bound): [AF_INET6][undef]:5000 + Thu Sep 23 22:28:36 2004 UDPv6 link remote: [AF_INET6][undef] + Thu Sep 23 22:28:50 2004 Peer Connection Initiated with [AF_INET6]::ffff:10.55.14.253:5000 + Thu Sep 23 22:28:51 2004 Initialization Sequence Completed + Thu Sep 23 22:28:56 2004 WARNING: Actual Remote Options ('... proto UDPv4 ... ') \ + are inconsistent with Expected Remote Options ('... proto UDPv6 ...') + + client# openvpn --remote 10.55.14.254 ... ### same default as now: --udp + : + Thu Sep 23 22:26:11 2004 UDPv4 link local (bound): [AF_INET][undef]:5000 + Thu Sep 23 22:26:11 2004 UDPv4 link remote: [AF_INET]10.55.14.254:5000 + Thu Sep 23 22:26:21 2004 Peer Connection Initiated with [AF_INET]10.55.14.254:5000 + Thu Sep 23 22:26:21 2004 WARNING: Actual Remote Options ('... proto UDPv6 ...') \ + are inconsistent with Expected Remote Options ('... proto UDPv4 ...') + Thu Sep 23 22:26:22 2004 Initialization Sequence Completed + + - IPv6 loopback + alone# openvpn --proto udp6 --remote ::1 ... + : + Wed Sep 22 13:03:07 2004 Peer Connection Initiated with [AF_INET6]::1:5000 + : + + - AF_UNIX toself + alone# openvpn --proto unix-dgram --local /tmp/o.s --remote /tmp/o.s --dev tun ... + : + Thu Sep 23 16:37:27 2004 Peer Connection Initiated with [AF_UNIX]/tmp/o.s + : + + - AF_UNIX between to diff instances + peer1# openvpn --proto unix-dgram --local /tmp/o1.s --remote /tmp/o2.s + peer2# openvpn --proto unix-dgram --local /tmp/o2.s --remote /tmp/o1.s + : + Wed Sep 22 12:49:03 2004 Peer Connection Initiated with [AF_UNIX]/tmp/o1.s + : + + +* Main code changes summary: + - socket.h: New struct openvpn_sockaddr type that holds sockaddrs and pktinfo, + (here I omitted #ifdef USE_PF_xxxx, see socket.h ) + + struct openvpn_sockaddr { + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + } addr; + union { + struct in_pktinfo in; + struct in6_pktinfo in6; + } pi; /* Multihome support for UDP */ + }; + + struct link_socket_addr + { + struct openvpn_sockaddr local; + struct openvpn_sockaddr remote; + struct openvpn_sockaddr actual; + }; + + PRO: allows simple type overloading: local.addr.sa, local.addr.in, local.addr.in6 ... etc + (also local.pi.in and local.pi.in6) + + - several function prototypes moved from sockaddr_in to openvpn_sockaddr + - several new sockaddr functions needed to "generalize" AF_xxxx operations: + addr_copy(), addr_zero(), ...etc + proto_is_udp(), proto_is_dgram(), proto_is_net() + +* TODO: (!: fundamental, w: wanted, n: nah ... not critical, ?: need more thought) + [!]- Implement comparison for mapped addesses: server in dual stack listening + IPv6 must permit incoming streams from allowed IPv4 peer (ie without --float). + [!]- IPv6 with actual host resolution, currently only numerical (AI_NUMERICHOST) + [n]- call socket() lately, after getaddrinfo() to decide IPv4 or IPv6 host + (hence socket()) instead of needing -p {udp|udp6} + NOT ACTUALLY a big trouble, given that you _do_ setup both sides + (keys, certs, etc), using udp or udp6 is actually _another_ setup bit. + [?]- integrate both IPv4 and IPv6 addr resolution with getaddrinfo instead of + venerable gethostbyname&friends, problem: horizontal portability (across + platforms) and vertical portab. (across versions) + + DONE: + - ./configure [ --disable-ipv6 ] [ --enable-unix-sockets ] + map to USE_PF_INET6 and USE_PF_UNIX + - merge MH patch + - -p tcp6-client, -p tcp6-server + - MH IPv6 support + +-- +JuanJo Ciarlante jjo|at|mendoza.gov.ar +: : +. Linux IP Aliasing author . +. Modular algo (AES et all) support for FreeSWAN/OpenSWAN author . +:... plus other scattered free software bits in the wild ...: diff -u openvpn-2/aclocal.m4:1.1 openvpn-2/aclocal.m4:1.1.8.2 --- aclocal.m4:1.1 Fri Mar 4 16:05:57 2005 +++ aclocal.m4 Wed May 11 15:17:51 2005 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.8.3 -*- Autoconf -*- +# generated automatically by aclocal 1.9.2 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. @@ -33,14 +33,14 @@ # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. -AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.8"]) +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], - [AM_AUTOMAKE_VERSION([1.8.3])]) + [AM_AUTOMAKE_VERSION([1.9.2])]) # AM_AUX_DIR_EXPAND @@ -108,7 +108,7 @@ # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997, 2000, 2001, 2003 Free Software Foundation, Inc. +# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. # 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 @@ -145,8 +145,8 @@ fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]) + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) fi])]) # serial 7 -*- Autoconf -*- @@ -266,9 +266,14 @@ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings - # (even with -Werror). So we grep stderr for any message - # that says an option was ignored. - if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi @@ -314,7 +319,8 @@ # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. # 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 @@ -350,27 +356,21 @@ else continue fi - grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue - # Extract the definition of DEP_FILES from the Makefile without - # running `make'. + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` - test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" - # We invoke sed twice because it is the simplest approach to - # changing $(DEPDIR) to its actual value in the expansion. - for file in `sed -n ' - /^DEP_FILES = .*\\\\$/ { - s/^DEP_FILES = // - :loop - s/\\\\$// - p - n - /\\\\$/ b loop - p - } - /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue @@ -425,7 +425,7 @@ # This macro actually does too much some checks are only needed if # your package does certain things. But this isn't really a big deal. -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify @@ -501,7 +501,6 @@ AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) -AM_MISSING_PROG(AMTAR, tar) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl @@ -510,7 +509,9 @@ AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl - +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], @@ -753,13 +754,21 @@ # this.) AC_DEFUN([AM_PROG_MKDIR_P], [if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then - # Keeping the `.' argument allows $(mkdir_p) to be used without - # argument. Indeed, we sometimes output rules like + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) - # where $(somedir) is conditionally defined. - # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more - # expensive solution, as it forces Make to start a sub-shell.) - mkdir_p='mkdir -p -- .' + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as @@ -925,4 +934,112 @@ INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 1 + + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + m4_include([acinclude.m4]) diff -u openvpn-2/buffer.c:1.4 openvpn-2/buffer.c:1.4.4.1 --- buffer.c:1.4 Tue Apr 19 15:16:50 2005 +++ buffer.c Mon May 2 10:33:48 2005 @@ -197,6 +197,17 @@ } } } +void buf_puts(struct buffer *buf, const char *str) +{ + uint8_t *ptr = BEND (buf); + int cap = buf_forward_capacity (buf); + if (cap > 0) + { + strncpynt ((char *)ptr,str, cap); + *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ + buf->len += (int) strlen ((char *)ptr); + } +} /* * This is necessary due to certain buggy implementations of snprintf, diff -u openvpn-2/buffer.h:1.4 openvpn-2/buffer.h:1.4.4.1 --- buffer.h:1.4 Tue Apr 19 15:16:50 2005 +++ buffer.h Mon May 2 10:33:49 2005 @@ -200,6 +200,11 @@ ; /* + * append str to a buffer with overflow check + */ +void buf_puts(struct buffer *buf, const char *str); + +/* * Like snprintf but guarantees null termination for size > 0 */ int openvpn_snprintf(char *str, size_t size, const char *format, ...) diff -u openvpn-2/config.h.in:1.1 openvpn-2/config.h.in:1.1.8.1 --- config.h.in:1.1 Fri Mar 4 16:05:57 2005 +++ config.h.in Mon May 2 10:33:49 2005 @@ -30,6 +30,9 @@ /* Enable management server capability */ #undef ENABLE_MANAGEMENT +/* Enable multi-homed UDP server capability */ +#undef ENABLE_MULTIHOME + /* Allow --askpass and --auth-user-pass passwords to be read from a file */ #undef ENABLE_PASSWORD_SAVE @@ -147,6 +150,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* struct in_pktinfo needed for IP_PKTINFO support */ +#undef HAVE_IN_PKTINFO + /* struct iovec needed for IPv6 support */ #undef HAVE_IOVEC @@ -234,6 +240,9 @@ /* Define to 1 if you have the `recvfrom' function. */ #undef HAVE_RECVFROM +/* Define to 1 if you have the `recvmsg' function. */ +#undef HAVE_RECVMSG + /* Define to 1 if you have the header file. */ #undef HAVE_RESOLV_H @@ -243,6 +252,9 @@ /* Define to 1 if you have the `send' function. */ #undef HAVE_SEND +/* Define to 1 if you have the `sendmsg' function. */ +#undef HAVE_SENDMSG + /* Define to 1 if you have the `sendto' function. */ #undef HAVE_SENDTO @@ -451,6 +463,15 @@ /* Use LZO compression library */ #undef USE_LZO +/* Enable payload conntrack */ +#undef USE_PAYLOAD_CONNTRACK + +/* struct sockaddr_in6 is needed for IPv6 peer support */ +#undef USE_PF_INET6 + +/* Compile support for PF_UNIX sockets */ +#undef USE_PF_UNIX + /* Use pthread-based multithreading */ #undef USE_PTHREAD diff -u openvpn-2/configure:1.2 openvpn-2/configure:1.2.4.2 --- configure:1.2 Tue Apr 19 15:16:50 2005 +++ configure Wed May 11 15:17:51 2005 @@ -311,7 +311,7 @@ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS IFCONFIG IPROUTE ROUTE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP LIBOBJS PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS IFCONFIG IPROUTE ROUTE build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP LIBOBJS PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -864,6 +864,7 @@ --disable-socks Disable Socks support --disable-http Disable HTTP proxy support --disable-fragment Disable internal fragmentation support (--fragment) + --disable-multihome Disable multi-homed UDP server support (--multihome) --disable-debug Disable debugging support (disable gremlin and verb 7+ messages) --enable-small Enable smaller executable size (disable OCC, usage message, and verb 4 parm list) --enable-pthread Enable pthread support (Experimental for OpenVPN 2.0) @@ -872,6 +873,9 @@ --enable-strict Enable strict compiler warnings (debugging option) --enable-profiling Enable profiling (debugging option) --enable-strict-options Enable strict options check between peers (debugging option) + --disable-ipv6 Disable UDP/IPv6 support + --enable-unix-sockets Enable PF_UNIX sockets links + --enable-payload-conntrack Enable payload conntrack for eg. TCP retrans. dd for reliable links --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors @@ -1439,6 +1443,15 @@ fi; +# Check whether --enable-multihome or --disable-multihome was given. +if test "${enable_multihome+set}" = set; then + enableval="$enable_multihome" + MULTIHOME="$enableval" +else + MULTIHOME="yes" + +fi; + # Check whether --enable-debug or --disable-debug was given. if test "${enable_debug+set}" = set; then enableval="$enable_debug" @@ -1513,6 +1526,33 @@ fi; +# Check whether --enable-ipv6 or --disable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + PF_INET6="$enableval" +else + PF_INET6="yes" + +fi; + +# Check whether --enable-unix-sockets or --disable-unix-sockets was given. +if test "${enable_unix_sockets+set}" = set; then + enableval="$enable_unix_sockets" + PF_UNIX="$enableval" +else + PF_UNIX="no" + +fi; + +# Check whether --enable-payload-conntrack or --disable-payload-conntrack was given. +if test "${enable_payload_conntrack+set}" = set; then + enableval="$enable_payload_conntrack" + PAYLOAD_CONNTRACK="$enableval" +else + PAYLOAD_CONNTRACK="no" + +fi; + # Check whether --with-ssl-headers or --without-ssl-headers was given. if test "${with_ssl_headers+set}" = set; then @@ -1828,7 +1868,7 @@ test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- -am__api_version="1.8" +am__api_version="1.9" # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -1980,13 +2020,21 @@ fi if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then - # Keeping the `.' argument allows $(mkdir_p) to be used without - # argument. Indeed, we sometimes output rules like + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) - # where $(somedir) is conditionally defined. - # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more - # expensive solution, as it forces Make to start a sub-shell.) - mkdir_p='mkdir -p -- .' + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as @@ -2130,9 +2178,6 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -AMTAR=${AMTAR-"${am_missing_run}tar"} - install_sh=${install_sh-"$am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user @@ -2225,6 +2270,13 @@ # We need awk for the "check" target. The system "awk" is bad on # some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + @@ -3368,9 +3420,14 @@ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings - # (even with -Werror). So we grep stderr for any message - # that says an option was ignored. - if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi @@ -4980,6 +5037,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -5718,6 +5795,71 @@ fi +echo "$as_me:$LINENO: checking for struct in_pktinfo" >&5 +echo $ECHO_N "checking for struct in_pktinfo... $ECHO_C" >&6 +if test "${ac_cv_type_struct_in_pktinfo+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include "syshead.h" + +int +main () +{ +if ((struct in_pktinfo *) 0) + return 0; +if (sizeof (struct in_pktinfo)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_struct_in_pktinfo=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_struct_in_pktinfo=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_struct_in_pktinfo" >&5 +echo "${ECHO_T}$ac_cv_type_struct_in_pktinfo" >&6 +if test $ac_cv_type_struct_in_pktinfo = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IN_PKTINFO 1 +_ACEOF + +fi + echo "$as_me:$LINENO: checking for unsigned int" >&5 echo $ECHO_N "checking for unsigned int... $ECHO_C" >&6 @@ -7313,6 +7455,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -7701,7 +7863,9 @@ -for ac_func in daemon chroot getpwnam setuid nice system getpid dup dup2 getpass strerror syslog openlog mlockall getgrnam setgid setgroups stat flock readv writev setsockopt getsockopt setsid chdir gettimeofday putenv getpeername unlink poll chsize ftruncate + + +for ac_func in daemon chroot getpwnam setuid nice system getpid dup dup2 getpass strerror syslog openlog mlockall getgrnam setgid setgroups stat flock readv writev setsockopt getsockopt setsid chdir gettimeofday putenv getpeername unlink poll chsize ftruncate sendmsg recvmsg do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -8281,6 +8445,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for valgrind/memcheck.h" >&5 @@ -8863,6 +9047,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: dmalloc.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: dmalloc.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: dmalloc.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: dmalloc.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: dmalloc.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: dmalloc.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: dmalloc.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: dmalloc.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: dmalloc.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: dmalloc.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: dmalloc.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for dmalloc.h" >&5 @@ -9082,6 +9286,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: dlfcn.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: dlfcn.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: dlfcn.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: dlfcn.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: dlfcn.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: dlfcn.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: dlfcn.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: dlfcn.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: dlfcn.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: dlfcn.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for dlfcn.h" >&5 @@ -9393,6 +9617,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: lzo1x.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: lzo1x.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: lzo1x.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: lzo1x.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: lzo1x.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: lzo1x.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: lzo1x.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: lzo1x.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: lzo1x.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: lzo1x.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: lzo1x.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: lzo1x.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for lzo1x.h" >&5 @@ -9613,6 +9857,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: openssl/evp.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: openssl/evp.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: openssl/evp.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: openssl/evp.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: openssl/evp.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/evp.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: openssl/evp.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for openssl/evp.h" >&5 @@ -9930,6 +10194,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -10392,6 +10676,26 @@ ac_header_preproc=yes ;; no:yes:* ) + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: openssl/ssl.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: openssl/ssl.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: openssl/ssl.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: openssl/ssl.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: openssl/ssl.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: openssl/ssl.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: openssl/ssl.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for openssl/ssl.h" >&5 @@ -10584,6 +10888,240 @@ fi fi +if test "$PF_UNIX" = "yes"; then + { echo "$as_me:$LINENO: checking for sys/un.h header file for PF_UNIX..." >&5 +echo "$as_me: checking for sys/un.h header file for PF_UNIX..." >&6;} + if test "${ac_cv_header_sys_un_h+set}" = set; then + echo "$as_me:$LINENO: checking for sys/un.h" >&5 +echo $ECHO_N "checking for sys/un.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_un_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_un_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_un_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking sys/un.h usability" >&5 +echo $ECHO_N "checking sys/un.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking sys/un.h presence" >&5 +echo $ECHO_N "checking sys/un.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: sys/un.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: sys/un.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: sys/un.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: sys/un.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: sys/un.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: sys/un.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: sys/un.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: sys/un.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sys/un.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/un.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: sys/un.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for sys/un.h" >&5 +echo $ECHO_N "checking for sys/un.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_un_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_sys_un_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_un_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_un_h" >&6 + +fi +if test $ac_cv_header_sys_un_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define USE_PF_UNIX 1 +_ACEOF + +else + { { echo "$as_me:$LINENO: error: sys/un.h header not found." >&5 +echo "$as_me: error: sys/un.h header not found." >&2;} + { (exit 1); exit 1; }; } + +fi + + +fi + +if test "$PF_INET6" = "yes"; then + { echo "$as_me:$LINENO: checking for struct sockaddr_in6 for IPv6 support..." >&5 +echo "$as_me: checking for struct sockaddr_in6 for IPv6 support..." >&6;} + echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5 +echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6 +if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include "syshead.h" + +int +main () +{ +if ((struct sockaddr_in6 *) 0) + return 0; +if (sizeof (struct sockaddr_in6)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_struct_sockaddr_in6=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_struct_sockaddr_in6=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_in6" >&5 +echo "${ECHO_T}$ac_cv_type_struct_sockaddr_in6" >&6 +if test $ac_cv_type_struct_sockaddr_in6 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define USE_PF_INET6 1 +_ACEOF + +fi + +fi + +if test "$PAYLOAD_CONNTRACK" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define USE_PAYLOAD_CONNTRACK 1 +_ACEOF + +fi + if test "$MULTI" = "yes"; then cat >>confdefs.h <<\_ACEOF @@ -10624,6 +11162,14 @@ fi +if test "$MULTIHOME" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define ENABLE_MULTIHOME 1 +_ACEOF + +fi + if test "$DEBUG" = "yes"; then cat >>confdefs.h <<\_ACEOF @@ -11339,7 +11885,6 @@ s,@AUTOMAKE@,$AUTOMAKE,;t t s,@AUTOHEADER@,$AUTOHEADER,;t t s,@MAKEINFO@,$MAKEINFO,;t t -s,@AMTAR@,$AMTAR,;t t s,@install_sh@,$install_sh,;t t s,@STRIP@,$STRIP,;t t s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t @@ -11348,6 +11893,9 @@ s,@AWK@,$AWK,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@am__leading_dot@,$am__leading_dot,;t t +s,@AMTAR@,$AMTAR,;t t +s,@am__tar@,$am__tar,;t t +s,@am__untar@,$am__untar,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t @@ -11993,27 +12541,21 @@ else continue fi - grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue - # Extract the definition of DEP_FILES from the Makefile without - # running `make'. + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` - test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" - # We invoke sed twice because it is the simplest approach to - # changing $(DEPDIR) to its actual value in the expansion. - for file in `sed -n ' - /^DEP_FILES = .*\\\\$/ { - s/^DEP_FILES = // - :loop - s/\\\\$// - p - n - /\\\\$/ b loop - p - } - /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue diff -u openvpn-2/configure.ac:1.4 openvpn-2/configure.ac:1.4.4.1 --- configure.ac:1.4 Tue Apr 19 15:16:50 2005 +++ configure.ac Mon May 2 10:33:49 2005 @@ -89,6 +89,12 @@ [FRAGMENT="yes"] ) +AC_ARG_ENABLE(multihome, + [ --disable-multihome Disable multi-homed UDP server support (--multihome)], + [MULTIHOME="$enableval"], + [MULTIHOME="yes"] +) + AC_ARG_ENABLE(debug, [ --disable-debug Disable debugging support (disable gremlin and verb 7+ messages)], [DEBUG="$enableval"], @@ -136,6 +142,24 @@ [STRICT_OPTIONS="no"] ) +AC_ARG_ENABLE(ipv6, + [ --disable-ipv6 Disable UDP/IPv6 support], + [PF_INET6="$enableval"], + [PF_INET6="yes"] +) + +AC_ARG_ENABLE(unix-sockets, + [ --enable-unix-sockets Enable PF_UNIX sockets links], + [PF_UNIX="$enableval"], + [PF_UNIX="no"] +) + +AC_ARG_ENABLE(payload-conntrack, + [ --enable-payload-conntrack Enable payload conntrack for eg. TCP retrans. dd for reliable links], + [PAYLOAD_CONNTRACK="$enableval"], + [PAYLOAD_CONNTRACK="no"] +) + AC_ARG_WITH(ssl-headers, [ --with-ssl-headers=DIR Crypto/SSL Include files location], [CS_HDR_DIR="$withval"] @@ -326,6 +350,11 @@ [AC_DEFINE(HAVE_CMSGHDR, 1, [struct cmsghdr needed for extended socket error support])], [], [#include "syshead.h"]) +AC_CHECK_TYPE( + [struct in_pktinfo], + [AC_DEFINE(HAVE_IN_PKTINFO, 1, [struct in_pktinfo needed for IP_PKTINFO support])], + [], + [#include "syshead.h"]) AC_CHECK_SIZEOF(unsigned int) AC_CHECK_SIZEOF(unsigned long) @@ -351,7 +380,7 @@ getpass strerror syslog openlog mlockall getgrnam setgid dnl setgroups stat flock readv writev setsockopt getsockopt dnl setsid chdir gettimeofday putenv getpeername unlink dnl - poll chsize ftruncate) + poll chsize ftruncate sendmsg recvmsg) AC_CACHE_SAVE dnl Required library functions @@ -543,6 +572,28 @@ fi fi +if test "$PF_UNIX" = "yes"; then + AC_CHECKING([for sys/un.h header file for PF_UNIX]) + AC_CHECK_HEADER(sys/un.h, + [AC_DEFINE(USE_PF_UNIX, 1, [Compile support for PF_UNIX sockets])], + [AC_MSG_ERROR([sys/un.h header not found.])] + ) +fi + +if test "$PF_INET6" = "yes"; then + AC_CHECKING([for struct sockaddr_in6 for IPv6 support]) + AC_CHECK_TYPE( + [struct sockaddr_in6], + [AC_DEFINE(USE_PF_INET6, 1, [struct sockaddr_in6 is needed for IPv6 peer support])], + [], + [#include "syshead.h"]) +fi + +dnl enable payload-conntrack optimizations +if test "$PAYLOAD_CONNTRACK" = "yes"; then + AC_DEFINE(USE_PAYLOAD_CONNTRACK, 1, [Enable payload conntrack]) +fi + dnl enable multi-client mode if test "$MULTI" = "yes"; then AC_DEFINE(ENABLE_CLIENT_SERVER, 1, [Enable client/server capability]) @@ -568,6 +619,11 @@ AC_DEFINE(ENABLE_HTTP_PROXY, 1, [Enable HTTP proxy support]) fi +dnl compile --multihome option +if test "$MULTIHOME" = "yes"; then + AC_DEFINE(ENABLE_MULTIHOME, 1, [Enable multi-homed UDP server capability]) +fi + dnl enable debugging if test "$DEBUG" = "yes"; then AC_DEFINE(ENABLE_DEBUG, 1, [Enable debugging support]) diff -u openvpn-2/errlevel.h:1.4 openvpn-2/errlevel.h:1.4.6.2 --- errlevel.h:1.4 Tue Apr 19 15:16:50 2005 +++ errlevel.h Wed Jun 1 09:59:13 2005 @@ -149,6 +149,10 @@ #define D_STREAM_DEBUG LOGLEV(9, 70, M_DEBUG) /* show TCP stream debug info */ #define D_WIN32_IO LOGLEV(9, 70, M_DEBUG) /* win32 I/O debugging info */ +#ifdef USE_PAYLOAD_CONNTRACK +#define D_PAYLOAD_CONNTRACK LOGLEV(9, 70, M_DEBUG) /* show payload conntrack debug info */ +#endif + #define D_SHAPER_DEBUG LOGLEV(10, 70, M_DEBUG) /* show traffic shaper info */ #define D_REGISTRY LOGLEV(11, 70, M_DEBUG) /* win32 registry debugging info */ diff -u openvpn-2/forward.c:1.4 openvpn-2/forward.c:1.4.4.4 --- forward.c:1.4 Tue Apr 19 15:16:50 2005 +++ forward.c Mon May 30 13:21:22 2005 @@ -42,6 +42,7 @@ #include "forward-inline.h" #include "occ-inline.h" #include "ping-inline.h" +#include "payload-inline.h" /* show event wait debugging info */ @@ -498,6 +499,10 @@ /* Should we ping the remote? */ check_ping_send (c); + +#if USE_PAYLOAD_CONNTRACK + check_payload_gc(c); +#endif } static void @@ -557,17 +562,17 @@ socks_postprocess_incoming_link (struct context *c) { if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) - socks_process_incoming_udp (&c->c2.buf, &c->c2.from); + socks_process_incoming_udp (&c->c2.buf, &c->c2.from.addr.in); } static inline void socks_preprocess_outgoing_link (struct context *c, - struct sockaddr_in **to_addr, + struct openvpn_sockaddr **to_addr, int *size_delta) { if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) { - *size_delta += socks_process_outgoing_udp (&c->c2.to_link, &c->c2.to_link_addr); + *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr); *to_addr = &c->c2.link_socket->socks_relay; } } @@ -879,12 +884,23 @@ * us to examine the IPv4 header. */ process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf); +#if USE_PAYLOAD_CONNTRACK + if (c->c2.payload_context) + { + if (payload_tcp_retrans_drop(c, &c->c2.buf)) + { + buf_reset (&c->c2.to_link); + goto out; + } + } +#endif encrypt_sign (c, true); } else { buf_reset (&c->c2.to_link); } +out: perf_pop (); gc_free (&gc); } @@ -946,7 +962,7 @@ * packet to remote over the TCP/UDP port. */ int size = 0; - ASSERT (addr_defined (&c->c2.to_link_addr)); + ASSERT (link_addr_defined (c->c2.to_link_addr)); #ifdef ENABLE_DEBUG /* In gremlin-test mode, we may choose to drop this packet */ @@ -981,12 +997,12 @@ msg (D_LINK_RW, "%s WRITE [%d] to %s: %s", proto2ascii (c->c2.link_socket->info.proto, true), BLEN (&c->c2.to_link), - print_sockaddr (&c->c2.to_link_addr, &gc), + print_link_sockaddr (c->c2.to_link_addr, &gc), PROTO_DUMP (&c->c2.to_link, &gc)); /* Packet send complexified by possible Socks5 usage */ { - struct sockaddr_in *to_addr = &c->c2.to_link_addr; + struct openvpn_sockaddr *to_addr = c->c2.to_link_addr; #ifdef ENABLE_SOCKS int size_delta = 0; #endif @@ -1020,7 +1036,7 @@ if (size != BLEN (&c->c2.to_link)) msg (D_LINK_ERRORS, "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)", - print_sockaddr (&c->c2.to_link_addr, &gc), + print_link_sockaddr (c->c2.to_link_addr, &gc), BLEN (&c->c2.to_link), size); } @@ -1029,7 +1045,7 @@ { if (c->c2.to_link.len > 0) msg (D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)", - print_sockaddr (&c->c2.to_link_addr, &gc), + print_link_sockaddr (c->c2.to_link_addr, &gc), c->c2.to_link.len, EXPANDED_SIZE (&c->c2.frame)); } diff -u openvpn-2/init.c:1.4 openvpn-2/init.c:1.4.4.5 --- init.c:1.4 Tue Apr 19 15:16:50 2005 +++ init.c Fri May 27 15:41:11 2005 @@ -674,7 +674,6 @@ addr_host (&c->c1.link_socket_addr.remote), !c->options.ifconfig_nowarn, c->c2.es); - init_tun_post (c->c1.tuntap, &c->c2.frame, &c->options.tuntap_options); @@ -1026,15 +1025,29 @@ switch (c->options.proto) { case PROTO_UDPv4: +#ifdef USE_PF_INET6 + case PROTO_UDPv6: +#endif if (proxy) sec = c->options.connect_retry_seconds; break; +#ifdef USE_PF_INET6 + case PROTO_TCPv6_SERVER: +#endif case PROTO_TCPv4_SERVER: sec = 1; break; +#ifdef USE_PF_INET6 + case PROTO_TCPv6_CLIENT: +#endif case PROTO_TCPv4_CLIENT: sec = c->options.connect_retry_seconds; break; +#ifdef USE_PF_UNIX + case PROTO_UNIX_DGRAM: + sec = 2; + break; +#endif } #ifdef ENABLE_DEBUG @@ -1633,6 +1646,17 @@ } } +#ifdef USE_PAYLOAD_CONNTRACK +static void +do_init_payload(struct context *c) +{ + if (c->options.tcp_retrans) + { + c->c2.payload_context = payload_new(c->options.tcp_retrans); + } +} + +#endif /* * Allocate our socket object. */ @@ -1650,6 +1674,13 @@ static void do_init_socket_1 (struct context *c, int mode) { + unsigned int flags = 0; + +#if ENABLE_IP_PKTINFO + if (c->options.multihome) + flags |= SF_USE_IP_PKTINFO; +#endif + link_socket_init_phase1 (c->c2.link_socket, c->options.local, c->c1.remote_list, @@ -1676,7 +1707,8 @@ c->options.connect_retry_seconds, c->options.mtu_discover_type, c->options.rcvbuf, - c->options.sndbuf); + c->options.sndbuf, + flags); } /* @@ -1892,6 +1924,21 @@ } #endif +#ifdef USE_PAYLOAD_CONNTRACK +/* + * Close payload conn tracker + */ +static void +do_close_payload (struct context *c) +{ + if (c->c2.payload_context) + { + payload_free (c->c2.payload_context); + c->c2.payload_context = NULL; + } +} +#endif + /* * Open and close our event objects. */ @@ -2015,7 +2062,7 @@ #ifdef WIN32 msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else - if (c->options.proto != PROTO_UDPv4) + if (!proto_is_udp(c->options.proto)) msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP"); else { @@ -2211,7 +2258,7 @@ /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ - if (c->options.proto == PROTO_TCPv4_SERVER) + if (c->options.proto == PROTO_TCPv4_SERVER || c->options.proto == PROTO_TCPv6_SERVER) { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; @@ -2324,6 +2371,9 @@ /* initialize dynamic MTU variable */ do_init_mssfix (c); +#ifdef USE_PAYLOAD_CONNTRACK + do_init_payload(c); +#endif /* bind the TCP/UDP socket */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) do_init_socket_1 (c, link_socket_mode); @@ -2412,6 +2462,9 @@ /* close TUN/TAP device */ do_close_tun (c, false); +#ifdef USE_PAYLOAD_CONNTRACK + do_close_payload(c); +#endif /* call plugin close functions and unload */ do_close_plugins (c); @@ -2440,17 +2493,7 @@ { CLEAR (*dest); - switch (src->options.proto) - { - case PROTO_UDPv4: - dest->mode = CM_CHILD_UDP; - break; - case PROTO_TCPv4_SERVER: - dest->mode = CM_CHILD_TCP; - break; - default: - ASSERT (0); - } + dest->mode = proto_is_dgram(src->options.proto)? CM_CHILD_UDP : CM_CHILD_TCP; dest->first_time = false; @@ -2548,7 +2591,7 @@ dest->c2.buffers_owned = false; dest->c2.event_set = NULL; - if (src->options.proto == PROTO_UDPv4) + if (proto_is_dgram(src->options.proto)) do_event_set_init (dest, false); } diff -u openvpn-2/manage.c:1.2 openvpn-2/manage.c:1.2.4.1 --- manage.c:1.2 Tue Apr 19 15:16:50 2005 +++ manage.c Mon May 2 10:33:49 2005 @@ -746,12 +746,15 @@ { struct gc_arena gc = gc_new (); + struct openvpn_sockaddr act; /* * Accept the TCP client. */ - man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &man->connection.remote, false); + man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &act, false); if (socket_defined (man->connection.sd_cli)) { + man->connection.remote = act; + if (socket_defined (man->connection.sd_top)) { #ifdef WIN32 @@ -1120,9 +1123,9 @@ /* * Initialize socket address */ - ms->local.sin_family = AF_INET; - ms->local.sin_addr.s_addr = 0; - ms->local.sin_port = htons (port); + ms->local.addr.in.sin_family = AF_INET; + ms->local.addr.in.sin_addr.s_addr = 0; + ms->local.addr.in.sin_port = htons (port); /* * Run management over tunnel, or @@ -1134,7 +1137,7 @@ } else { - ms->local.sin_addr.s_addr = getaddr + ms->local.addr.in.sin_addr.s_addr = getaddr (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL); } @@ -1381,7 +1384,7 @@ && man->connection.state == MS_INITIAL) { /* listen on our local TUN/TAP IP address */ - man->settings.local.sin_addr.s_addr = htonl (tun_local_ip); + man->settings.local.addr.in.sin_addr.s_addr = htonl (tun_local_ip); man_connection_init (man); } diff -u openvpn-2/manage.h:1.2 openvpn-2/manage.h:1.2.6.1 --- manage.h:1.2 Tue Apr 19 15:16:50 2005 +++ manage.h Mon May 2 10:33:49 2005 @@ -185,7 +185,7 @@ struct man_settings { bool defined; - struct sockaddr_in local; + struct openvpn_sockaddr local; bool up_query_passwords; bool management_over_tunnel; struct user_pass up; @@ -212,7 +212,7 @@ socket_descriptor_t sd_top; socket_descriptor_t sd_cli; - struct sockaddr_in remote; + struct openvpn_sockaddr remote; #ifdef WIN32 struct net_event_win32 ne32; diff -u openvpn-2/mroute.c:1.4 openvpn-2/mroute.c:1.4.4.5 --- mroute.c:1.4 Tue Apr 19 15:16:50 2005 +++ mroute.c Sat May 21 21:06:39 2005 @@ -172,27 +172,69 @@ * to a struct mroute_addr (addr). */ bool -mroute_extract_sockaddr_in (struct mroute_addr *addr, const struct sockaddr_in *saddr, bool use_port) +mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, const struct openvpn_sockaddr *osaddr, bool use_port) { - if (saddr->sin_family == AF_INET) - { + switch (osaddr->addr.sa.sa_family) + { + case AF_INET: if (use_port) { addr->type = MR_ADDR_IPV4 | MR_WITH_PORT; addr->netbits = 0; addr->len = 6; - memcpy (addr->addr, &saddr->sin_addr.s_addr, 4); - memcpy (addr->addr + 4, &saddr->sin_port, 2); + memcpy (addr->addr, &osaddr->addr.in.sin_addr.s_addr, 4); + memcpy (addr->addr + 4, &osaddr->addr.in.sin_port, 2); } else { addr->type = MR_ADDR_IPV4; addr->netbits = 0; addr->len = 4; - memcpy (addr->addr, &saddr->sin_addr.s_addr, 4); + memcpy (addr->addr, &osaddr->addr.in.sin_addr.s_addr, 4); } return true; - } + +#ifdef USE_PF_INET6 + case AF_INET6: + if (use_port) + { + addr->type = MR_ADDR_IPV6 | MR_WITH_PORT; + addr->netbits = 0; + addr->len = 18; + memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16); + memcpy (addr->addr + 16, &osaddr->addr.in6.sin6_port, 2); + } + else + { + addr->type = MR_ADDR_IPV6; + addr->netbits = 0; + addr->len = 16; + memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16); + } + return true; +#endif +#ifdef USE_PF_UNIX + case AF_UNIX: + { + struct stat st_buf; + addr->type = MR_ADDR_UNIX; + addr->netbits = 0; + addr->len = 0 ; + memset(addr->addr, 0, sizeof (addr->addr)); + if (stat(osaddr->addr.un.sun_path, &st_buf)<0) + { + msg(M_WARN, "Could not stat(%s)", osaddr->addr.un.sun_path); + return false; + } + msg(M_INFO, "MR_ADDR_UNIX stat(\"%s\"): (0x%08lx, %lu)", osaddr->addr.un.sun_path, (unsigned long)st_buf.st_dev, (unsigned long)st_buf.st_ino); + /* Put unix socket path {device,inode} numbers into addr (uniq and shorter that pathname */ + memcpy(addr->addr, &st_buf.st_dev, sizeof(st_buf.st_dev)); + memcpy(addr->addr+sizeof(st_buf.st_dev), &st_buf.st_ino, sizeof(st_buf.st_ino)); + addr->len = sizeof(st_buf.st_dev) + sizeof (st_buf.st_ino) ; + return true; + } +#endif + } return false; } @@ -267,8 +309,59 @@ } break; case MR_ADDR_IPV6: +#ifdef USE_PF_INET6 + { + struct buffer buf; + struct sockaddr_in6 sin6; + int port; + char buf6[INET6_ADDRSTRLEN] = ""; + memset(&sin6, 0, sizeof sin6); + sin6.sin6_family = AF_INET6; + buf_set_read (&buf, maddr.addr, maddr.len); + if (buf_read(&buf, &sin6.sin6_addr, sizeof (sin6.sin6_addr))) + { + if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), + buf6, sizeof (buf6), NULL, 0, NI_NUMERICHOST) != 0) + { + buf_printf (&out, "MR_ADDR_IPV6 getnameinfo() err"); + break; + } + buf_puts (&out, buf6); + if (maddr.type & MR_WITH_NETBITS) + buf_printf (&out, "/%d", maddr.netbits); + if (maddr.type & MR_WITH_PORT) + { + port = buf_read_u16 (&buf); + if (port >= 0) + buf_printf (&out, ":%d", port); + } + } + } +#else /* old pre IPV6 1-line code: */ buf_printf (&out, "IPV6"); +#endif break; +#ifdef USE_PF_UNIX + case MR_ADDR_UNIX: + { + struct buffer buf; + dev_t path_dev; + ino_t path_ino; + buf_set_read (&buf, maddr.addr, maddr.len); + if (!buf_read(&buf, &path_dev, sizeof path_dev)) + { + msg(M_WARN, "Error reading path_dev from MR_ADDR_UNIX addr"); + break; + } + if (!buf_read(&buf, &path_ino, sizeof path_ino)) + { + msg(M_WARN, "Error reading path_ino from MR_ADDR_UNIX addr"); + break; + } + buf_printf (&out, "UNIX: (0x%08lx, %lu)", (unsigned long)path_dev, (unsigned long)path_ino); + } + break; +#endif default: buf_printf (&out, "UNKNOWN"); break; diff -u openvpn-2/mroute.h:1.4 openvpn-2/mroute.h:1.4.6.2 --- mroute.h:1.4 Tue Apr 19 15:16:50 2005 +++ mroute.h Mon May 30 15:08:34 2005 @@ -54,13 +54,14 @@ #define MR_ADDR_ETHER 1 #define MR_ADDR_IPV4 2 #define MR_ADDR_IPV6 3 -#define MR_ADDR_MASK 3 +#define MR_ADDR_UNIX 4 +#define MR_ADDR_MASK 7 /* Address type mask indicating that port # is part of address */ -#define MR_WITH_PORT 4 +#define MR_WITH_PORT 8 /* Address type mask indicating that netbits is part of address */ -#define MR_WITH_NETBITS 8 +#define MR_WITH_NETBITS 16 struct mroute_addr { uint8_t len; /* length of address */ @@ -98,6 +99,11 @@ const struct sockaddr_in *saddr, bool use_port); +struct openvpn_sockaddr; +int mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, + const struct openvpn_sockaddr *osaddr, + int use_port); + bool mroute_learnable_address (const struct mroute_addr *addr); uint32_t mroute_addr_hash_function (const void *key, uint32_t iv); diff -u openvpn-2/mtcp.c:1.4 openvpn-2/mtcp.c:1.4.4.1 --- mtcp.c:1.4 Tue Apr 19 15:16:50 2005 +++ mtcp.c Mon May 2 10:33:49 2005 @@ -159,7 +159,8 @@ ASSERT (mi->context.c2.link_socket); ASSERT (mi->context.c2.link_socket->info.lsa); ASSERT (mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM); - if (!mroute_extract_sockaddr_in (&mi->real, &mi->context.c2.link_socket->info.lsa->actual, true)) + ASSERT (mi->context.c2.link_socket->info.lsa->actual.addr.sa.sa_family == AF_INET); + if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual, true)) { msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined"); return false; diff -u openvpn-2/mudp.c:1.4 openvpn-2/mudp.c:1.4.4.2 --- mudp.c:1.4 Tue Apr 19 15:16:50 2005 +++ mudp.c Mon May 30 15:09:00 2005 @@ -51,7 +51,7 @@ struct multi_instance *mi = NULL; struct hash *hash = m->hash; - if (mroute_extract_sockaddr_in (&real, &m->top.c2.from, true)) + if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from, true)) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); diff -u openvpn-2/multi.c:1.4 openvpn-2/multi.c:1.4.4.1 --- multi.c:1.4 Tue Apr 19 15:16:50 2005 +++ multi.c Mon May 2 10:33:49 2005 @@ -938,13 +938,13 @@ in_addr_t a, int netbits) /* -1 if host route, otherwise # of network bits in address */ { - struct sockaddr_in remote_si; + struct openvpn_sockaddr remote_si; struct mroute_addr addr; CLEAR (remote_si); - remote_si.sin_family = AF_INET; - remote_si.sin_addr.s_addr = htonl (a); - ASSERT (mroute_extract_sockaddr_in (&addr, &remote_si, false)); + remote_si.addr.in.sin_family = AF_INET; + remote_si.addr.in.sin_addr.s_addr = htonl (a); + ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false)); if (netbits >= 0) { @@ -2008,15 +2008,15 @@ struct multi_context *m = (struct multi_context *) arg; struct hash_iterator hi; struct hash_element *he; - struct sockaddr_in saddr; + struct openvpn_sockaddr saddr; struct mroute_addr maddr; int count = 0; CLEAR (saddr); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = htonl (addr); - saddr.sin_port = htons (port); - if (mroute_extract_sockaddr_in (&maddr, &saddr, true)) + saddr.addr.in.sin_family = AF_INET; + saddr.addr.in.sin_addr.s_addr = htonl (addr); + saddr.addr.in.sin_port = htons (port); + if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true)) { hash_iterator_init (m->iter, &hi, true); while ((he = hash_iterator_next (&hi))) @@ -2076,16 +2076,10 @@ { ASSERT (top->options.mode == MODE_SERVER); - switch (top->options.proto) { - case PROTO_UDPv4: - tunnel_server_udp (top); - break; - case PROTO_TCPv4_SERVER: - tunnel_server_tcp (top); - break; - default: - ASSERT (0); - } + if (proto_is_dgram(top->options.proto)) + tunnel_server_udp(top); + else + tunnel_server_tcp(top); } #else diff -u openvpn-2/occ.c:1.4 openvpn-2/occ.c:1.4.4.1 --- occ.c:1.4 Tue Apr 19 15:16:50 2005 +++ occ.c Mon May 2 10:33:49 2005 @@ -372,7 +372,7 @@ c->c2.max_send_size_remote, c->c2.max_recv_size_local); if (!c->options.fragment - && c->options.proto == PROTO_UDPv4 + && (proto_is_dgram(c->options.proto)) && c->c2.max_send_size_local > TUN_MTU_MIN && (c->c2.max_recv_size_remote < c->c2.max_send_size_local || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) diff -u openvpn-2/openvpn.h:1.4 openvpn-2/openvpn.h:1.4.4.2 --- openvpn.h:1.4 Tue Apr 19 15:16:50 2005 +++ openvpn.h Fri May 27 15:21:08 2005 @@ -46,6 +46,9 @@ #include "pool.h" #include "plugin.h" #include "manage.h" +#ifdef USE_PAYLOAD_CONNTRACK +#include "payload.h" +#endif /* * Our global key schedules, packaged thusly @@ -209,8 +212,8 @@ struct link_socket_info *link_socket_info; const struct link_socket *accept_from; /* possibly do accept() on a parent link_socket */ - struct sockaddr_in to_link_addr; /* IP address of remote */ - struct sockaddr_in from; /* address of incoming datagram */ + struct openvpn_sockaddr *to_link_addr; /* IP address of remote */ + struct openvpn_sockaddr from; /* address of incoming datagram */ /* MTU frame parameters */ struct frame frame; @@ -410,6 +413,9 @@ struct event_timeout scheduled_exit; #endif +#ifdef USE_PAYLOAD_CONNTRACK + struct payload_context *payload_context; +#endif }; /* diff -u openvpn-2/options.c:1.4 openvpn-2/options.c:1.4.4.5 --- options.c:1.4 Tue Apr 19 15:16:50 2005 +++ options.c Wed May 25 20:49:36 2005 @@ -72,6 +72,18 @@ #ifdef USE_PTHREAD " [PTHREAD]" #endif +#ifdef ENABLE_IP_PKTINFO + " [MH]" +#endif +#ifdef USE_PF_INET6 + " [PF_INET6]" +#endif +#ifdef USE_PF_UNIX + " [PF_UNIX]" +#endif +#ifdef USE_PAYLOAD_CONNTRACK + " [PAYLOAD_CONNTRACK]" +#endif " built on " __DATE__ ; @@ -92,6 +104,12 @@ "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" "--proto p : Use protocol p for communicating with peer.\n" " p = udp (default), tcp-server, or tcp-client\n" +#ifdef USE_PF_INET6 + " p = udp6, tcp6-server, or tcp6-client (IPv6)\n" +#endif +#ifdef USE_PF_UNIX + " also (experimental) p = unix-dgram\n" +#endif "--connect-retry n : For --proto tcp-client, number of seconds to wait\n" " between connection retries (default=%d).\n" #ifdef ENABLE_HTTP_PROXY @@ -171,6 +189,9 @@ "--ping-timer-rem: Run the --ping-exit/--ping-restart timer only if we have a\n" " remote address.\n" "--ping n : Ping remote once every n seconds over TCP/UDP port.\n" +#if ENABLE_IP_PKTINFO + "--multihome : Configure a multi-homed UDP server.\n" +#endif "--fast-io : (experimental) Optimize TUN/TAP/UDP writes.\n" #ifdef ENABLE_OCC "--explicit-exit-notify n : (experimental) on exit, send exit signal to remote.\n" @@ -204,6 +225,10 @@ #endif "--mssfix [n] : Set upper bound on TCP MSS, default = tun-mtu size\n" " or --fragment max value, whichever is lower.\n" +#if USE_PAYLOAD_CONNTRACK + "--tcp-retrans n : Drop TCP retransmissions for n seconds time span max\n" + " (eg. n=60), useful for reliable links.\n" +#endif "--sndbuf size : Set the TCP/UDP send buffer size.\n" "--rcvbuf size : Set the TCP/UDP receive buffer size.\n" "--txqueuelen n : Set the tun/tap TX queue length to n (Linux only).\n" @@ -531,6 +556,9 @@ o->link_mtu = LINK_MTU_DEFAULT; o->mtu_discover_type = -1; o->mssfix = MSSFIX_DEFAULT; +#if USE_PAYLOAD_CONNTRACK + o->tcp_retrans = 0; +#endif o->route_delay_window = 30; o->resolve_retry_seconds = RESOLV_RETRY_INFINITE; #ifdef ENABLE_OCC @@ -995,6 +1023,9 @@ SHOW_BOOL (persist_key); SHOW_INT (mssfix); +#if USE_PAYLOAD_CONNTRACK + SHOW_INT (tcp_retrans); +#endif #if PASSTOS_CAPABILITY SHOW_BOOL (passtos); @@ -1033,6 +1064,10 @@ SHOW_INT (rcvbuf); SHOW_INT (sndbuf); +#if ENABLE_IP_PKTINFO + SHOW_BOOL (multihome); +#endif + #ifdef ENABLE_HTTP_PROXY if (o->http_proxy_options) show_http_proxy_options (o->http_proxy_options); @@ -1252,7 +1287,7 @@ * Sanity check on TCP mode options */ - if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT) + if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT && options->proto != PROTO_TCPv6_CLIENT) msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client"); /* @@ -1262,8 +1297,8 @@ msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); #ifdef ENABLE_OCC - if (options->proto != PROTO_UDPv4 && options->mtu_test) - msg (M_USAGE, "--mtu-test only makes sense with --proto udp"); + if (!proto_is_udp(options->proto) && options->mtu_test) + msg (M_USAGE, "Options error: --mtu-test only makes sense with --proto udp or --proto udp6"); #endif /* @@ -1307,7 +1342,8 @@ const char *remote = l->array[i].hostname; const int remote_port = l->array[i].port; - if (string_defined_equal (options->local, remote) + if (proto_is_net(options->proto) + && string_defined_equal (options->local, remote) && options->local_port == remote_port) msg (M_USAGE, "--remote and --local addresses are the same"); @@ -1374,16 +1410,18 @@ */ #ifdef ENABLE_FRAGMENT - if (options->proto != PROTO_UDPv4 && options->fragment) - msg (M_USAGE, "--fragment can only be used with --proto udp"); + if (!proto_is_udp(options->proto) && options->fragment) + msg (M_USAGE, "--fragment can only be used with --proto udp or --proto udp6"); #endif + if (!proto_is_net(options->proto) && !options->local) + msg (M_USAGE, "--local MUST be specified with --proto unix-dgram or --proto unix-stream"); #ifdef ENABLE_OCC - if (options->proto != PROTO_UDPv4 && options->explicit_exit_notification) + if (!proto_is_udp(options->proto) && options->explicit_exit_notification) msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); #endif - if (!options->remote_list && options->proto == PROTO_TCPv4_CLIENT) + if (!options->remote_list && (options->proto == PROTO_TCPv4_CLIENT||options->proto== PROTO_TCPv6_CLIENT)) msg (M_USAGE, "--remote MUST be used in TCP Client mode"); #ifdef ENABLE_HTTP_PROXY @@ -1401,7 +1439,7 @@ msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); #endif - if (options->proto == PROTO_TCPv4_SERVER && remote_list_len (options->remote_list) > 1) + if ((options->proto == PROTO_TCPv4_SERVER||options->proto == PROTO_TCPv6_SERVER) && remote_list_len (options->remote_list) > 1) msg (M_USAGE, "TCP server mode allows at most one --remote address"); #if P2MP_SERVER @@ -1426,8 +1464,8 @@ msg (M_USAGE, "--mode server only works with --dev tun or --dev tap"); if (options->pull) msg (M_USAGE, "--pull cannot be used with --mode server"); - if (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER)) - msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); + if (!(proto_is_udp(options->proto) || options->proto == PROTO_TCPv4_SERVER || options->proto == PROTO_TCPv6_SERVER || options->proto == PROTO_UNIX_DGRAM)) + msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server (also udp6/tcp6)"); if (!options->tls_server) msg (M_USAGE, "--mode server requires --tls-server"); if (options->remote_list) @@ -1450,9 +1488,9 @@ msg (M_USAGE, "--inetd cannot be used with --mode server"); if (options->ipchange) msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); - if (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER)) - msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); - if (options->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per)) + if (!(proto_is_dgram(options->proto) || options->proto == PROTO_TCPv4_SERVER || options->proto == PROTO_TCPv6_SERVER )) + msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server (also udp6/tcp6)"); + if (!proto_is_udp(options->proto) && (options->cf_max || options->cf_per)) msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); if (dev != DEV_TYPE_TAP && options->ifconfig_pool_netmask) msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode"); @@ -1526,7 +1564,7 @@ /* * Check consistency of replay options */ - if ((options->proto != PROTO_UDPv4) + if ((!proto_is_udp(options->proto)) && (options->replay_window != defaults.replay_window || options->replay_time != defaults.replay_time)) msg (M_USAGE, "--replay-window only makes sense with --proto udp"); @@ -1655,7 +1693,7 @@ */ if (options->pull && options->ping_rec_timeout_action == PING_UNDEF - && options->proto == PROTO_UDPv4) + && proto_is_udp(options->proto)) { options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART; options->ping_rec_timeout_action = PING_RESTART; @@ -2996,6 +3034,13 @@ VERIFY_PERMISSION (OPT_P_GENERAL); options->mlock = true; } +#if ENABLE_IP_PKTINFO + else if (streq (p[0], "multihome")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->multihome = true; + } +#endif else if (streq (p[0], "verb") && p[1]) { ++i; @@ -3500,6 +3545,14 @@ options->mssfix_default = true; } +#if USE_PAYLOAD_CONNTRACK + else if (streq (p[0], "tcp-retrans") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->tcp_retrans = positive_atoi (p[1]); + } +#endif #ifdef ENABLE_OCC else if (streq (p[0], "disable-occ")) { diff -u openvpn-2/options.h:1.4 openvpn-2/options.h:1.4.4.1 --- options.h:1.4 Tue Apr 19 15:16:50 2005 +++ options.h Mon May 2 10:33:49 2005 @@ -178,6 +178,9 @@ int mssfix; /* Upper bound on TCP MSS */ bool mssfix_default; /* true if --mssfix was supplied without a parameter */ +#if USE_PAYLOAD_CONNTRACK + int tcp_retrans; /* Drop TCP retransmissions for this time window [secs] */ +#endif #if PASSTOS_CAPABILITY bool passtos; @@ -222,6 +225,10 @@ /* optimize TUN/TAP/UDP writes */ bool fast_io; +#if ENABLE_IP_PKTINFO + bool multihome; +#endif + #ifdef USE_LZO bool comp_lzo; bool comp_lzo_adaptive; diff -u /dev/null openvpn-2/payload-inline.h:1.1.2.1 --- /dev/null Wed Jun 22 13:01:25 2005 +++ payload-inline.h Sun May 29 22:14:36 2005 @@ -0,0 +1,24 @@ +#ifndef _PAYLOAD_INLINE_H +#define _PAYLOAD_INLINE_H + +#ifdef USE_PAYLOAD_CONNTRACK +/* + * Should run conntrack GC? + */ +static inline void +check_payload_gc (struct context *c) +{ + void check_payload_gc_dowork (struct context *c); + if (!c->c2.payload_context) + return; + if (!event_timeout_defined (&c->c2.payload_context->gc.wakeup)) + return; + if (event_timeout_trigger (&c->c2.payload_context->gc.wakeup, &c->c2.timeval, ETT_DEFAULT)) + check_payload_gc_dowork (c); +} + +#endif +#endif /* _PAYLOAD_INLINE_H */ +/* +vim: cino={.5s,\:.5s,+.5s,t0,g0,^-2,e-2,n-2,p2s,(0,=.5s:sw=4:ts=8:sts=4 + */ diff -u /dev/null openvpn-2/payload.c:1.1.10.16 --- /dev/null Wed Jun 22 13:01:25 2005 +++ payload.c Wed Jun 22 11:37:15 2005 @@ -0,0 +1,499 @@ +/* + ***** THIS IS WORK IN PROGRESS (and correctly ifdef'd out) --jjo Jun/2005 ***** + * + * Payload conntrack optimizations for OpenVPN + * Intended for filtering TCP retransmissions over reliable links + * + * QUICK copy-n-paste for jjo: + * make payload.o CFLAGS="-D USE_PAYLOAD_CONNTRACK=1 -Wall " + * + * Author: JuanJo Ciarlante + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (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 + */ + +#ifdef WIN32 +#include "config-win32.h" +#else +#include "config.h" +#endif + +#ifdef USE_PAYLOAD_CONNTRACK + +#include "syshead.h" +#include "forward.h" +#include "memdbg.h" + +#include "list.h" +#include "forward-inline.h" +#include "payload.h" +#define PAYLOAD_HASH_SIZE 256 /* Should be configurable by option */ + +#define PAYLOAD_N_TCPSEGS 8 +/* + * struct payload_tuple_id : uniq 5-upla (proto==TCP is implicit) + */ +struct payload_tuple_id { + /* BEGIN uniq TCP 5-upla id */ + uint32_t ip_saddr, ip_daddr; + uint16_t tcp_sport, tcp_dport; + /* END uniq TCP 5-upla id */ +}; + +/* + * payload_tuple: 1 per TCP connection, currently only TX side hook + */ +struct payload_tuple { + struct payload_tuple_id id; + /* round robin array with PAYLOAD_N_TCPSEGS latest tcp segments: */ + struct { + struct openvpn_tcphdr tcph; + int tcp_len; + int hits; + } tcp_seg[PAYLOAD_N_TCPSEGS]; + int tcp_seg_idx; /* next slot to use */ + time_t last_used; + time_t expires; + int conn_hits; + int deleted; +}; + +/* shortcuts macros for easier printing */ +#define PAYLOAD_FMT_MIN "0x%08x:%d -> 0x%08x:%d" +#define PAYLOAD_FMT_MIN_ARGS(pip, ptcp) \ + ntohl(pip->saddr), ntohs(ptcp->source),\ + ntohl(pip->daddr), ntohs(ptcp->dest) + +#define PAYLOAD_FMT_MED PAYLOAD_FMT_MIN " (seq=%08x, ack_seq=%08x)" +#define PAYLOAD_FMT_MED_ARGS(pip, ptcp) PAYLOAD_FMT_MIN_ARGS(pip, ptcp) ,\ + ntohl(ptcp->seq),ntohl(ptcp->ack_seq) + +#define PAYLOAD_FMT_FULL PAYLOAD_FMT_MED " w=%d [%c%c%c%c%c%c]" /* doesn't show WSCALE */ +#define PAYLOAD_FMT_FULL_ARGS(pip, ptcp) PAYLOAD_FMT_MED_ARGS(pip,ptcp) ,\ + ntohs(ptcp->window), \ + OPENVPN_TCPH_FIN_MASK & ptcp->flags ? 'F' : '.', \ + OPENVPN_TCPH_SYN_MASK & ptcp->flags ? 'S' : '.', \ + OPENVPN_TCPH_RST_MASK & ptcp->flags ? 'R' : '.', \ + OPENVPN_TCPH_PSH_MASK & ptcp->flags ? 'P' : '.', \ + OPENVPN_TCPH_ACK_MASK & ptcp->flags ? 'A' : '.', \ + OPENVPN_TCPH_URG_MASK & ptcp->flags ? 'P' : '.' +/* hash related functions */ +static inline const uint8_t * +payload_tuple_hash_ptr (const struct payload_tuple *pt) +{ + return (uint8_t *) &pt->id; +} + +static inline uint32_t +payload_tuple_hash_len (const struct payload_tuple *pt) +{ + return (uint32_t) sizeof (pt->id); +} + +uint32_t +payload_tuple_hash_func (const void *key, uint32_t iv) +{ + return hash_func(payload_tuple_hash_ptr((const struct payload_tuple *)key), + payload_tuple_hash_len((const struct payload_tuple *)key), + iv); +} + +bool +payload_tuple_compare_func(const void *key1, const void *key2) +{ + return memcmp(&((const struct payload_tuple *)key1)->id, + &((const struct payload_tuple *)key2)->id, + sizeof ((const struct payload_tuple *)key1)->id) == 0; +} + + +/* create a new conntrack entry */ +static struct payload_tuple * +payload_tuple_new(void) +{ + struct payload_tuple *pt; + ALLOC_OBJ_CLEAR(pt, struct payload_tuple); + return pt; +} +void +payload_tuple_delete(struct payload_tuple *pt) +{ + free(pt); +} + +/* initialize conntrack entry with {ip,tcp} hdr data */ +static void +payload_tuple_id_init(struct payload_tuple_id *pt_id, const struct openvpn_iphdr *pip, const struct openvpn_tcphdr *ptcp) +{ + ASSERT(pt_id); + CLEAR(*pt_id); + pt_id->ip_saddr=pip->saddr; + pt_id->ip_daddr=pip->daddr; + pt_id->tcp_sport=ptcp->source; + pt_id->tcp_dport=ptcp->dest; +} + +/* + * How many buckets in hash to gc per pass. (shamelessly stolen from multi.c) + */ +#define PAYLOAD_GC_DIVISOR 256 /* How many passes to cover whole hash table */ +#define PAYLOAD_GC_MIN 16 /* Minimum number of buckets per pass */ +#define PAYLOAD_GC_MAX 1024 /* Maximum number of buckets per pass */ +static int +payload_gc_buckets_per_pass (int n_buckets) +{ + return constrain_int (n_buckets / PAYLOAD_GC_DIVISOR, PAYLOAD_GC_MIN, PAYLOAD_GC_MAX); +} + +/* + * Adjust next event wakeup based on how many conntrack entries present + * currently it programs + */ +static void +payload_gc_adjust_timers(struct context *c) +{ + struct payload_context *pc=c->c2.payload_context; + int n=hash_n_elements(pc->hash); + if (n>0) + { + if (pc->gc.wakeup.n != 1) + event_timeout_init (&pc->gc.wakeup, 1, now); + context_reschedule_sec(c, 1); + reset_coarse_timers(c); + dmsg(D_PAYLOAD_CONNTRACK, "payload_gc_adjust_timers: n_elem=%d wakeup.n=%d", n, pc->gc.wakeup.n); + } + else + { + event_timeout_clear(&pc->gc.wakeup); + dmsg(D_PAYLOAD_CONNTRACK, "payload_gc_adjust_timers: n_elem=%d timeout_cleared", n); + } +} +/* + * garbage collect old (pt->deleted) entries + */ +int +payload_gc_run(struct payload_context *pc, int start_bucket, int end_bucket) +{ + int n_deleted=0, n_total=0, n_total_hits=0; + struct hash_element *he; + struct hash_iterator hi; + if (start_bucket < 0) + { + start_bucket = 0; + end_bucket = hash_n_buckets (pc->hash); + } + hash_iterator_init_range (pc->hash, &hi, true, start_bucket, end_bucket); + while ((he = hash_iterator_next (&hi)) != NULL) + { + struct payload_tuple *pt = (struct payload_tuple *) he->value; + n_total++; + n_total_hits+=pt->conn_hits; + if (now > pt->expires) + pt->deleted++; + /* + * could have been marked syncronously (from payload_tcp_dd ...) or + * async (here) by above check + */ + if (pt->deleted) + { + n_deleted++; + dmsg(D_PAYLOAD_CONNTRACK, "payload_gc_run DELETED " PAYLOAD_FMT_MIN, + ntohl(pt->id.ip_saddr), ntohs(pt->id.tcp_sport), + ntohl(pt->id.ip_daddr), ntohs(pt->id.tcp_dport)); + payload_tuple_delete(pt); + hash_iterator_delete_element (&hi); + } + } + hash_iterator_free (&hi); + dmsg(D_PAYLOAD_CONNTRACK, "payload_gc_run(%d,%d) DELETED %d/%d entries, n_elem=%d, total_hits=%d" , + start_bucket, end_bucket, + n_deleted, n_total, hash_n_elements(pc->hash), n_total_hits); + return n_deleted; +} + +static void +payload_gc_dowork(struct payload_context *pc) +{ + if (pc->gc.bucket_base >= hash_n_buckets(pc->hash)) + pc->gc.bucket_base = 0; + payload_gc_run(pc, pc->gc.bucket_base, pc->gc.bucket_base+pc->gc.buckets_per_pass); + pc->gc.bucket_base+= pc->gc.buckets_per_pass; +} + +/* + * conntrack cleaner from event ticks + */ +void +check_payload_gc_dowork (struct context *c) +{ + struct payload_context *pc=c->c2.payload_context; + ASSERT(pc); + payload_gc_dowork(pc); + payload_gc_adjust_timers(c); +} + +/* + * Loop over TCP options, call callback() if matches passed TCP opt (wildcard: OPENVPN_TCPOPT_ANY) + * + * Some examples: + * - is SACK present? + * if(tcp_opt_process(buf, OPENVPN_TCPOPT_SACK, NULL, NULL, pip, ptcp)) ... + * - if SACK is present, call myfunc(..., myarg, ...) + * if(tcp_opt_process(buf, OPENVPN_TCPOPT_SACK, myfunc, myarg, pip, ptcp)) ... + * - is any option present? (except EOL, NOP) + * if(tcp_opt_process(buf, OPENVPN_TCPOPT_ANY, NULL, NULL, pip, ptcp)) ... + * - for each option (except EOL, NOP) call myfunc(..., myarg, ...) + * if(tcp_opt_process(buf, OPENVPN_TCPOPT_ANY, myfunc, myarg, pip, ptcp)) ... + * + */ +static inline bool +tcp_opt_process (struct buffer *buf, int optnum, bool (*callback)(uint8_t *opt, int optlen, void *callback_arg), void *callback_arg) +{ + int hlen, olen, optlen; + uint8_t *opt; + struct openvpn_tcphdr *ptcp; + + ASSERT (BLEN (buf) >= (int) sizeof (struct openvpn_tcphdr)); + + verify_align_4 (buf); + + ptcp = (struct openvpn_tcphdr *) BPTR (buf); + hlen = OPENVPN_TCPH_GET_DOFF (ptcp->doff_res); + + /* Invalid header length or header without options. */ + if (hlen <= (int) sizeof (struct openvpn_tcphdr) + || hlen > BLEN (buf)) + return false; + + for (olen = hlen - sizeof (struct openvpn_tcphdr), + opt = (uint8_t *)(ptcp + 1); + olen > 0; + olen -= optlen, opt += optlen) { + if (*opt == OPENVPN_TCPOPT_EOL) + break; + else if (*opt == OPENVPN_TCPOPT_NOP) + optlen = 1; + else { + optlen = *(opt + 1); + if (optlen <= 0 || optlen > olen) + break; + /* + * TCP opt found, callback() passed function and return true if callback succeded + */ + + if (optnum == OPENVPN_TCPOPT_ANY || optnum == *opt) { + if (callback) { + if (callback(opt, optlen, callback_arg)) + return true; + } else + /* if no callback function, just return true (opt found) */ + return true; + } + } + } + return false; +} + +static inline bool +tcp_dd_opt_skip_segment(uint8_t *opt, int optlen, void *arg) +{ + switch(*opt) + { + case OPENVPN_TCPOPT_SACK: + case OPENVPN_TCPOPT_WSCALE: + return true; + } + return false; +} +/* + * careful logic: TCP may update window, probe 0-window and alike + * yet could be seen as a retransmission + */ + +static inline int +payload_tcp_dd_drop_hit(struct context *c, const struct openvpn_iphdr *pip, const struct openvpn_tcphdr *ptcp, struct buffer *buf) +{ + bool result=false; + struct hash_element *he; + uint32_t hv; + struct hash_bucket *bucket; + struct payload_context *pc=c->c2.payload_context; + struct payload_tuple_id pt_id; + struct payload_tuple *pt; + struct openvpn_tcphdr tcph = *ptcp; /* local copy: stored tcph is NOT equal to sniffed one */ + int ip_totlen=ntohs(pip->tot_len); + int tcp_len=ip_totlen-OPENVPN_IPH_GET_LEN (pip->version_len); /* tcphdr+DATA */ + + ASSERT(pc); + tcph.check=0; /* TCP chksum will vary with eg. tstamp */ + payload_tuple_id_init(&pt_id, pip, ptcp); + + hv= hash_value (pc->hash, &pt_id); + bucket= hash_bucket (pc->hash, hv); + hash_bucket_lock (bucket); + he = hash_lookup_fast (pc->hash, bucket, &pt_id, hv); + if (he) + { + int i; + pt = (struct payload_tuple *) he->value; + /* + * Avoid filtering out if: + * - SYN or FIN + * - zero window + * - zero window probe (data size=1) + * - SACK or WSCALE option present + */ + if ( (ptcp->flags & (OPENVPN_TCPH_SYN_MASK|OPENVPN_TCPH_FIN_MASK)) + || tcph.window == 0 + || (ip_totlen-OPENVPN_TCPH_GET_DOFF(tcph.doff_res))==1 + || tcp_opt_process(buf, OPENVPN_TCPOPT_ANY, tcp_dd_opt_skip_segment, NULL)) + { + dmsg(D_PAYLOAD_CONNTRACK, "payload_tcp_dd_drop_hit: SKIP segment " PAYLOAD_FMT_FULL, + PAYLOAD_FMT_FULL_ARGS(pip, ptcp)); + goto done; + } + + /* search for seen TCP header */ + for(i=0;itcp_seg[i].tcph.seq==tcph.seq + && memcmp(pt->tcp_seg+i, &tcph, sizeof tcph)==0 + && pt->tcp_seg[i].tcp_len == tcp_len) + { + pt->tcp_seg[i].hits++; + pt->conn_hits++; + dmsg(D_PAYLOAD_CONNTRACK, "payload_tcp_dd_drop_hit HIT! conn_hits=%d timeleft=%ld " PAYLOAD_FMT_FULL, + pt->conn_hits, pt->expires-now, + PAYLOAD_FMT_FULL_ARGS(pip, ptcp)); + result=true; /* _IS_ a dup */ + goto done; + } + } + if (pt->expires < now) + { + pt->deleted=true; + goto out; + } + } + else + { + dmsg(D_PAYLOAD_CONNTRACK, "payload_tcp_dd_drop_hit CREATED " PAYLOAD_FMT_FULL, PAYLOAD_FMT_FULL_ARGS(pip, ptcp)); + pt = payload_tuple_new(); + pt->id = pt_id; + hash_add_fast(pc->hash, bucket, &pt_id, hv, pt); + payload_gc_adjust_timers(c); + } + + /* Not found or new ... use next available slot */ + pt->tcp_seg[pt->tcp_seg_idx].tcph=tcph; + pt->tcp_seg[pt->tcp_seg_idx].tcp_len=tcp_len; + pt->tcp_seg[pt->tcp_seg_idx].hits=0; + pt->tcp_seg_idx++; + pt->tcp_seg_idx%=PAYLOAD_N_TCPSEGS; + +done: + /* refresh entry */ + pt->expires=now+pc->tcp_retrans; + pt->last_used=now; + +out: + hash_bucket_unlock (bucket); + return result; +} + +/* + * External interface: payload_tcp_retrans_drop() returns true + * if this segment IS a dup (should be dropped by caller) + */ +bool +payload_tcp_retrans_drop (struct context *c, struct buffer *buf) +{ + const struct openvpn_iphdr *pip; + int hlen; + if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) + return false; + pip = (struct openvpn_iphdr *) BPTR (buf); + + hlen = OPENVPN_IPH_GET_LEN (pip->version_len); + + if (pip->protocol == OPENVPN_IPPROTO_TCP + && ntohs (pip->tot_len) == BLEN (buf) + && (ntohs (pip->frag_off) & OPENVPN_IP_OFFMASK) == 0 + && hlen <= BLEN (buf) + && BLEN (buf) - hlen + >= (int) sizeof (struct openvpn_tcphdr)) + { + struct buffer newbuf = *buf; + if (buf_advance (&newbuf, hlen)) + { + const struct openvpn_tcphdr *ptcp = (struct openvpn_tcphdr *) BPTR (&newbuf); + /* + dmsg(D_PAYLOAD_CONNTRACK, "payload_tcp_retrans_drop : " PAYLOAD_FMT_FULL, PAYLOAD_FMT_FULL_ARGS(pip, ptcp)); + */ + if (c->c2.payload_context && payload_tcp_dd_drop_hit(c, pip, ptcp, buf)) + return true; + } + } + return false; + +} +/* Initialize payload (conntrack) hash table */ +struct payload_context * +payload_new(int tcp_retrans) +{ + struct payload_context *pc; + ASSERT(tcp_retrans); + + ALLOC_OBJ_CLEAR(pc, struct payload_context); + pc->tcp_retrans = tcp_retrans; + pc->hash= hash_init(PAYLOAD_HASH_SIZE, payload_tuple_hash_func, payload_tuple_compare_func); + pc->gc.buckets_per_pass = payload_gc_buckets_per_pass(PAYLOAD_HASH_SIZE); +#if 0+WIP + pc->payload_context>schedule = schedule_init(); + pc->payload_context>max_tcp_conns = 64; /* XXX: obviously must be configurable, test 4now */ +#endif + event_timeout_clear(&pc->gc.wakeup); + return pc; +} +void payload_free(struct payload_context *pc) +{ + struct hash_iterator hi; + struct hash_element *he; + ASSERT(pc); + + event_timeout_clear(&pc->gc.wakeup); + hash_iterator_init (pc->hash, &hi, true); + while ((he = hash_iterator_next (&hi))) + { + struct payload_tuple *pt = (struct payload_tuple *) he->value; + pt->deleted++; + } + hash_iterator_free (&hi); + payload_gc_run(pc, -1, 0); + free(pc); +} + +#endif +/* +vim: cino={.5s,\:.5s,+.5s,t0,g0,^-2,e-2,n-2,p2s,(0,=.5s:sw=4:ts=8:sts=4 + */ diff -u /dev/null openvpn-2/payload.h:1.1.10.5 --- /dev/null Wed Jun 22 13:01:25 2005 +++ payload.h Sun May 29 22:14:22 2005 @@ -0,0 +1,22 @@ +#ifndef _PAYLOAD_H +#define _PAYLOAD_H +struct payload_context { + struct hash *hash; + struct schedule *schedule; /* unused by now */ + int max_tcp_conns; /* unused by now */ + int tcp_retrans; + struct { + time_t per_second_trigger; + int bucket_base; + int buckets_per_pass; + struct event_timeout wakeup; + } gc; +}; + +struct payload_context * payload_new(int tcp_retrans); +void payload_free(struct payload_context *); +int payload_tcp_retrans_drop(struct context *c, struct buffer *buf); +#endif /* _PAYLOAD_H */ +/* +vim: cino={.5s,\:.5s,+.5s,t0,g0,^-2,e-2,n-2,p2s,(0,=.5s:sw=4:ts=8:sts=4 + */ diff -u openvpn-2/proto.h:1.3 openvpn-2/proto.h:1.3.6.1 --- proto.h:1.3 Tue Apr 19 15:16:51 2005 +++ proto.h Sun May 29 22:14:22 2005 @@ -121,6 +121,11 @@ #define OPENVPN_TCPOPT_MAXSEG 2 #define OPENVPN_TCPOLEN_MAXSEG 4 +#define OPENVPN_TCPOPT_WSCALE 3 +#define OPENVPN_TCPOPT_SACK 5 +#define OPENVPN_TCPOPT_TIMESTAMP 8 +#define OPENVPN_TCPOPT_ANY 255 + /* * The following macro is used to update an * internet checksum. "acc" is a 32-bit diff -u openvpn-2/socket.c:1.4 openvpn-2/socket.c:1.4.4.17 --- socket.c 2005-11-04 20:28:42.000000000 +0100 +++ socket.c 2007-06-27 16:31:29.573636000 +0200 @@ -236,9 +236,10 @@ static void update_remote (const char* host, - struct sockaddr_in *addr, + struct openvpn_sockaddr *addr, bool *changed) { + if (addr->addr.sa.sa_family == AF_INET) { if (host && addr) { const in_addr_t new_addr = getaddr ( @@ -247,12 +248,13 @@ 1, NULL, NULL); - if (new_addr && addr->sin_addr.s_addr != new_addr) + if (new_addr && addr->addr.in.sin_addr.s_addr != new_addr) { - addr->sin_addr.s_addr = new_addr; + addr->addr.in.sin_addr.s_addr = new_addr; *changed = true; } } + } } static int @@ -439,22 +441,79 @@ } static socket_descriptor_t -create_socket_udp (void) +create_socket_udp (const unsigned int flags) { socket_descriptor_t sd; if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) msg (M_SOCKERR, "UDP: Cannot create UDP socket"); +#if ENABLE_IP_PKTINFO + else if (flags & SF_USE_IP_PKTINFO) + { + int pad = 1; + setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad)); + } +#endif + return sd; +} + +#ifdef USE_PF_INET6 +static socket_descriptor_t +create_socket_udp6 (const unsigned int flags) +{ + socket_descriptor_t sd; + + if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) + msg (M_SOCKERR, "UDP: Cannot create UDP6 socket"); +#if ENABLE_IP_PKTINFO + else if (flags & SF_USE_IP_PKTINFO) + { + int pad = 1; + setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, (void*)&pad, sizeof(pad)); + } +#endif return sd; } +static socket_descriptor_t +create_socket_tcp6 (void) +{ + socket_descriptor_t sd; + + if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) + msg (M_SOCKERR, "Cannot create TCP6 socket"); + + /* set SO_REUSEADDR on socket */ + { + int on = 1; + if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof (on)) < 0) + msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); + } + + return sd; +} + +#endif +#ifdef USE_PF_UNIX +static socket_descriptor_t +create_socket_unix_dgram (void) +{ + socket_descriptor_t sd; + + if ((sd = socket (PF_UNIX, SOCK_DGRAM, 0)) < 0) + msg (M_SOCKERR, "PF_UNIX: Cannot create datagram socket"); + return sd; +} +#endif + static void create_socket (struct link_socket *sock) { /* create socket */ if (sock->info.proto == PROTO_UDPv4) { - sock->sd = create_socket_udp (); + sock->sd = create_socket_udp (sock->socket_flags); #ifdef ENABLE_SOCKS if (sock->socks_proxy) @@ -466,6 +525,23 @@ { sock->sd = create_socket_tcp (); } +#ifdef USE_PF_INET6 + else if (sock->info.proto == PROTO_TCPv6_SERVER + || sock->info.proto == PROTO_TCPv6_CLIENT) + { + sock->sd = create_socket_tcp6 (); + } + else if (sock->info.proto == PROTO_UDPv6) + { + sock->sd = create_socket_udp6 (sock->socket_flags); + } +#endif +#ifdef USE_PF_UNIX + else if (sock->info.proto == PROTO_UNIX_DGRAM) + { + sock->sd = create_socket_unix_dgram(); + } +#endif else { ASSERT (0); @@ -478,7 +554,7 @@ static void socket_do_listen (socket_descriptor_t sd, - const struct sockaddr_in *local, + const struct openvpn_sockaddr *local, bool do_listen, bool do_set_nonblock) { @@ -486,7 +562,7 @@ if (do_listen) { msg (M_INFO, "Listening for incoming TCP connection on %s", - print_sockaddr (local, &gc)); + print_link_sockaddr (local, &gc)); if (listen (sd, 1)) msg (M_SOCKERR, "TCP: listen() failed"); } @@ -500,16 +576,23 @@ socket_descriptor_t socket_do_accept (socket_descriptor_t sd, - struct sockaddr_in *remote, + struct openvpn_sockaddr *act, const bool nowait) { - socklen_t remote_len = sizeof (*remote); + /* af_addr_size WILL return 0 in this case if AFs other than AF_INET + * are compiled because act is empty here. + * could use getsockname() to support later remote_len check + */ + socklen_t remote_len_af = af_addr_size(act->addr.sa.sa_family); + socklen_t remote_len = sizeof(act->addr); socket_descriptor_t new_sd = SOCKET_UNDEFINED; + CLEAR (*act); + #ifdef HAVE_GETPEERNAME if (nowait) { - new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len); + new_sd = getpeername (sd, &act->addr.sa, &remote_len); if (!socket_defined (new_sd)) msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed"); @@ -522,7 +605,7 @@ #endif else { - new_sd = accept (sd, (struct sockaddr *) remote, &remote_len); + new_sd = accept (sd, &act->addr.sa, &remote_len); } #if 0 /* For debugging only, test the effect of accept() failures */ @@ -538,7 +621,7 @@ { msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd); } - else if (remote_len != sizeof (*remote)) + else if (remote_len_af && remote_len != remote_len_af) /* only check if we have remote_len_af!=0 */ { msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); openvpn_close_socket (new_sd); @@ -548,27 +631,29 @@ } static void -tcp_connection_established (const struct sockaddr_in *remote) +tcp_connection_established (const struct openvpn_sockaddr *remote) { struct gc_arena gc = gc_new (); msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + print_link_sockaddr (remote, &gc)); gc_free (&gc); } static int socket_listen_accept (socket_descriptor_t sd, - struct sockaddr_in *remote, + struct openvpn_sockaddr *act, const char *remote_dynamic, bool *remote_changed, - const struct sockaddr_in *local, + const struct openvpn_sockaddr *local, bool do_listen, bool nowait, volatile int *signal_received) { struct gc_arena gc = gc_new (); - struct sockaddr_in remote_verify = *remote; + struct openvpn_sockaddr remote_verify; int new_sd = SOCKET_UNDEFINED; + addr_copy_sa(&remote_verify, act); + CLEAR (*act); socket_do_listen (sd, local, do_listen, true); @@ -601,17 +686,17 @@ continue; } - new_sd = socket_do_accept (sd, remote, nowait); + new_sd = socket_do_accept (sd, act, nowait); if (socket_defined (new_sd)) { update_remote (remote_dynamic, &remote_verify, remote_changed); if (addr_defined (&remote_verify) - && !addr_match (&remote_verify, remote)) + && !addr_match (&remote_verify, act)) { msg (M_WARN, "TCP NOTE: Rejected connection attempt from %s due to --remote setting", - print_sockaddr (remote, &gc)); + print_link_sockaddr (act, &gc)); if (openvpn_close_socket (new_sd)) msg (M_SOCKERR, "TCP: close socket failed (new_sd)"); } @@ -624,7 +709,7 @@ if (!nowait && openvpn_close_socket (sd)) msg (M_SOCKERR, "TCP: close socket failed (sd)"); - tcp_connection_established (remote); + tcp_connection_established (act); gc_free (&gc); return new_sd; @@ -632,7 +717,7 @@ static void socket_connect (socket_descriptor_t *sd, - struct sockaddr_in *remote, + struct openvpn_sockaddr *remote, struct remote_list *remote_list, const char *remote_dynamic, bool *remote_changed, @@ -642,11 +727,11 @@ struct gc_arena gc = gc_new (); msg (M_INFO, "Attempting to establish TCP connection with %s", - print_sockaddr (remote, &gc)); + print_link_sockaddr (remote, &gc)); while (true) { - const int status = connect (*sd, (struct sockaddr *) remote, - sizeof (*remote)); + const int status = connect (*sd, &remote->addr.sa, + af_addr_size(remote->addr.sa.sa_family)); get_signal (signal_received); if (*signal_received) @@ -657,26 +742,33 @@ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: connect to %s failed, will try again in %d seconds", - print_sockaddr (remote, &gc), + print_link_sockaddr (remote, &gc), connect_retry_seconds); openvpn_close_socket (*sd); openvpn_sleep (connect_retry_seconds); + switch(remote->addr.sa.sa_family) { +case AF_INET: if (remote_list) { remote_list_next (remote_list); remote_dynamic = remote_list_host (remote_list); - remote->sin_port = htons (remote_list_port (remote_list)); + remote->addr.in.sin_port = htons (remote_list_port (remote_list)); *remote_changed = true; } *sd = create_socket_tcp (); update_remote (remote_dynamic, remote, remote_changed); + break; +default: + msg(M_FATAL, "Only TCP is supported for connection oriented, sa_family=%d", + remote->addr.sa.sa_family); + } } msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + print_link_sockaddr (remote, &gc)); done: gc_free (&gc); @@ -723,26 +815,62 @@ resolve_bind_local (struct link_socket *sock) { struct gc_arena gc = gc_new (); + int addrlen; /* resolve local address if undefined */ if (!addr_defined (&sock->info.lsa->local)) { - sock->info.lsa->local.sin_family = AF_INET; - sock->info.lsa->local.sin_addr.s_addr = + switch(addr_guess_family(sock->info.proto, sock->local_host)) { /* may return AF_{INET|INET6|UNIX} guessed from local_host */ +case AF_INET: + sock->info.lsa->local.addr.in.sin_family = AF_INET; + sock->info.lsa->local.addr.in.sin_addr.s_addr = (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, sock->local_host, 0, NULL, NULL) : htonl (INADDR_ANY)); - sock->info.lsa->local.sin_port = htons (sock->local_port); + sock->info.lsa->local.addr.in.sin_port = htons (sock->local_port); + addrlen=sizeof(struct sockaddr_in); + break; +#ifdef USE_PF_INET6 +case AF_INET6: +{ + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_NUMERICHOST|AI_PASSIVE; + hints.ai_family=AF_INET6; + /* if no local_host provided, ask for IN6ADDR_ANY ... */ + if ((err=getaddrinfo(sock->local_host? sock->local_host : "::", + NULL, &hints, &ai))==0) { + sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + } else { + msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s", + sock->local_host, + gai_strerror(err)); + } + sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); + addrlen=sizeof(struct sockaddr_in6); + break; +} +#endif +#ifdef USE_PF_UNIX +case AF_UNIX: + sock->info.lsa->local.addr.un.sun_family = AF_UNIX; + strncpynt(sock->info.lsa->local.addr.un.sun_path, sock->local_host, sizeof(sock->info.lsa->local.addr.un.sun_path)); + addrlen=(offsetof (struct sockaddr_un, sun_path) + strlen (sock->info.lsa->local.addr.un.sun_path) + 1); + + break; +#endif + } } /* bind to local address/port */ if (sock->bind_local) { - if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local, - sizeof (sock->info.lsa->local))) + if (bind (sock->sd, &sock->info.lsa->local.addr.sa, addrlen)) { const int errnum = openvpn_errno_socket (); msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s", @@ -766,8 +894,11 @@ /* resolve remote address if undefined */ if (!addr_defined (&sock->info.lsa->remote)) { - sock->info.lsa->remote.sin_family = AF_INET; - sock->info.lsa->remote.sin_addr.s_addr = 0; + switch(addr_guess_family(sock->info.proto, sock->remote_host)) + { +case AF_INET: + sock->info.lsa->remote.addr.in.sin_family = AF_INET; + sock->info.lsa->remote.addr.in.sin_addr.s_addr = 0; if (sock->remote_host) { @@ -812,7 +943,7 @@ ASSERT (0); } - sock->info.lsa->remote.sin_addr.s_addr = getaddr ( + sock->info.lsa->remote.addr.in.sin_addr.s_addr = getaddr ( flags, sock->remote_host, retry, @@ -839,14 +970,46 @@ } } - sock->info.lsa->remote.sin_port = htons (sock->remote_port); + sock->info.lsa->remote.addr.in.sin_port = htons (sock->remote_port); + break; +#ifdef USE_PF_INET6 +case AF_INET6: +{ + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_NUMERICHOST; + hints.ai_family=AF_INET6; + if ((err=getaddrinfo(sock->remote_host? sock->remote_host : "::" , NULL, &hints, &ai))==0) { + sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + } else { + msg (M_FATAL, "getaddrinfo() failed for remote \"%s\": %s", + sock->remote_host, + gai_strerror(err)); + } + sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); + break; +} +#endif +#ifdef USE_PF_UNIX +case AF_UNIX: + sock->info.lsa->remote.addr.un.sun_family = AF_UNIX; + if (sock->remote_host) + strncpynt (sock->info.lsa->remote.addr.un.sun_path, sock->remote_host, + sizeof (sock->info.lsa->remote.addr.un.sun_path)); + else + sock->info.lsa->remote.addr.un.sun_path[0] = 0; + break; +#endif + } } /* should we re-use previous active remote address? */ - if (addr_defined (&sock->info.lsa->actual)) + if (link_addr_defined (&sock->info.lsa->actual)) { msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", - print_sockaddr (&sock->info.lsa->actual, &gc)); + print_link_sockaddr (&sock->info.lsa->actual, &gc)); if (remote_dynamic) *remote_dynamic = NULL; } @@ -902,7 +1065,8 @@ int connect_retry_seconds, int mtu_discover_type, int rcvbuf, - int sndbuf) + int sndbuf, + const unsigned int socket_flags) { const char *remote_host; int remote_port; @@ -938,6 +1102,8 @@ sock->socket_buffer_sizes.rcvbuf = rcvbuf; sock->socket_buffer_sizes.sndbuf = sndbuf; + sock->socket_flags = socket_flags; + sock->info.proto = proto; sock->info.remote_float = remote_float; sock->info.lsa = lsa; @@ -1084,7 +1250,7 @@ goto done; /* TCP client/server */ - if (sock->info.proto == PROTO_TCPv4_SERVER) + if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv6_SERVER) { switch (sock->mode) { @@ -1119,7 +1285,7 @@ ASSERT (0); } } - else if (sock->info.proto == PROTO_TCPv4_CLIENT) + else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv6_CLIENT) { socket_connect (&sock->sd, &sock->info.lsa->actual, @@ -1181,8 +1347,8 @@ sock->remote_host = sock->proxy_dest_host; sock->remote_port = sock->proxy_dest_port; sock->did_resolve_remote = false; - sock->info.lsa->actual.sin_addr.s_addr = 0; - sock->info.lsa->remote.sin_addr.s_addr = 0; + addr_zero_host(&sock->info.lsa->actual); + addr_zero_host(&sock->info.lsa->remote); resolve_remote (sock, 1, NULL, signal_received); @@ -1197,7 +1363,7 @@ if (remote_changed) { msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); - sock->info.lsa->remote.sin_addr.s_addr = sock->info.lsa->actual.sin_addr.s_addr; + addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual); } } @@ -1221,7 +1387,8 @@ #if EXTENDED_SOCKET_ERROR_CAPABILITY /* if the OS supports it, enable extended error passing on the socket */ - set_sock_extended_error_passing (sock->sd); + if (addr_inet4or6(&sock->info.lsa->local.addr.sa)) + set_sock_extended_error_passing (sock->sd); #endif /* print local address */ @@ -1231,12 +1398,12 @@ msg (M_INFO, "%s link local%s: %s", proto2ascii (sock->info.proto, true), (sock->bind_local ? " (bound)" : ""), - print_sockaddr_ex (&sock->info.lsa->local, sock->bind_local, ":", &gc)); + print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT: 0, &gc)); /* print active remote address */ msg (M_INFO, "%s link remote: %s", proto2ascii (sock->info.proto, true), - print_sockaddr_ex (&sock->info.lsa->actual, addr_defined (&sock->info.lsa->actual), ":", &gc)); + print_sockaddr_ex (&sock->info.lsa->actual, ":", PS_SHOW_PORT_IF_DEFINED|PS_SHOW_PKTINFO, &gc)); done: if (sig_save && signal_received) @@ -1312,13 +1479,17 @@ void link_socket_connection_initiated (const struct buffer *buf, struct link_socket_info *info, - const struct sockaddr_in *addr, + const struct openvpn_sockaddr *act, const char *common_name, struct env_set *es) { struct gc_arena gc = gc_new (); - info->lsa->actual = *addr; /* Note: skip this line for --force-dest */ + /* acquire script mutex */ + //mutex_lock_static (L_SCRIPT); + + //addr_copy(&info->lsa->actual.addr.sa, addr); /* Note: skip this line for --force-dest */ + info->lsa->actual = *act; /* Note: skip this line for --force-dest */ setenv_trusted (es, info); info->connection_established = true; @@ -1327,7 +1498,7 @@ struct buffer out = alloc_buf_gc (256, &gc); if (common_name) buf_printf (&out, "[%s] ", common_name); - buf_printf (&out, "Peer Connection Initiated with %s", print_sockaddr (&info->lsa->actual, &gc)); + buf_printf (&out, "Peer Connection Initiated with %s", print_link_sockaddr (&info->lsa->actual, &gc)); msg (M_INFO, "%s", BSTR (&out)); } @@ -1337,7 +1508,7 @@ /* Process --ipchange plugin */ if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE)) { - const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, true, " ", &gc); + const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, " ", PS_SHOW_PORT, &gc); if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, es)) msg (M_WARN, "WARNING: ipchange plugin call failed"); } @@ -1349,7 +1520,7 @@ setenv_str (es, "script_type", "ipchange"); buf_printf (&out, "%s %s", info->ipchange_command, - print_sockaddr_ex (&info->lsa->actual, true, " ", &gc)); + print_sockaddr_ex (&info->lsa->actual, " ", PS_SHOW_PORT, &gc)); system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed"); } @@ -1359,17 +1530,38 @@ void link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_info *info, - const struct sockaddr_in *from_addr) + const struct openvpn_sockaddr *from_addr) { struct gc_arena gc = gc_new (); + switch(from_addr->addr.sa.sa_family) { +case AF_INET: msg (D_LINK_ERRORS, "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", + print_link_sockaddr (from_addr, &gc), + (int)from_addr->addr.sa.sa_family, + print_sockaddr (&info->lsa->remote, &gc)); + break; +#ifdef USE_PF_INET6 +case AF_INET6: + msg (D_LINK_ERRORS, + "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", + print_link_sockaddr (from_addr, &gc), + (int)from_addr->addr.sa.sa_family, + print_sockaddr (&info->lsa->remote, &gc)); + break; +#endif +#ifdef USE_PF_UNIX +case AF_UNIX: + msg (D_LINK_ERRORS, + "AF_UNIX: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source by removing --remote or adding --float)", print_sockaddr (from_addr, &gc), - (int)from_addr->sin_family, + (int)from_addr->addr.sa.sa_family, print_sockaddr (&info->lsa->remote, &gc)); + break; +#endif + } buf->len = 0; - gc_free (&gc); } @@ -1384,10 +1576,24 @@ { const struct link_socket_addr *lsa = info->lsa; +/* + * This logic supports "redirect-gateway" semantic, which + * makes sense only for PF_INET routes over PF_INET endpoints + * + * Maybe in the future consider PF_INET6 endpoints also ... + * by now just ignore it + * + */ +#if defined ( USE_PF_INET6 ) || defined ( USE_PF_UNIX ) + if(lsa->actual.addr.sa.sa_family != AF_INET) + return 0; +#else + ASSERT(lsa->actual.addr.sa.sa_family == AF_INET); +#endif if (addr_defined (&lsa->actual)) - return ntohl (lsa->actual.sin_addr.s_addr); + return ntohl (lsa->actual.addr.in.sin_addr.s_addr); else if (addr_defined (&lsa->remote)) - return ntohl (lsa->remote.sin_addr.s_addr); + return ntohl (lsa->remote.addr.in.sin_addr.s_addr); else return 0; } @@ -1580,28 +1786,96 @@ */ const char * -print_sockaddr (const struct sockaddr_in *addr, struct gc_arena *gc) +print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc) { - return print_sockaddr_ex(addr, true, ":", gc); + return print_sockaddr_ex(addr, ":", PS_SHOW_PORT, gc); } const char * -print_sockaddr_ex (const struct sockaddr_in *addr, bool do_port, const char* separator, struct gc_arena *gc) +print_sockaddr_ex (const struct openvpn_sockaddr *addr, const char* separator, int flags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - const int port = ntohs (addr->sin_port); - + struct buffer out; + bool addr_is_defined; + + if (!addr) { + return "[NULL]"; + } + addr_is_defined = addr_defined (addr); + switch(addr->addr.sa.sa_family) { +case AF_INET: { + const int port= ntohs (addr->addr.in.sin_port); + out = alloc_buf_gc (128, gc); + buf_puts (&out, "[AF_INET]"); mutex_lock_static (L_INET_NTOA); - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sin_addr) : "[undef]")); + buf_puts (&out, (addr_is_defined ? inet_ntoa (addr->addr.in.sin_addr) : "[undef]")); mutex_unlock_static (L_INET_NTOA); - if (do_port && port) + if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) + && port) { if (separator) buf_printf (&out, "%s", separator); buf_printf (&out, "%d", port); } +#if ENABLE_IP_PKTINFO + if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(addr)) + { + buf_printf (&out, " (via %s)", inet_ntoa (addr->pi.in.ipi_spec_dst)); + } +#endif + } + break; +#ifdef USE_PF_INET6 +case AF_INET6: { + const int port= ntohs (addr->addr.in6.sin6_port); + char buf[INET6_ADDRSTRLEN] = "[undef]"; + out = alloc_buf_gc (128, gc); + buf_puts (&out, "[AF_INET6]"); + if (addr_is_defined) + { + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); + buf_puts (&out, buf); + } + if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) + && port) + { + if (separator) + buf_puts (&out, separator); + + buf_printf (&out, "%d", port); + } +#if ENABLE_IP_PKTINFO + if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(addr)) + { + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = addr->pi.in6.ipi6_addr; + { + if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), + buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0) + buf_printf (&out, " (via %s)", buf); + else + buf_printf (&out, " (via [getnameinfo() err])"); + } + } +#endif + } + break; +#endif +#ifdef USE_PF_UNIX +case AF_UNIX: { + out = alloc_buf_gc (sizeof (addr->addr.un.sun_path)+9 /* "[AF_UNIX]" */+1, gc); + buf_puts (&out, "[AF_UNIX]"); + buf_puts (&out, addr->addr.un.sun_path); + } + break; +#endif +default: + return "[NO address family defined]"; + } return BSTR (&out); } @@ -1627,26 +1901,53 @@ return BSTR (&out); } +const char * +print_link_sockaddr (const struct openvpn_sockaddr *act, struct gc_arena *gc) +{ + return print_sockaddr_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc); +} + /* set environmental variables for ip/port in *addr */ void -setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct sockaddr_in *addr, const bool flags) +setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags) { char name_buf[256]; + char buf[128]; + switch(addr->addr.sa.sa_family) { +case AF_INET: if (flags & SA_IP_PORT) openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); else openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); - mutex_lock_static (L_INET_NTOA); - setenv_str (es, name_buf, inet_ntoa (addr->sin_addr)); + setenv_str (es, name_buf, inet_ntoa (addr->addr.in.sin_addr)); mutex_unlock_static (L_INET_NTOA); - if ((flags & SA_IP_PORT) && addr->sin_port) + if ((flags & SA_IP_PORT) && (addr->addr.in.sin_port)) { openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); - setenv_int (es, name_buf, ntohs (addr->sin_port)); + setenv_int (es, name_buf, ntohs (addr->addr.in.sin_port)); } + break; +#ifdef USE_PF_INET6 +case AF_INET6: + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + setenv_str (es, name_buf, buf); + + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); + setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); + break; +#endif +#ifdef USE_PF_UNIX +case AF_UNIX: + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_path", name_prefix); + setenv_str (es, name_buf, addr->addr.un.sun_path); + break; +#endif + } } void @@ -1654,13 +1955,15 @@ { if (addr || !(flags & SA_SET_IF_NONZERO)) { - struct sockaddr_in si; - CLEAR (si); - si.sin_addr.s_addr = htonl (addr); - setenv_sockaddr (es, name_prefix, &si, flags); + struct openvpn_sockaddr osa; + CLEAR (osa); + osa.addr.in.sin_family = AF_INET; + osa.addr.in.sin_addr.s_addr = htonl (addr); + setenv_sockaddr (es, name_prefix, &osa, flags); } } + /* * Convert protocol names between index and ascii form. */ @@ -1668,16 +1971,67 @@ struct proto_names { const char *short_form; const char *display_form; + bool is_dgram; + bool is_net; + sa_family_t proto_af; }; /* Indexed by PROTO_x */ -static const struct proto_names proto_names[] = { - {"udp", "UDPv4"}, - {"tcp-server", "TCPv4_SERVER"}, - {"tcp-client", "TCPv4_CLIENT"}, - {"tcp", "TCPv4"} +static const struct proto_names proto_names[PROTO_N] = { + {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC}, + {"udp", "UDPv4",1,1, AF_INET}, + {"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, + {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, + {"tcp", "TCPv4",0,1, AF_INET}, +#ifdef USE_PF_INET6 + {"udp6" ,"UDPv6",1,1, AF_INET6}, + {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, + {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, + {"tcp6" ,"TCPv6",0,1, AF_INET6}, +#endif +#ifdef USE_PF_UNIX + {"unix-dgram" ,"UNIX_DGRAM",1,0, AF_UNIX }, + {"unix-stream","UNIX_STREAM",1,0, AF_UNIX } +#endif }; +bool +proto_is_net(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_net; +} +bool +proto_is_dgram(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_dgram; +} +bool +proto_is_udp(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_dgram&&proto_names[proto].is_net; +} +bool +proto_is_tcp(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; +} + +sa_family_t +proto_sa_family(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].proto_af; +} + int ascii2proto (const char* proto_name) { @@ -1708,7 +2062,7 @@ int i; ASSERT (PROTO_N == SIZE (proto_names)); - for (i = 0; i < PROTO_N; ++i) + for (i = 1; i < PROTO_N; ++i) /* skip first slot */ { if (i) buf_printf(&out, " "); @@ -1717,6 +2071,47 @@ return BSTR (&out); } + +int +addr_guess_family(int proto, const char *name) +{ + sa_family_t ret; + if (proto) { + return proto_sa_family(proto); /* already stamped */ + } +#ifdef USE_PF_UNIX + else if (name && name[0] == '/') { + return AF_UNIX; + } +#endif +#ifdef USE_PF_INET6 + else { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_NUMERICHOST; + if ((err=getaddrinfo(name, NULL, &hints, &ai))==0) { + ret=ai->ai_family; + freeaddrinfo(ai); + return ret; + } + } +#endif + return AF_INET; /* default */ +} +const char * +addr_family_name (int af) +{ + switch (af) { + case AF_INET: return "AF_INET"; + case AF_INET6: return "AF_INET6"; +#ifdef USE_PF_UNIX + case AF_UNIX: return "AF_UNIX"; +#endif + } + return "AF_UNSPEC"; +} + /* * Given a local proto, return local proto * if !remote, or compatible remote proto @@ -1790,24 +2185,128 @@ #ifndef WIN32 +#if ENABLE_IP_PKTINFO + +struct openvpn_in_pktinfo +{ + struct cmsghdr cmsghdr; + struct in_pktinfo pi; +}; +#ifdef USE_PF_INET6 +struct openvpn_in6_pktinfo +{ + struct cmsghdr cmsghdr; + struct in6_pktinfo pi6; +}; +#endif + +union openvpn_pktinfo { + struct openvpn_in_pktinfo cmsgpi; +#ifdef USE_PF_INET6 + struct openvpn_in6_pktinfo cmsgpi6; +#endif +}; + +/* UDPv4 and UDPv6 */ +static socklen_t +link_socket_read_udp_posix_recvmsg (struct link_socket *sock, + struct buffer *buf, + int maxsize, + struct openvpn_sockaddr *from) +{ + struct iovec iov; + union openvpn_pktinfo opi; + struct msghdr mesg; + socklen_t fromlen = sizeof (from->addr); + + iov.iov_base = BPTR (buf); + iov.iov_len = maxsize; + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + mesg.msg_name = &from->addr; + mesg.msg_namelen = fromlen; + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (opi); + buf->len = recvmsg (sock->sd, &mesg, 0); + if (buf->len >= 0) + { + struct cmsghdr *cmsg; + fromlen = mesg.msg_namelen; + cmsg = CMSG_FIRSTHDR (&mesg); + if (cmsg != NULL + && CMSG_NXTHDR (&mesg, cmsg) == NULL + && cmsg->cmsg_level == SOL_IP + && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len >= sizeof (struct openvpn_in_pktinfo)) + { + struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); + from->pi.in.ipi_ifindex = pkti->ipi_ifindex; + from->pi.in.ipi_spec_dst = pkti->ipi_spec_dst; + } +#ifdef USE_PF_INET6 + else if (cmsg != NULL + && CMSG_NXTHDR (&mesg, cmsg) == NULL + && cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo)) + { + struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); + from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; + from->pi.in6.ipi6_addr = pkti6->ipi6_addr; + } +#endif + } + return fromlen; +} +#endif + +/* UDPv4 and UDPv6 */ int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from) + struct openvpn_sockaddr *from) +{ + socklen_t fromlen = sizeof (from->addr); + socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto)); + CLEAR (*from); + ASSERT (buf_safe (buf, maxsize)); +#if ENABLE_IP_PKTINFO + /* if (sock->info.proto == PROTO_UDPv4 && sock->socket_flags & SF_USE_IP_PKTINFO) */ + /* Both PROTO_UDPv4 and PROTO_UDPv6 */ + if (proto_is_udp(sock->info.proto) && sock->socket_flags & SF_USE_IP_PKTINFO) + fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); + else +#endif + buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, + &from->addr.sa, &fromlen); + if (buf->len >= 0 && expectedlen && fromlen != expectedlen) + bad_address_length (fromlen, expectedlen); + return buf->len; +} + +#endif + +#ifdef USE_PF_UNIX + +int +link_socket_read_unix_dgram (struct link_socket *sock, + struct buffer *buf, + int maxsize, + struct sockaddr_un *from) { socklen_t fromlen = sizeof (*from); CLEAR (*from); ASSERT (buf_safe (buf, maxsize)); + /* PF_UNIX DGRAM */ buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, (struct sockaddr *) from, &fromlen); - if (fromlen != sizeof (*from)) - bad_address_length (fromlen, sizeof (*from)); + if (fromlen > sizeof (*from)) + bad_address_length (fromlen, sizeof (*from)); /* jjo: XXX: actually excessive_addr_len() */ return buf->len; } #endif - /* * Socket Write Routines */ @@ -1815,7 +2314,7 @@ int link_socket_write_tcp (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { packet_size_type len = BLEN (buf); dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset); @@ -1829,6 +2328,68 @@ #endif } +#if ENABLE_IP_PKTINFO + +int +link_socket_write_udp_posix_sendmsg (struct link_socket *sock, + struct buffer *buf, + struct openvpn_sockaddr *to) +{ + struct iovec iov; + struct msghdr mesg; + struct cmsghdr *cmsg; + + /* ASSERT(sock->info.lsa->remote.addr.in.sin_family == AF_INET); */ + iov.iov_base = BPTR (buf); + iov.iov_len = BLEN (buf); + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + switch (sock->info.lsa->remote.addr.sa.sa_family) { + case AF_INET: { + struct openvpn_in_pktinfo opi; + struct in_pktinfo *pkti; + mesg.msg_name = &to->addr.sa; + mesg.msg_namelen = sizeof (struct sockaddr_in); + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (opi); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = sizeof (opi); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); + pkti->ipi_ifindex = to->pi.in.ipi_ifindex; + pkti->ipi_spec_dst = to->pi.in.ipi_spec_dst; + pkti->ipi_addr.s_addr = 0; + break; + } +#ifdef USE_PF_INET6 + case AF_INET6: { + struct openvpn_in6_pktinfo opi6; + struct in6_pktinfo *pkti6; + mesg.msg_name = &to->addr.sa; + mesg.msg_namelen = sizeof (struct sockaddr_in6); + mesg.msg_control = &opi6; + mesg.msg_controllen = sizeof (opi6); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = sizeof (opi6); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); + pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; + pkti6->ipi6_addr = to->pi.in6.ipi6_addr; + break; + } +#endif + default: ASSERT(0); + } + return sendmsg (sock->sd, &mesg, 0); +} + +#endif + + /* * Win32 overlapped socket I/O functions. */ diff -u openvpn-2/socket.h:1.4 openvpn-2/socket.h:1.4.4.11 --- socket.h:1.4 Tue Apr 19 15:16:51 2005 +++ socket.h Mon May 30 15:09:56 2005 @@ -77,12 +77,32 @@ /* convert a packet_size_type from network to host order */ #define ntohps(x) ntohs(x) +struct openvpn_sockaddr { + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifdef USE_PF_INET6 + struct sockaddr_in6 in6; +#endif +#ifdef USE_PF_UNIX + struct sockaddr_un un; +#endif + } addr; +#if ENABLE_IP_PKTINFO + union { + struct in_pktinfo in; +#ifdef USE_PF_INET6 + struct in6_pktinfo in6; +#endif + } pi; /* Multihome support for UDP */ +#endif +}; /* IP addresses which are persistant across SIGUSR1s */ struct link_socket_addr { - struct sockaddr_in local; - struct sockaddr_in remote; /* initial remote */ - struct sockaddr_in actual; /* remote may change due to --float */ + struct openvpn_sockaddr local; + struct openvpn_sockaddr remote; + struct openvpn_sockaddr actual; }; struct link_socket_info @@ -184,6 +204,8 @@ struct stream_buf stream_buf; struct buffer stream_buf_data; bool stream_reset; +# define SF_USE_IP_PKTINFO (1<<0) + unsigned int socket_flags; #ifdef ENABLE_HTTP_PROXY /* HTTP proxy */ @@ -193,7 +215,7 @@ #ifdef ENABLE_SOCKS /* Socks proxy */ struct socks_proxy_info *socks_proxy; - struct sockaddr_in socks_relay; /* Socks UDP relay address */ + struct openvpn_sockaddr socks_relay; /* Socks UDP relay address */ #endif #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS) @@ -276,7 +298,8 @@ int connect_retry_seconds, int mtu_discover_type, int rcvbuf, - int sndbuf); + int sndbuf, + const unsigned int flags); void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame, @@ -291,14 +314,21 @@ void link_socket_close (struct link_socket *sock); -const char *print_sockaddr_ex (const struct sockaddr_in *addr, - bool do_port, +#define PS_SHOW_PORT_IF_DEFINED (1<<0) +#define PS_SHOW_PORT (1<<1) +#define PS_SHOW_PKTINFO (1<<2) +const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr, const char* separator, + int flags, struct gc_arena *gc); -const char *print_sockaddr (const struct sockaddr_in *addr, +const char *print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc); +const char *print_link_sockaddr (const struct openvpn_sockaddr *act, + struct gc_arena *gc); + +int addr_guess_type(int proto, const char *name); #define IA_EMPTY_IF_UNDEF (1<<0) #define IA_NET_ORDER (1<<1) const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc); @@ -307,27 +337,26 @@ #define SA_SET_IF_NONZERO (1<<1) void setenv_sockaddr (struct env_set *es, const char *name_prefix, - const struct sockaddr_in *addr, + const struct openvpn_sockaddr *addr, const bool flags); void setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, const bool flags); - void bad_address_length (int actual, int expected); in_addr_t link_socket_current_remote (const struct link_socket_info *info); void link_socket_connection_initiated (const struct buffer *buf, struct link_socket_info *info, - const struct sockaddr_in *addr, + const struct openvpn_sockaddr *addr, const char *common_name, struct env_set *es); void link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_info *info, - const struct sockaddr_in *from_addr); + const struct openvpn_sockaddr *from_addr); void link_socket_bad_outgoing_addr (void); @@ -348,10 +377,19 @@ socket_descriptor_t create_socket_tcp (void); socket_descriptor_t socket_do_accept (socket_descriptor_t sd, - struct sockaddr_in *remote, + struct openvpn_sockaddr *act, const bool nowait); /* + * proto related + */ +bool proto_is_net(int proto); +bool proto_is_dgram(int proto); +bool proto_is_udp(int proto); +bool proto_is_tcp(int proto); + + +/* * DNS resolution */ @@ -373,28 +411,70 @@ * Transport protocol naming and other details. */ -#define PROTO_UDPv4 0 -#define PROTO_TCPv4_SERVER 1 -#define PROTO_TCPv4_CLIENT 2 -#define PROTO_TCPv4 3 -#define PROTO_N 4 +#if 0 /* PRE UDPv6/TCPv6 code */ +#define PROTO_NONE 0 /* catch for uninitialized */ +#define PROTO_UDPv4 1 +#define PROTO_TCPv4_SERVER 2 +#define PROTO_TCPv4_CLIENT 3 +#define PROTO_TCPv4 4 +#define PROTO_UDPv6 5 +#define PROTO_TCPv6_SERVER 6 +#define PROTO_TCPv6_CLIENT 7 +#define PROTO_TCPv6 8 +#define PROTO_UNIX_DGRAM 9 +#define PROTO_UNIX_STREAM 10 +#define PROTO_N 11 +#endif + +/* + * Use enum's instead of #define to allow for easier + * optional proto support + */ +enum proto_num { + PROTO_NONE, /* catch for uninitialized */ + PROTO_UDPv4, + PROTO_TCPv4_SERVER, + PROTO_TCPv4_CLIENT, + PROTO_TCPv4, + PROTO_UDPv6, + PROTO_TCPv6_SERVER, + PROTO_TCPv6_CLIENT, + PROTO_TCPv6, + PROTO_UNIX_DGRAM, + PROTO_UNIX_STREAM, + PROTO_N +}; int ascii2proto (const char* proto_name); const char *proto2ascii (int proto, bool display_form); const char *proto2ascii_all (struct gc_arena *gc); int proto_remote (int proto, bool remote); +const char *addr_family_name(int af); /* * Overhead added to packets by various protocols. */ #define IPv4_UDP_HEADER_SIZE 28 #define IPv4_TCP_HEADER_SIZE 40 -#define IPv6_UDP_HEADER_SIZE 40 +#define IPv6_UDP_HEADER_SIZE 48 +#define IPv6_TCP_HEADER_SIZE 60 -static const int proto_overhead[] = { /* indexed by PROTO_x */ - IPv4_UDP_HEADER_SIZE, +static const int proto_overhead[PROTO_N] = { /* indexed by PROTO_x */ + 0, + IPv4_UDP_HEADER_SIZE, /* IPv4 */ + IPv4_TCP_HEADER_SIZE, IPv4_TCP_HEADER_SIZE, - IPv4_TCP_HEADER_SIZE + IPv4_TCP_HEADER_SIZE, +#ifdef USE_PF_INET6 + IPv6_UDP_HEADER_SIZE, /* IPv6 */ + IPv6_TCP_HEADER_SIZE, + IPv6_TCP_HEADER_SIZE, + IPv6_TCP_HEADER_SIZE, +#endif +#ifdef USE_PF_UNIX + 0, /* AF_UNIX proxies, assume no overhead */ + 0, +#endif }; static inline int @@ -426,7 +506,7 @@ static inline bool link_socket_proto_connection_oriented (int proto) { - return proto == PROTO_TCPv4_SERVER || proto == PROTO_TCPv4_CLIENT; + return !proto_is_dgram(proto); } static inline bool @@ -437,35 +517,113 @@ else return false; } - static inline bool -addr_defined (const struct sockaddr_in *addr) +addr_defined (const struct openvpn_sockaddr *addr) { - return addr->sin_addr.s_addr != 0; + if (!addr) return 0; + switch (addr->addr.sa.sa_family) { + case AF_INET: return addr->addr.in.sin_addr.s_addr != 0; +#ifdef USE_PF_UNIX + case AF_UNIX: return addr->addr.un.sun_path[0] != 0; +#endif +#ifdef USE_PF_INET6 + case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr); +#endif + default: return 0; + } +} +static inline bool +addr_defined_ipi (const struct openvpn_sockaddr *addr) +{ +#if ENABLE_IP_PKTINFO + if (!addr) return 0; + switch (addr->addr.sa.sa_family) { + case AF_INET: return addr->pi.in.ipi_spec_dst.s_addr != 0; +#ifdef USE_PF_UNIX + case AF_UNIX: ASSERT(0); +#endif +#ifdef USE_PF_INET6 + case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->pi.in6.ipi6_addr); +#endif + default: return 0; + } +#else + ASSERT(0); +#endif +} +static inline bool +addr_defined_sa (const struct sockaddr *addr) +{ + struct openvpn_sockaddr osa; + memcpy(&osa.addr.sa, addr, sizeof (osa.addr)); + return addr_defined(&osa); } static inline bool -addr_match (const struct sockaddr_in *a1, const struct sockaddr_in *a2) +link_addr_defined (const struct openvpn_sockaddr *act) { - return a1->sin_addr.s_addr == a2->sin_addr.s_addr; + return addr_defined (act); +} +static inline bool +addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) +{ + switch(a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in.sin_addr.s_addr == a2->addr.in.sin_addr.s_addr; +#ifdef USE_PF_UNIX + case AF_UNIX: + return strncmp(a1->addr.un.sun_path, a2->addr.un.sun_path, sizeof (a1->addr.un.sun_path)) == 0; +#endif +#ifdef USE_PF_INET6 + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); +#endif + } + ASSERT(0); + return false; } static inline in_addr_t -addr_host (const struct sockaddr_in *s) +addr_host (const struct openvpn_sockaddr *addr) { - return ntohl (s->sin_addr.s_addr); + /* + * "public" addr returned is checked against ifconfig for + * possible clash: non sense for now given + * that we do ifconfig only IPv4 + */ +#if defined(USE_PF_INET6) || defined(USE_PF_UNIX) + if(addr->addr.sa.sa_family != AF_INET) + return 0; +#else + ASSERT(addr->addr.sa.sa_family == AF_INET); +#endif + return ntohl (addr->addr.in.sin_addr.s_addr); } static inline bool -addr_port_match (const struct sockaddr_in *a1, const struct sockaddr_in *a2) +addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - return a1->sin_addr.s_addr == a2->sin_addr.s_addr - && a1->sin_port == a2->sin_port; + switch(a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in.sin_addr.s_addr == a2->addr.in.sin_addr.s_addr + && a1->addr.in.sin_port == a2->addr.in.sin_port; +#ifdef USE_PF_UNIX + case AF_UNIX: + return strncmp(a1->addr.un.sun_path, a2->addr.un.sun_path, sizeof (a1->addr.un.sun_path)) == 0; +#endif +#ifdef USE_PF_INET6 + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) + && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port; +#endif + } + ASSERT(0); + return false; } static inline bool -addr_match_proto (const struct sockaddr_in *a1, - const struct sockaddr_in *a2, +addr_match_proto (const struct openvpn_sockaddr *a1, + const struct openvpn_sockaddr *a2, const int proto) { return link_socket_proto_connection_oriented (proto) @@ -473,6 +631,93 @@ : addr_port_match (a1, a2); } +static inline void +addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) +{ + dst->addr = src->addr; +} + +static inline void +addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) +{ + switch(src->addr.sa.sa_family) { + case AF_INET: + dst->addr.in.sin_addr.s_addr = src->addr.in.sin_addr.s_addr; + break; +#ifdef USE_PF_UNIX + case AF_UNIX: + strncpynt(dst->addr.un.sun_path, src->addr.un.sun_path, sizeof dst->addr.un.sun_path); + break; +#endif +#ifdef USE_PF_INET6 + case AF_INET6: + dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr; + break; +#endif + } +} + + +static inline void +addr_zero_host(struct openvpn_sockaddr *addr) +{ + switch(addr->addr.sa.sa_family) { + case AF_INET: + addr->addr.in.sin_addr.s_addr = 0; + break; +#ifdef USE_PF_UNIX + case AF_UNIX: + *addr->addr.un.sun_path=0; + break; +#endif +#ifdef USE_PF_INET6 + case AF_INET6: + memset(&addr->addr.in6.sin6_addr, 0, sizeof (struct in6_addr)); + break; +#endif + } +} + +static inline bool +addr_inet4or6(struct sockaddr *addr) +{ + return addr->sa_family == AF_INET || addr->sa_family == AF_INET6; +} +int +addr_guess_family(int proto, const char *name); + +static inline int +af_addr_size(sa_family_t af) +{ +#if defined(USE_PF_INET6) || defined (USE_PF_UNIX) + switch(af) { + case AF_INET: return sizeof (struct sockaddr_in); +#ifdef USE_PF_UNIX + case AF_UNIX: return sizeof (struct sockaddr_un); +#endif +#ifdef USE_PF_INET6 + case AF_INET6: return sizeof (struct sockaddr_in6); +#endif + default: +#if 0 + /* could be called from socket_do_accept() with empty addr */ + msg (M_ERR, "Bad address family: %d\n", addr->sa_family); + ASSERT(0); +#endif + return 0; + } +#else /* only AF_INET */ + return sizeof(struct sockaddr_in); +#endif +} + + +static inline bool +link_addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) +{ + return addr_port_match (a1, a2); +} + static inline bool socket_connection_reset (const struct link_socket *sock, int status) { @@ -496,18 +741,25 @@ static inline bool link_socket_verify_incoming_addr (struct buffer *buf, const struct link_socket_info *info, - const struct sockaddr_in *from_addr) + const struct openvpn_sockaddr *from_addr) { if (buf->len > 0) { - if (from_addr->sin_family != AF_INET) - return false; - if (!addr_defined (from_addr)) - return false; - if (info->remote_float || !addr_defined (&info->lsa->remote)) - return true; - if (addr_match_proto (from_addr, &info->lsa->remote, info->proto)) - return true; + switch (from_addr->addr.sa.sa_family) { +#ifdef USE_PF_UNIX + case AF_UNIX: +#endif +#ifdef USE_PF_INET6 + case AF_INET6: +#endif + case AF_INET: + if (!addr_defined (from_addr)) + return false; + if (info->remote_float || !addr_defined (&info->lsa->remote)) + return true; + if (addr_match_proto (from_addr, &info->lsa->remote, info->proto)) + return true; + } } return false; } @@ -515,16 +767,15 @@ static inline void link_socket_get_outgoing_addr (struct buffer *buf, const struct link_socket_info *info, - struct sockaddr_in *addr) + struct openvpn_sockaddr **act) { if (buf->len > 0) { struct link_socket_addr *lsa = info->lsa; - if (addr_defined (&lsa->actual)) + if (link_addr_defined (&lsa->actual)) { - addr->sin_family = lsa->actual.sin_family; - addr->sin_addr.s_addr = lsa->actual.sin_addr.s_addr; - addr->sin_port = lsa->actual.sin_port; + //addr_copy(addr, &lsa->actual.addr); + *act = &lsa->actual; } else { @@ -537,7 +788,7 @@ static inline void link_socket_set_outgoing_addr (const struct buffer *buf, struct link_socket_info *info, - const struct sockaddr_in *addr, + const struct openvpn_sockaddr *addr, const char *common_name, struct env_set *es) { @@ -601,34 +852,48 @@ int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from); + struct openvpn_sockaddr *from); #endif +#ifdef USE_PF_UNIX +int link_socket_read_unix_dgram (struct link_socket *sock, + struct buffer *buf, + int maxsize, + struct sockaddr_un *from); +#endif /* read a TCP or UDP packet from link */ static inline int link_socket_read (struct link_socket *sock, struct buffer *buf, int maxsize, - struct sockaddr_in *from) + struct openvpn_sockaddr *from) { - if (sock->info.proto == PROTO_UDPv4) + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { int res; #ifdef WIN32 - res = link_socket_read_udp_win32 (sock, buf, from); + res = link_socket_read_udp_win32 (sock, buf, from->in); #else res = link_socket_read_udp_posix (sock, buf, maxsize, from); #endif return res; } - else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT) + else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ { /* from address was returned by accept */ - *from = sock->info.lsa->actual; + addr_copy_sa(from, &sock->info.lsa->actual); return link_socket_read_tcp (sock, buf); } +#ifdef USE_PF_UNIX + else if (sock->info.proto == PROTO_UNIX_DGRAM) + { + int res; + res = link_socket_read_unix_dgram (sock, buf, maxsize, &from->addr.un); + return res; + } +#endif else { ASSERT (0); @@ -642,14 +907,14 @@ int link_socket_write_tcp (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to); + struct openvpn_sockaddr *to); #ifdef WIN32 static inline int link_socket_write_win32 (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { int err = 0; int status = 0; @@ -659,7 +924,7 @@ if (status < 0) err = WSAGetLastError (); } - socket_send_queue (sock, buf, to); + socket_send_queue (sock, buf, to->addr); if (status < 0) { WSASetLastError (err); @@ -674,30 +939,57 @@ static inline int link_socket_write_udp_posix (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { - return sendto (sock->sd, BPTR (buf), BLEN (buf), 0, - (struct sockaddr *) to, - (socklen_t) sizeof (*to)); +#if ENABLE_IP_PKTINFO + int link_socket_write_udp_posix_sendmsg (struct link_socket *sock, + struct buffer *buf, + struct openvpn_sockaddr *to); + + /* + if (sock->info.proto == PROTO_UDPv4 && (sock->socket_flags & SF_USE_IP_PKTINFO) + && to->pi.in.ipi_spec_dst.s_addr) + + */ + if (proto_is_udp(sock->info.proto) && (sock->socket_flags & SF_USE_IP_PKTINFO) + && addr_defined_ipi(to)) + return link_socket_write_udp_posix_sendmsg (sock, buf, to); + else +#endif + return sendto (sock->sd, BPTR (buf), BLEN (buf), 0, + &to->addr.sa, + (socklen_t) af_addr_size(to->addr.sa.sa_family)); } static inline int link_socket_write_tcp_posix (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { return send (sock->sd, BPTR (buf), BLEN (buf), MSG_NOSIGNAL); } #endif +#ifdef USE_PF_UNIX +static inline int +link_socket_write_unix_dgram (struct link_socket *sock, + struct buffer *buf, + struct sockaddr_un *to) +{ + return sendto (sock->sd, BPTR (buf), BLEN (buf), 0, + (struct sockaddr *) to, + (socklen_t) sizeof (*to)); +} +#endif + static inline int link_socket_write_udp (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { #ifdef WIN32 - return link_socket_write_win32 (sock, buf, to); + return link_socket_write_win32 (sock, buf, to->in); #else return link_socket_write_udp_posix (sock, buf, to); #endif @@ -707,16 +999,22 @@ static inline int link_socket_write (struct link_socket *sock, struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { - if (sock->info.proto == PROTO_UDPv4) + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { return link_socket_write_udp (sock, buf, to); } - else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT) + else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ { return link_socket_write_tcp (sock, buf, to); } +#ifdef USE_PF_UNIX + else if (sock->info.proto == PROTO_UNIX_DGRAM) + { + return link_socket_write_unix_dgram (sock, buf, &to->addr.un); + } +#endif else { ASSERT (0); diff -u openvpn-2/socks.c:1.4 openvpn-2/socks.c:1.4.6.1 --- socks.c:1.4 Tue Apr 19 15:16:51 2005 +++ socks.c Mon May 2 10:33:50 2005 @@ -148,7 +148,7 @@ } static bool -recv_socks_reply (socket_descriptor_t sd, struct sockaddr_in *addr, +recv_socks_reply (socket_descriptor_t sd, struct openvpn_sockaddr *addr, volatile int *signal_received) { char atyp = '\0'; @@ -159,9 +159,9 @@ if (addr != NULL) { - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = htonl (INADDR_ANY); - addr->sin_port = htons (0); + addr->addr.in.sin_family = AF_INET; + addr->addr.in.sin_addr.s_addr = htonl (INADDR_ANY); + addr->addr.in.sin_port = htons (0); } while (len < 4 + alen + 2) @@ -248,8 +248,8 @@ /* ATYP == 1 (IP V4 address) */ if (atyp == '\x01' && addr != NULL) { - memcpy (&addr->sin_addr, buf + 4, sizeof (addr->sin_addr)); - memcpy (&addr->sin_port, buf + 8, sizeof (addr->sin_port)); + memcpy (&addr->addr.in.sin_addr, buf + 4, sizeof (addr->addr.in.sin_addr)); + memcpy (&addr->addr.in.sin_port, buf + 8, sizeof (addr->addr.in.sin_port)); } @@ -310,7 +310,7 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p, socket_descriptor_t ctrl_sd, /* already open to proxy */ socket_descriptor_t udp_sd, - struct sockaddr_in *relay_addr, + struct openvpn_sockaddr *relay_addr, volatile int *signal_received) { if (!socks_handshake (ctrl_sd, signal_received)) @@ -385,7 +385,7 @@ */ int socks_process_outgoing_udp (struct buffer *buf, - struct sockaddr_in *to) + struct openvpn_sockaddr *to) { /* * Get a 10 byte subset buffer prepended to buf -- @@ -400,8 +400,8 @@ buf_write_u16 (&head, 0); /* RSV = 0 */ buf_write_u8 (&head, 0); /* FRAG = 0 */ buf_write_u8 (&head, '\x01'); /* ATYP = 1 (IP V4) */ - buf_write (&head, &to->sin_addr, sizeof (to->sin_addr)); - buf_write (&head, &to->sin_port, sizeof (to->sin_port)); + buf_write (&head, &to->addr.in.sin_addr, sizeof (to->addr.in.sin_addr)); + buf_write (&head, &to->addr.in.sin_port, sizeof (to->addr.in.sin_port)); return 10; } diff -u openvpn-2/socks.h:1.4 openvpn-2/socks.h:1.4.6.1 --- socks.h:1.4 Tue Apr 19 15:16:51 2005 +++ socks.h Mon May 2 10:33:50 2005 @@ -34,6 +34,8 @@ #include "buffer.h" +struct openvpn_sockaddr; + struct socks_proxy_info { bool defined; bool retry; @@ -58,14 +60,14 @@ void establish_socks_proxy_udpassoc (struct socks_proxy_info *p, socket_descriptor_t ctrl_sd, /* already open to proxy */ socket_descriptor_t udp_sd, - struct sockaddr_in *relay_addr, + struct openvpn_sockaddr *relay_addr, volatile int *signal_received); void socks_process_incoming_udp (struct buffer *buf, struct sockaddr_in *from); int socks_process_outgoing_udp (struct buffer *buf, - struct sockaddr_in *to); + struct openvpn_sockaddr *to); #endif #endif diff -u openvpn-2/ssl.c:1.4 openvpn-2/ssl.c:1.4.4.1 --- ssl.c:1.4 Tue Apr 19 15:16:51 2005 +++ ssl.c Mon May 2 10:33:50 2005 @@ -361,7 +361,7 @@ static void setenv_untrusted (struct tls_session *session) { - setenv_sockaddr (session->opt->es, "untrusted", &session->untrusted_sockaddr, SA_IP_PORT); + setenv_sockaddr (session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT); } static void @@ -1783,7 +1783,7 @@ write_control_auth (struct tls_session *session, struct key_state *ks, struct buffer *buf, - struct sockaddr_in *to_link_addr, + struct openvpn_sockaddr **to_link_addr, int opcode, int max_ack, bool prepend_ack) @@ -1791,7 +1791,7 @@ uint8_t *header; struct buffer null = clear_buf (); - ASSERT (addr_defined (&ks->remote_addr)); + ASSERT (link_addr_defined (&ks->remote_addr)); ASSERT (reliable_ack_write (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); ASSERT (session_id_write_prepend (&session->session_id, buf)); @@ -1803,7 +1803,7 @@ openvpn_encrypt (buf, null, &session->tls_auth, NULL); ASSERT (swap_hmac (buf, &session->tls_auth, false)); } - *to_link_addr = ks->remote_addr; + *to_link_addr = &ks->remote_addr; } /* @@ -1812,7 +1812,7 @@ static bool read_control_auth (struct buffer *buf, const struct crypto_options *co, - const struct sockaddr_in *from) + const struct openvpn_sockaddr *from) { struct gc_arena gc = gc_new (); @@ -1825,7 +1825,7 @@ { msg (D_TLS_ERRORS, "TLS Error: cannot locate HMAC in incoming packet from %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); gc_free (&gc); return false; } @@ -1837,7 +1837,7 @@ { msg (D_TLS_ERRORS, "TLS Error: incoming packet authentication failed from %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); gc_free (&gc); return false; } @@ -2719,7 +2719,7 @@ tls_process (struct tls_multi *multi, struct tls_session *session, struct buffer *to_link, - struct sockaddr_in *to_link_addr, + struct openvpn_sockaddr **to_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) { @@ -3112,7 +3112,7 @@ bool tls_multi_process (struct tls_multi *multi, struct buffer *to_link, - struct sockaddr_in *to_link_addr, + struct openvpn_sockaddr **to_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup) { @@ -3136,7 +3136,7 @@ /* set initial remote address */ if (i == TM_ACTIVE && ks->state == S_INITIAL && - addr_defined (&to_link_socket_info->lsa->actual)) + link_addr_defined (&to_link_socket_info->lsa->actual)) ks->remote_addr = to_link_socket_info->lsa->actual; dmsg (D_TLS_DEBUG, @@ -3145,17 +3145,30 @@ state_name (ks->state), session_id_print (&session->session_id, &gc), session_id_print (&ks->session_id_remote, &gc), - print_sockaddr (&ks->remote_addr, &gc)); + print_link_sockaddr (&ks->remote_addr, &gc)); - if (ks->state >= S_INITIAL && addr_defined (&ks->remote_addr)) + if (ks->state >= S_INITIAL && link_addr_defined (&ks->remote_addr)) { + struct openvpn_sockaddr *tla = NULL; + update_time (); - if (tls_process (multi, session, to_link, to_link_addr, + if (tls_process (multi, session, to_link, &tla, to_link_socket_info, wakeup)) active = true; /* + * If tls_process produced an outgoing packet, + * return the openvpn_sockaddr object (which + * contains the outgoing address). + */ + if (tla) + { + multi->to_link_addr = *tla; + *to_link_addr = &multi->to_link_addr; + } + + /* * If tls_process hits an error: * (1) If the session has an unexpired lame duck key, preserve it. * (2) Reinitialize the session. @@ -3274,7 +3287,7 @@ bool tls_pre_decrypt (struct tls_multi *multi, - struct sockaddr_in *from, + const struct openvpn_sockaddr *from, struct buffer *buf, struct crypto_options *opt) { @@ -3316,7 +3329,7 @@ if (DECRYPT_KEY_ENABLED (multi, ks) && key_id == ks->key_id && ks->authenticated - && addr_port_match(from, &ks->remote_addr)) + && link_addr_port_match(from, &ks->remote_addr)) { /* return appropriate data channel decrypt key in opt */ opt->key_ctx_bi = &ks->key; @@ -3329,7 +3342,7 @@ ks->n_bytes += buf->len; dmsg (D_TLS_DEBUG, "TLS: data channel, key_id=%d, IP=%s", - key_id, print_sockaddr (from, &gc)); + key_id, print_link_sockaddr (from, &gc)); gc_free (&gc); return ret; } @@ -3349,7 +3362,7 @@ msg (D_TLS_ERRORS, "TLS Error: local/remote TLS keys are out of sync: %s [%d]", - print_sockaddr (from, &gc), key_id); + print_link_sockaddr (from, &gc), key_id); goto error; } else /* control channel packet */ @@ -3363,7 +3376,7 @@ { msg (D_TLS_ERRORS, "TLS Error: unknown opcode received from %s op=%d", - print_sockaddr (from, &gc), op); + print_link_sockaddr (from, &gc), op); goto error; } @@ -3378,7 +3391,7 @@ { msg (D_TLS_ERRORS, "TLS Error: client->client or server->server connection attempted from %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } } @@ -3387,7 +3400,7 @@ * Authenticate Packet */ dmsg (D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s", - packet_opcode_name (op), print_sockaddr (from, &gc)); + packet_opcode_name (op), print_link_sockaddr (from, &gc)); /* get remote session-id */ { @@ -3397,7 +3410,7 @@ { msg (D_TLS_ERRORS, "TLS Error: session-id not found in packet from %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } } @@ -3414,9 +3427,9 @@ state_name (ks->state), session_id_print (&session->session_id, &gc), session_id_print (&sid, &gc), - print_sockaddr (from, &gc), + print_link_sockaddr (from, &gc), session_id_print (&ks->session_id_remote, &gc), - print_sockaddr (&ks->remote_addr, &gc)); + print_link_sockaddr (&ks->remote_addr, &gc)); if (session_id_equal (&ks->session_id_remote, &sid)) /* found a match */ @@ -3461,7 +3474,7 @@ { msg (D_TLS_ERRORS, "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [1]", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } @@ -3477,13 +3490,13 @@ msg (D_TLS_DEBUG_LOW, "TLS: Initial packet from %s, sid=%s", - print_sockaddr (from, &gc), + print_link_sockaddr (from, &gc), session_id_print (&sid, &gc)); do_burst = true; new_link = true; i = TM_ACTIVE; - session->untrusted_sockaddr = *from; + session->untrusted_addr = *from; } } @@ -3503,7 +3516,7 @@ { msg (D_TLS_ERRORS, "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [2]", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } @@ -3526,11 +3539,11 @@ */ msg (D_TLS_DEBUG_LOW, "TLS: new session incoming connection from %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); new_link = true; i = TM_UNTRUSTED; - session->untrusted_sockaddr = *from; + session->untrusted_addr = *from; } else { @@ -3544,7 +3557,7 @@ { msg (D_TLS_ERRORS, "TLS Error: Unroutable control packet received from %s (si=%d op=%s)", - print_sockaddr (from, &gc), + print_link_sockaddr (from, &gc), i, packet_opcode_name (op)); goto error; @@ -3553,10 +3566,10 @@ /* * Verify remote IP address */ - if (!new_link && !addr_port_match (&ks->remote_addr, from)) + if (!new_link && !link_addr_port_match (&ks->remote_addr, from)) { msg (D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } @@ -3618,11 +3631,11 @@ ks->remote_addr = *from; ++multi->n_sessions; } - else if (!addr_port_match (&ks->remote_addr, from)) + else if (!link_addr_port_match (&ks->remote_addr, from)) { msg (D_TLS_ERRORS, "TLS Error: Existing session control channel packet from unknown IP address: %s", - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } @@ -3719,7 +3732,7 @@ */ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, - const struct sockaddr_in *from, + const struct openvpn_sockaddr *from, const struct buffer *buf) { struct gc_arena gc = gc_new (); @@ -3747,7 +3760,7 @@ */ dmsg (D_TLS_STATE_ERRORS, "TLS State Error: No TLS state for client %s, opcode=%d", - print_sockaddr (from, &gc), + print_link_sockaddr (from, &gc), op); goto error; } @@ -3757,7 +3770,7 @@ dmsg (D_TLS_STATE_ERRORS, "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected", key_id, - print_sockaddr (from, &gc)); + print_link_sockaddr (from, &gc)); goto error; } @@ -3766,7 +3779,7 @@ dmsg (D_TLS_STATE_ERRORS, "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected", buf->len, - print_sockaddr (from, &gc), + print_link_sockaddr (from, &gc), EXPANDED_SIZE_DYNAMIC (&tas->frame)); goto error; } diff -u openvpn-2/ssl.h:1.4 openvpn-2/ssl.h:1.4.4.1 --- ssl.h:1.4 Tue Apr 19 15:16:51 2005 +++ ssl.h Mon May 2 10:33:50 2005 @@ -345,7 +345,7 @@ int initial_opcode; /* our initial P_ opcode */ struct session_id session_id_remote; /* peer's random session ID */ - struct sockaddr_in remote_addr; /* peer's IP addr */ + struct openvpn_sockaddr remote_addr; /* peer's IP addr */ struct packet_id packet_id; /* for data channel, to prevent replay attacks */ struct key_ctx_bi key; /* data channel keys for encrypt/decrypt/hmac */ @@ -488,7 +488,7 @@ bool verified; /* true if peer certificate was verified against CA */ /* not-yet-authenticated incoming client */ - struct sockaddr_in untrusted_sockaddr; + struct openvpn_sockaddr untrusted_addr; struct key_state key[KS_SIZE]; }; @@ -535,6 +535,12 @@ struct key_state *save_ks; /* temporary pointer used between pre/post routines */ /* + * Used to return outgoing address from + * tls_multi_process. + */ + struct openvpn_sockaddr to_link_addr; + + /* * Number of sessions negotiated thus far. */ int n_sessions; @@ -590,19 +596,19 @@ bool tls_multi_process (struct tls_multi *multi, struct buffer *to_link, - struct sockaddr_in *to_link_addr, + struct openvpn_sockaddr **to_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup); void tls_multi_free (struct tls_multi *multi, bool clear); bool tls_pre_decrypt (struct tls_multi *multi, - struct sockaddr_in *from, + const struct openvpn_sockaddr *from, struct buffer *buf, struct crypto_options *opt); bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, - const struct sockaddr_in *from, + const struct openvpn_sockaddr *from, const struct buffer *buf); void tls_pre_encrypt (struct tls_multi *multi, diff -u openvpn-2/syshead.h:1.4 openvpn-2/syshead.h:1.4.4.2 --- syshead.h:1.4 Tue Apr 19 15:16:51 2005 +++ syshead.h Mon May 2 13:41:16 2005 @@ -57,6 +57,14 @@ #include #endif +#ifdef USE_PF_UNIX +#include +#endif + +#ifdef USE_PF_INET6 +#include +#endif + #ifdef HAVE_SYS_IOCTL_H #include #endif @@ -290,6 +298,15 @@ #endif /* + * Does this platform support linux-style IP_PKTINFO? + */ +#if defined(ENABLE_MULTIHOME) && defined(HAVE_IN_PKTINFO) && defined(IP_PKTINFO) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG) +#define ENABLE_IP_PKTINFO 1 +#else +#define ENABLE_IP_PKTINFO 0 +#endif + +/* * Disable ESEC */ #if 0