summaryrefslogtreecommitdiff
path: root/debian/patches/jjo-ipv6-support.patch
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2011-12-13 11:04:22 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2012-02-21 15:53:41 +0100
commit3cedd1dd9877a0bae3e69d27c3d1a2fcd98787c0 (patch)
treea1af6e31567b9a7a992bc90d6106a7cfb0c67b37 /debian/patches/jjo-ipv6-support.patch
parent349cfa7acb95abe865209a28e417ec74b56f9bba (diff)
Imported Debian patch 2.2.1-1debian/2.2.1-1
Diffstat (limited to 'debian/patches/jjo-ipv6-support.patch')
-rw-r--r--debian/patches/jjo-ipv6-support.patch4011
1 files changed, 4011 insertions, 0 deletions
diff --git a/debian/patches/jjo-ipv6-support.patch b/debian/patches/jjo-ipv6-support.patch
new file mode 100644
index 0000000..c516763
--- /dev/null
+++ b/debian/patches/jjo-ipv6-support.patch
@@ -0,0 +1,4011 @@
+Description: OpenVPN over UDP6/TCP6 patch
+Author: JuanJo Ciarlante <jjo@google.com>
+URL: https://github.com/jjo/openvpn-ipv6/
+Index: openvpn-2.2.1/README.ipv6
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openvpn-2.2.1/README.ipv6 2011-12-13 12:23:07.264081559 +0100
+@@ -0,0 +1,81 @@
++[ Last updated: 25-Mar-2011. ]
++
++OpenVPN-2.1 over UDP6/TCP6 README for ipv6-0.4.x patch releases:
++( --udp6 and --tcp6-{client,server} )
++
++* Availability
++ Source code under GPLv2 from http://github.com/jjo/openvpn-ipv6
++
++ Distro ready repos/packages:
++ o Debian sid official repo, by Alberto Gonzalez Iniesta,
++ starting from openvpn_2.1~rc20-2
++ o Gentoo official portage tree, by Marcel Pennewiss:
++ - https://bugs.gentoo.org/show_bug.cgi?id=287896
++ o Ubuntu package, by Bernhard Schmidt:
++ - https://launchpad.net/~berni/+archive/ipv6/+packages
++ o Freetz.org, milestone freetz-1.2
++ - http://trac.freetz.org/milestone/freetz-1.2
++
++* Status:
++ o OK:
++ - upd6,tcp6: GNU/Linux, win32, openbsd-4.7, freebsd-8.1
++ - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux
++ (gives a warning on local!=remote proto matching)
++ o NOT:
++ - win32: tcp4->tcp6 (ipv4/6 mapped) fails w/connection refused
++ o NOT tested:
++ - mgmt console
++
++* Build setup:
++ ./configure --enable-ipv6 (by default)
++
++* Usage:
++ For IPv6 just specify "-p upd6" an proper IPv6 hostnames, adapting the example
++ from man page ...
++
++ On may:
++ openvpn --proto udp6 --remote <june_IPv6_addr> --dev tun1 \
++ --ifconfig 10.4.0.1 10.4.0.2 --verb 5 --secret key
++
++ On june:
++ openvpn --proto udp6 --remote <may_IPv6_addr> --dev tun1 \
++ --ifconfig 10.4.0.2 10.4.0.1 --verb 5 --secret key
++
++ Same for --proto tcp6-client, tcp6-server.
++
++* 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;
++ } addr;
++ };
++
++ 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: See TODO.ipv6
++
++--
++JuanJo Ciarlante jjo () google () com ............................
++: :
++. Linux IP Aliasing author .
++. Modular algo (AES et all) support for FreeSWAN/OpenSWAN author .
++. OpenVPN over IPv6 support .
++:...... plus other scattered free software bits in the wild ...:
+Index: openvpn-2.2.1/TODO.ipv6
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openvpn-2.2.1/TODO.ipv6 2011-12-13 12:23:07.267081520 +0100
+@@ -0,0 +1,30 @@
++[ Last updated: 11-Nov-2009. ]
++
++* All platforms:
++ o mgmt console: as currently passes straight in_addr_t bits around
++
++ o make possible to get AF from getaddrinfo() answer, ie allow openvpn to
++ use ipv4/6 if DNS returns A/AAAA without specifying protocol.
++ Hard: requires deep changes in initialization/calling logic
++
++ o use AI_PASSIVE
++
++ o the getaddr()/getaddr6() interface is not prepared for handling socktype
++ "tagging", currently I abuse the sockflags bits for getting the ai_socktype
++ downstream.
++
++ o implement comparison for mapped addesses: server in dual stack
++ listening IPv6 must permit incoming streams from allowed IPv4 peer,
++ currently you need to pass eg: --remote ffff::1.2.3.4
++
++ o do something with multi mode learn routes, for now just ignoring
++ ipv6 addresses seems the most sensible thing to do, because there's
++ no support for intra-tunnel ipv6 stuff.
++
++* win32:
++ o find out about mapped addresses, as I can't make it work
++ with bound at ::1 and connect to 127.0.0.1
++
++* N/A:
++ o this is ipv6 *endpoint* support, so don't expect "ifconfig6"-like
++ support in this patch
+Index: openvpn-2.2.1/acinclude.m4
+===================================================================
+--- openvpn-2.2.1.orig/acinclude.m4 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/acinclude.m4 2011-12-13 12:23:07.290081232 +0100
+@@ -123,5 +123,9 @@
+ AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
+ [type to use in place of socklen_t if not defined])],
+ [#include <sys/types.h>
+-#include <sys/socket.h>])
++#ifdef WIN32
++#include <ws2tcpip.h>
++#else
++#include <sys/socket.h>
++#endif])
+ ])
+Index: openvpn-2.2.1/aclocal.m4
+===================================================================
+--- openvpn-2.2.1.orig/aclocal.m4 2011-07-01 11:26:36.000000000 +0200
++++ openvpn-2.2.1/aclocal.m4 2011-12-13 12:23:07.323080820 +0100
+@@ -13,8 +13,8 @@
+
+ m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.66],,
+-[m4_warning([this file was generated for autoconf 2.66.
++m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],,
++[m4_warning([this file was generated for autoconf 2.65.
+ You have another version of autoconf. It may work, but is not guaranteed to.
+ If you have problems, you may need to regenerate the build system entirely.
+ To do so, use the procedure documented by the package, typically `autoreconf'.])])
+Index: openvpn-2.2.1/buffer.c
+===================================================================
+--- openvpn-2.2.1.orig/buffer.c 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/buffer.c 2011-12-13 12:23:07.326080784 +0100
+@@ -214,6 +214,23 @@
+ return ret;
+ }
+
++bool
++buf_puts(struct buffer *buf, const char *str)
++{
++ int ret = false;
++ 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);
++ ret = true;
++ }
++ return ret;
++}
++
++
+ /*
+ * This is necessary due to certain buggy implementations of snprintf,
+ * that don't guarantee null termination for size > 0.
+Index: openvpn-2.2.1/buffer.h
+===================================================================
+--- openvpn-2.2.1.orig/buffer.h 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/buffer.h 2011-12-13 12:23:07.329080745 +0100
+@@ -277,6 +277,11 @@
+ ;
+
+ /*
++ * puts append to a buffer with overflow check
++ */
++bool 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, ...)
+Index: openvpn-2.2.1/config.h.in
+===================================================================
+--- openvpn-2.2.1.orig/config.h.in 2011-07-01 11:26:37.000000000 +0200
++++ openvpn-2.2.1/config.h.in 2011-12-13 12:23:07.332080708 +0100
+@@ -531,6 +531,9 @@
+ /* Use LZO compression library */
+ #undef USE_LZO
+
++/* struct sockaddr_in6 is needed for IPv6 peer support */
++#undef USE_PF_INET6
++
+ /* Enable PKCS11 capability */
+ #undef USE_PKCS11
+
+Index: openvpn-2.2.1/configure
+===================================================================
+--- openvpn-2.2.1.orig/configure 2011-07-01 11:26:37.000000000 +0200
++++ openvpn-2.2.1/configure 2011-12-13 12:23:07.347080520 +0100
+@@ -319,7 +319,7 @@
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
++ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+ } # as_fn_mkdir_p
+@@ -359,19 +359,19 @@
+ fi # as_fn_arith
+
+
+-# as_fn_error STATUS ERROR [LINENO LOG_FD]
+-# ----------------------------------------
++# as_fn_error ERROR [LINENO LOG_FD]
++# ---------------------------------
+ # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+ # provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+-# script with STATUS, using 1 if that was 0.
++# script with status $?, using 1 if that was 0.
+ as_fn_error ()
+ {
+- as_status=$1; test $as_status -eq 0 && as_status=1
+- if test "$4"; then
+- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ as_status=$?; test $as_status -eq 0 && as_status=1
++ if test "$3"; then
++ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+- $as_echo "$as_me: error: $2" >&2
++ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+ } # as_fn_error
+
+@@ -533,7 +533,7 @@
+ exec 6>&1
+
+ # Name of the host.
+-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
++# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+ # so uname gets run too.
+ ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+@@ -715,6 +715,7 @@
+ enable_http
+ enable_fragment
+ enable_multihome
++enable_ipv6
+ enable_port_share
+ enable_debug
+ enable_small
+@@ -858,7 +859,7 @@
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+- as_fn_error $? "invalid feature name: $ac_useropt"
++ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+@@ -884,7 +885,7 @@
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+- as_fn_error $? "invalid feature name: $ac_useropt"
++ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+@@ -1088,7 +1089,7 @@
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+- as_fn_error $? "invalid package name: $ac_useropt"
++ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+@@ -1104,7 +1105,7 @@
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+- as_fn_error $? "invalid package name: $ac_useropt"
++ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+@@ -1134,8 +1135,8 @@
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+- -*) as_fn_error $? "unrecognized option: \`$ac_option'
+-Try \`$0 --help' for more information"
++ -*) as_fn_error "unrecognized option: \`$ac_option'
++Try \`$0 --help' for more information."
+ ;;
+
+ *=*)
+@@ -1143,7 +1144,7 @@
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
++ as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+@@ -1161,13 +1162,13 @@
+
+ if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+- as_fn_error $? "missing argument to $ac_option"
++ as_fn_error "missing argument to $ac_option"
+ fi
+
+ if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
++ fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+ fi
+@@ -1190,7 +1191,7 @@
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
++ as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
+ done
+
+ # There might be people who depend on the old broken behavior: `$host'
+@@ -1204,8 +1205,8 @@
+ if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+- $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+- If a cross compiler is detected then cross compile mode will be used" >&2
++ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
++ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+@@ -1220,9 +1221,9 @@
+ ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ ac_ls_di=`ls -di .` &&
+ ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+- as_fn_error $? "working directory cannot be determined"
++ as_fn_error "working directory cannot be determined"
+ test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+- as_fn_error $? "pwd does not report name of working directory"
++ as_fn_error "pwd does not report name of working directory"
+
+
+ # Find the source files, if location was not specified.
+@@ -1261,11 +1262,11 @@
+ fi
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
++ as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
+ fi
+ ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ ac_abs_confdir=`(
+- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
++ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
+ pwd)`
+ # When building in place, set srcdir=.
+ if test "$ac_abs_confdir" = "$ac_pwd"; then
+@@ -1305,7 +1306,7 @@
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+- -q, --quiet, --silent do not print \`checking ...' messages
++ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+@@ -1383,6 +1384,7 @@
+ --disable-http Disable HTTP proxy support
+ --disable-fragment Disable internal fragmentation support (--fragment)
+ --disable-multihome Disable multi-homed UDP server support (--multihome)
++ --disable-ipv6 Disable UDP/IPv6 support
+ --disable-port-share Disable TCP server port-share support (--port-share)
+ --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)
+@@ -1588,10 +1590,10 @@
+ ac_fn_c_check_header_mongrel ()
+ {
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+- if eval "test \"\${$3+set}\"" = set; then :
++ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+ $as_echo_n "checking for $2... " >&6; }
+-if eval "test \"\${$3+set}\"" = set; then :
++if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ fi
+ eval ac_res=\$$3
+@@ -1650,15 +1652,17 @@
+ $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+ $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+-( $as_echo "## -------------------------------------------------- ##
++( cat <<\_ASBOX
++## -------------------------------------------------- ##
+ ## Report this to openvpn-users@lists.sourceforge.net ##
+-## -------------------------------------------------- ##"
++## -------------------------------------------------- ##
++_ASBOX
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+ $as_echo_n "checking for $2... " >&6; }
+-if eval "test \"\${$3+set}\"" = set; then :
++if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ eval "$3=\$ac_header_compiler"
+@@ -1722,7 +1726,7 @@
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+ $as_echo_n "checking for $2... " >&6; }
+-if eval "test \"\${$3+set}\"" = set; then :
++if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+@@ -1753,7 +1757,7 @@
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+ $as_echo_n "checking for $2... " >&6; }
+-if eval "test \"\${$3+set}\"" = set; then :
++if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ eval "$3=no"
+@@ -2030,7 +2034,7 @@
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+ $as_echo_n "checking for $2... " >&6; }
+-if eval "test \"\${$3+set}\"" = set; then :
++if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+@@ -2203,9 +2207,11 @@
+ {
+ echo
+
+- $as_echo "## ---------------- ##
++ cat <<\_ASBOX
++## ---------------- ##
+ ## Cache variables. ##
+-## ---------------- ##"
++## ---------------- ##
++_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+ (
+@@ -2239,9 +2245,11 @@
+ )
+ echo
+
+- $as_echo "## ----------------- ##
++ cat <<\_ASBOX
++## ----------------- ##
+ ## Output variables. ##
+-## ----------------- ##"
++## ----------------- ##
++_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+@@ -2254,9 +2262,11 @@
+ echo
+
+ if test -n "$ac_subst_files"; then
+- $as_echo "## ------------------- ##
++ cat <<\_ASBOX
++## ------------------- ##
+ ## File substitutions. ##
+-## ------------------- ##"
++## ------------------- ##
++_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+@@ -2270,9 +2280,11 @@
+ fi
+
+ if test -s confdefs.h; then
+- $as_echo "## ----------- ##
++ cat <<\_ASBOX
++## ----------- ##
+ ## confdefs.h. ##
+-## ----------- ##"
++## ----------- ##
++_ASBOX
+ echo
+ cat confdefs.h
+ echo
+@@ -2327,12 +2339,7 @@
+ ac_site_file1=NONE
+ ac_site_file2=NONE
+ if test -n "$CONFIG_SITE"; then
+- # We do not want a PATH search for config.site.
+- case $CONFIG_SITE in #((
+- -*) ac_site_file1=./$CONFIG_SITE;;
+- */*) ac_site_file1=$CONFIG_SITE;;
+- *) ac_site_file1=./$CONFIG_SITE;;
+- esac
++ ac_site_file1=$CONFIG_SITE
+ elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+@@ -2347,11 +2354,7 @@
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+ $as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+- . "$ac_site_file" \
+- || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "failed to load site script $ac_site_file
+-See \`config.log' for more details" "$LINENO" 5; }
++ . "$ac_site_file"
+ fi
+ done
+
+@@ -2427,7 +2430,7 @@
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+ $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+- as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
++ as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+ fi
+ ## -------------------- ##
+ ## Main body of script. ##
+@@ -2446,22 +2449,16 @@
+
+ ac_aux_dir=
+ for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+- if test -f "$ac_dir/install-sh"; then
+- ac_aux_dir=$ac_dir
+- ac_install_sh="$ac_aux_dir/install-sh -c"
+- break
+- elif test -f "$ac_dir/install.sh"; then
+- ac_aux_dir=$ac_dir
+- ac_install_sh="$ac_aux_dir/install.sh -c"
+- break
+- elif test -f "$ac_dir/shtool"; then
+- ac_aux_dir=$ac_dir
+- ac_install_sh="$ac_aux_dir/shtool install -c"
+- break
+- fi
++ for ac_t in install-sh install.sh shtool; do
++ if test -f "$ac_dir/$ac_t"; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh="$ac_aux_dir/$ac_t -c"
++ break 2
++ fi
++ done
+ done
+ if test -z "$ac_aux_dir"; then
+- as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
++ as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+ fi
+
+ # These three variables are undocumented and unsupported,
+@@ -2475,7 +2472,7 @@
+
+ # Make sure we can run config.sub.
+ $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
++ as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+ $as_echo_n "checking build system type... " >&6; }
+@@ -2486,16 +2483,16 @@
+ test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+ test "x$ac_build_alias" = x &&
+- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
++ as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
+ ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
++ as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+ $as_echo "$ac_cv_build" >&6; }
+ case $ac_cv_build in
+ *-*-*) ;;
+-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
++*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
+ esac
+ build=$ac_cv_build
+ ac_save_IFS=$IFS; IFS='-'
+@@ -2520,7 +2517,7 @@
+ ac_cv_host=$ac_cv_build
+ else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
++ as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+ fi
+
+ fi
+@@ -2528,7 +2525,7 @@
+ $as_echo "$ac_cv_host" >&6; }
+ case $ac_cv_host in
+ *-*-*) ;;
+-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
++*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
+ esac
+ host=$ac_cv_host
+ ac_save_IFS=$IFS; IFS='-'
+@@ -2650,11 +2647,11 @@
+ '
+ case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+- as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
++ as_fn_error "unsafe absolute working directory name" "$LINENO" 5;;
+ esac
+ case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+- as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
++ as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+ esac
+
+ # Do `set' in a subshell so we don't clobber the current shell's
+@@ -2676,7 +2673,7 @@
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+- as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
++ as_fn_error "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+
+@@ -2686,7 +2683,7 @@
+ # Ok.
+ :
+ else
+- as_fn_error $? "newly created file is older than distributed files!
++ as_fn_error "newly created file is older than distributed files!
+ Check your system clock" "$LINENO" 5
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+@@ -2924,7 +2921,7 @@
+ $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+ set x ${MAKE-make}
+ ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+-if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then :
++if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ cat >conftest.make <<\_ACEOF
+@@ -2932,7 +2929,7 @@
+ all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+ _ACEOF
+-# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
++# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+ case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+@@ -2966,7 +2963,7 @@
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+- as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
++ as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+ fi
+
+@@ -3184,6 +3181,15 @@
+ fi
+
+
++# Check whether --enable-ipv6 was given.
++if test "${enable_ipv6+set}" = set; then :
++ enableval=$enable_ipv6; PF_INET6="$enableval"
++else
++ PF_INET6="yes"
++
++fi
++
++
+ # Check whether --enable-port-share was given.
+ if test "${enable_port_share+set}" = set; then :
+ enableval=$enable_port_share; PORT_SHARE="$enableval"
+@@ -3954,8 +3960,8 @@
+
+ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "no acceptable C compiler found in \$PATH
+-See \`config.log' for more details" "$LINENO" 5; }
++as_fn_error "no acceptable C compiler found in \$PATH
++See \`config.log' for more details." "$LINENO" 5; }
+
+ # Provide some information about the compiler.
+ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+@@ -4069,8 +4075,9 @@
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error 77 "C compiler cannot create executables
+-See \`config.log' for more details" "$LINENO" 5; }
++{ as_fn_set_status 77
++as_fn_error "C compiler cannot create executables
++See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ $as_echo "yes" >&6; }
+@@ -4112,8 +4119,8 @@
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+-See \`config.log' for more details" "$LINENO" 5; }
++as_fn_error "cannot compute suffix of executables: cannot compile and link
++See \`config.log' for more details." "$LINENO" 5; }
+ fi
+ rm -f conftest conftest$ac_cv_exeext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+@@ -4170,9 +4177,9 @@
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "cannot run C compiled programs.
++as_fn_error "cannot run C compiled programs.
+ If you meant to cross compile, use \`--host'.
+-See \`config.log' for more details" "$LINENO" 5; }
++See \`config.log' for more details." "$LINENO" 5; }
+ fi
+ fi
+ fi
+@@ -4223,8 +4230,8 @@
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "cannot compute suffix of object files: cannot compile
+-See \`config.log' for more details" "$LINENO" 5; }
++as_fn_error "cannot compute suffix of object files: cannot compile
++See \`config.log' for more details." "$LINENO" 5; }
+ fi
+ rm -f conftest.$ac_cv_objext conftest.$ac_ext
+ fi
+@@ -4762,8 +4769,8 @@
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+-See \`config.log' for more details" "$LINENO" 5; }
++as_fn_error "C preprocessor \"$CPP\" fails sanity check
++See \`config.log' for more details." "$LINENO" 5; }
+ fi
+
+ ac_ext=c
+@@ -4824,7 +4831,7 @@
+ done
+ IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
++ as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+ else
+ ac_cv_path_GREP=$GREP
+@@ -4890,7 +4897,7 @@
+ done
+ IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
++ as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+ else
+ ac_cv_path_EGREP=$EGREP
+@@ -5064,7 +5071,8 @@
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+ "
+-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
++eval as_val=\$$as_ac_Header
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+ _ACEOF
+@@ -5181,7 +5189,7 @@
+ test -n "$MAN2HTML" && break
+ done
+
+- test -z "${MAN2HTML}" && as_fn_error $? "man2html is required for win32" "$LINENO" 5
++ test -z "${MAN2HTML}" && as_fn_error "man2html is required for win32" "$LINENO" 5
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+@@ -5518,7 +5526,11 @@
+
+
+ ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include <sys/types.h>
++#ifdef WIN32
++#include <ws2tcpip.h>
++#else
+ #include <sys/socket.h>
++#endif
+ "
+ if test "x$ac_cv_type_socklen_t" = x""yes; then :
+
+@@ -5570,7 +5582,7 @@
+ esac
+
+ if test "x$curl_cv_socklen_t_equiv" = x; then
+- as_fn_error $? "Cannot find a type to use in place of socklen_t" "$LINENO" 5
++ as_fn_error "Cannot find a type to use in place of socklen_t" "$LINENO" 5
+ fi
+
+ fi
+@@ -5711,7 +5723,7 @@
+
+ else
+
+- as_fn_error $? "C compiler is unable to creaty empty arrays" "$LINENO" 5
++ as_fn_error "C compiler is unable to creaty empty arrays" "$LINENO" 5
+
+ fi
+ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+@@ -5725,7 +5737,8 @@
+ do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
++eval as_val=\$$as_ac_Header
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+ _ACEOF
+@@ -5781,7 +5794,8 @@
+ do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
++eval as_val=\$$as_ac_Header
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+ _ACEOF
+@@ -6077,8 +6091,9 @@
+ if test "$ac_cv_type_unsigned_int" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error 77 "cannot compute sizeof (unsigned int)
+-See \`config.log' for more details" "$LINENO" 5; }
++{ as_fn_set_status 77
++as_fn_error "cannot compute sizeof (unsigned int)
++See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_int=0
+ fi
+@@ -6110,8 +6125,9 @@
+ if test "$ac_cv_type_unsigned_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+-as_fn_error 77 "cannot compute sizeof (unsigned long)
+-See \`config.log' for more details" "$LINENO" 5; }
++{ as_fn_set_status 77
++as_fn_error "cannot compute sizeof (unsigned long)
++See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_long=0
+ fi
+@@ -6208,13 +6224,14 @@
+ do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
+ else
+- as_fn_error $? "Required library function not found" "$LINENO" 5
++ as_fn_error "Required library function not found" "$LINENO" 5
+ fi
+ done
+
+@@ -6222,7 +6239,8 @@
+ do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+@@ -6513,7 +6531,8 @@
+ do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+@@ -6727,13 +6746,14 @@
+ do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
+ else
+- as_fn_error $? "Required library function not found" "$LINENO" 5
++ as_fn_error "Required library function not found" "$LINENO" 5
+ fi
+ done
+
+@@ -6741,7 +6761,8 @@
+ do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+@@ -6861,6 +6882,19 @@
+
+ LDFLAGS="$OLDLDFLAGS"
+
++if test "$PF_INET6" = "yes"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_in6 for IPv6 support..." >&5
++$as_echo "$as_me: checking for struct sockaddr_in6 for IPv6 support..." >&6;}
++ ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#include \"syshead.h\"
++"
++if test "x$ac_cv_type_struct_sockaddr_in6" = x""yes; then :
++
++$as_echo "#define USE_PF_INET6 1" >>confdefs.h
++
++fi
++
++fi
++
+
+ if test "$MEMCHECK" = "valgrind"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for valgrind tool and Header files..." >&5
+@@ -6874,7 +6908,7 @@
+ CFLAGS="-g -fno-inline"
+
+ else
+- as_fn_error $? "valgrind headers not found." "$LINENO" 5
++ as_fn_error "valgrind headers not found." "$LINENO" 5
+
+ fi
+
+@@ -6933,12 +6967,12 @@
+
+
+ else
+- as_fn_error $? "dmalloc library not found." "$LINENO" 5
++ as_fn_error "dmalloc library not found." "$LINENO" 5
+
+ fi
+
+ else
+- as_fn_error $? "dmalloc headers not found." "$LINENO" 5
++ as_fn_error "dmalloc headers not found." "$LINENO" 5
+
+ fi
+
+@@ -7093,7 +7127,7 @@
+ as_ac_Lib=`$as_echo "ac_cv_lib_$i''_lzo1x_1_15_compress" | $as_tr_sh`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzo1x_1_15_compress in -l$i" >&5
+ $as_echo_n "checking for lzo1x_1_15_compress in -l$i... " >&6; }
+-if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
++if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ ac_check_lib_save_LIBS=$LIBS
+@@ -7128,7 +7162,8 @@
+ eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+ $as_echo "$ac_res" >&6; }
+-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
++eval as_val=\$$as_ac_Lib
++ if test "x$as_val" = x""yes; then :
+
+
+ LIBS="-l$i $LIBS"
+@@ -7148,14 +7183,14 @@
+
+ done
+ if test $havelzolib = 0 ; then
+- as_fn_error $? "LZO headers were found but LZO library was not found" "$LINENO" 5
++ as_fn_error "LZO headers were found but LZO library was not found" "$LINENO" 5
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: LZO headers were not found" >&5
+ $as_echo "LZO headers were not found" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: LZO library available from http://www.oberhumer.com/opensource/lzo/" >&5
+ $as_echo "LZO library available from http://www.oberhumer.com/opensource/lzo/" >&6; }
+- as_fn_error $? "Or try ./configure --disable-lzo" "$LINENO" 5
++ as_fn_error "Or try ./configure --disable-lzo" "$LINENO" 5
+ fi
+ fi
+
+@@ -7167,7 +7202,7 @@
+ if test "x$ac_cv_header_openssl_evp_h" = x""yes; then :
+
+ else
+- as_fn_error $? "OpenSSL Crypto headers not found." "$LINENO" 5
++ as_fn_error "OpenSSL Crypto headers not found." "$LINENO" 5
+ fi
+
+
+@@ -7176,7 +7211,7 @@
+ as_ac_Lib=`$as_echo "ac_cv_lib_$lib''_EVP_CIPHER_CTX_init" | $as_tr_sh`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_init in -l$lib" >&5
+ $as_echo_n "checking for EVP_CIPHER_CTX_init in -l$lib... " >&6; }
+-if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
++if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ ac_check_lib_save_LIBS=$LIBS
+@@ -7211,7 +7246,8 @@
+ eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+ $as_echo "$ac_res" >&6; }
+-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
++eval as_val=\$$as_ac_Lib
++ if test "x$as_val" = x""yes; then :
+
+ cryptofound=1
+
+@@ -7223,7 +7259,7 @@
+
+ done
+
+- test -n "$cryptofound" || as_fn_error $? "OpenSSL Crypto library not found." "$LINENO" 5
++ test -n "$cryptofound" || as_fn_error "OpenSSL Crypto library not found." "$LINENO" 5
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking that OpenSSL Library is at least version 0.9.6" >&5
+ $as_echo_n "checking that OpenSSL Library is at least version 0.9.6... " >&6; }
+@@ -7303,7 +7339,7 @@
+
+
+ else
+- as_fn_error $? "OpenSSL crypto Library is too old." "$LINENO" 5
++ as_fn_error "OpenSSL crypto Library is too old." "$LINENO" 5
+
+ fi
+ rm -f conftest*
+@@ -7317,7 +7353,7 @@
+ if test "x$ac_cv_header_openssl_ssl_h" = x""yes; then :
+
+ else
+- as_fn_error $? "OpenSSL SSL headers not found." "$LINENO" 5
++ as_fn_error "OpenSSL SSL headers not found." "$LINENO" 5
+
+ fi
+
+@@ -7327,7 +7363,7 @@
+ as_ac_Lib=`$as_echo "ac_cv_lib_$lib''_SSL_CTX_new" | $as_tr_sh`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_new in -l$lib" >&5
+ $as_echo_n "checking for SSL_CTX_new in -l$lib... " >&6; }
+-if eval "test \"\${$as_ac_Lib+set}\"" = set; then :
++if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+ else
+ ac_check_lib_save_LIBS=$LIBS
+@@ -7362,7 +7398,8 @@
+ eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+ $as_echo "$ac_res" >&6; }
+-if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
++eval as_val=\$$as_ac_Lib
++ if test "x$as_val" = x""yes; then :
+
+ sslfound=1
+
+@@ -7374,7 +7411,7 @@
+
+ done
+
+- test -n "${sslfound}" || as_fn_error $? "OpenSSL SSL library not found." "$LINENO" 5
++ test -n "${sslfound}" || as_fn_error "OpenSSL SSL library not found." "$LINENO" 5
+
+ if test "$MEMCHECK" = "ssl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Memory Debugging Capabilities in OpenSSL Library..." >&5
+@@ -7424,7 +7461,7 @@
+ $as_echo "NOTE: OpenSSL library must be compiled with CRYPTO_MDEBUG" >&6; }
+
+ else
+- as_fn_error $? "Memory Debugging function in OpenSSL library not found." "$LINENO" 5
++ as_fn_error "Memory Debugging function in OpenSSL library not found." "$LINENO" 5
+
+ fi
+
+@@ -7799,7 +7836,6 @@
+
+ ac_libobjs=
+ ac_ltlibobjs=
+-U=
+ for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+@@ -7823,15 +7859,15 @@
+ fi
+
+ if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+- as_fn_error $? "conditional \"AMDEP\" was never defined.
++ as_fn_error "conditional \"AMDEP\" was never defined.
+ Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+- as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
++ as_fn_error "conditional \"am__fastdepCC\" was never defined.
+ Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+ if test -z "${WIN32_TRUE}" && test -z "${WIN32_FALSE}"; then
+- as_fn_error $? "conditional \"WIN32\" was never defined.
++ as_fn_error "conditional \"WIN32\" was never defined.
+ Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
+
+@@ -7981,19 +8017,19 @@
+ (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+-# as_fn_error STATUS ERROR [LINENO LOG_FD]
+-# ----------------------------------------
++# as_fn_error ERROR [LINENO LOG_FD]
++# ---------------------------------
+ # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+ # provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+-# script with STATUS, using 1 if that was 0.
++# script with status $?, using 1 if that was 0.
+ as_fn_error ()
+ {
+- as_status=$1; test $as_status -eq 0 && as_status=1
+- if test "$4"; then
+- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ as_status=$?; test $as_status -eq 0 && as_status=1
++ if test "$3"; then
++ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+- $as_echo "$as_me: error: $2" >&2
++ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+ } # as_fn_error
+
+@@ -8189,7 +8225,7 @@
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
++ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+ } # as_fn_mkdir_p
+@@ -8368,7 +8404,7 @@
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+- as_fn_error $? "ambiguous option: \`$1'
++ as_fn_error "ambiguous option: \`$1'
+ Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+@@ -8377,7 +8413,7 @@
+ ac_cs_silent=: ;;
+
+ # This is an error.
+- -*) as_fn_error $? "unrecognized option: \`$1'
++ -*) as_fn_error "unrecognized option: \`$1'
+ Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+@@ -8441,7 +8477,7 @@
+ "install-win32/Makefile") CONFIG_FILES="$CONFIG_FILES install-win32/Makefile" ;;
+ "install-win32/settings") CONFIG_FILES="$CONFIG_FILES install-win32/settings" ;;
+
+- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
++ *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+ done
+
+@@ -8479,7 +8515,7 @@
+ {
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
++} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
+
+ # Set up the scripts for CONFIG_FILES section.
+ # No need to generate them if there are no CONFIG_FILES.
+@@ -8496,7 +8532,7 @@
+ fi
+ ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+ if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+- ac_cs_awk_cr='\\r'
++ ac_cs_awk_cr='\r'
+ else
+ ac_cs_awk_cr=$ac_cr
+ fi
+@@ -8510,18 +8546,18 @@
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+ } >conf$$subs.sh ||
+- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
++ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
++ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ ac_delim='%!_!# '
+ for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+@@ -8610,28 +8646,20 @@
+ else
+ cat
+ fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
++ || as_fn_error "could not setup config files machinery" "$LINENO" 5
+ _ACEOF
+
+-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
++# VPATH may cause trouble with some makes, so we remove $(srcdir),
++# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+ # trailing colons and then remove the whole line if VPATH becomes empty
+ # (actually we leave an empty line to preserve line numbers).
+ if test "x$srcdir" = x.; then
+- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+-h
+-s///
+-s/^/:/
+-s/[ ]*$/:/
+-s/:\$(srcdir):/:/g
+-s/:\${srcdir}:/:/g
+-s/:@srcdir@:/:/g
+-s/^:*//
++ ac_vpsub='/^[ ]*VPATH[ ]*=/{
++s/:*\$(srcdir):*/:/
++s/:*\${srcdir}:*/:/
++s/:*@srcdir@:*/:/
++s/^\([^=]*=[ ]*\):*/\1/
+ s/:*$//
+-x
+-s/\(=[ ]*\).*/\1/
+-G
+-s/\n//
+ s/^[^=]*=[ ]*$//
+ }'
+ fi
+@@ -8659,7 +8687,7 @@
+ if test -z "$ac_t"; then
+ break
+ elif $ac_last_try; then
+- as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
++ as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+@@ -8744,7 +8772,7 @@
+ _ACAWK
+ _ACEOF
+ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+- as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
++ as_fn_error "could not setup config headers machinery" "$LINENO" 5
+ fi # test -n "$CONFIG_HEADERS"
+
+
+@@ -8757,7 +8785,7 @@
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
++ :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+@@ -8785,7 +8813,7 @@
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
++ as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+@@ -8812,7 +8840,7 @@
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
++ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+@@ -8949,22 +8977,22 @@
+ $ac_datarootdir_hack
+ "
+ eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ || as_fn_error "could not create $ac_file" "$LINENO" 5
+
+ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+-which seems to be undefined. Please make sure it is defined" >&5
++which seems to be undefined. Please make sure it is defined." >&5
+ $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+-which seems to be undefined. Please make sure it is defined" >&2;}
++which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+@@ -8975,19 +9003,19 @@
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+ $as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$tmp/config.h" "$ac_file" \
+- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+- || as_fn_error $? "could not create -" "$LINENO" 5
++ || as_fn_error "could not create -" "$LINENO" 5
+ fi
+ # Compute "$ac_file"'s index in $config_headers.
+ _am_arg="$ac_file"
+@@ -9138,7 +9166,7 @@
+ ac_clean_files=$ac_clean_files_save
+
+ test $ac_write_fail = 0 ||
+- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
++ as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+ # configure is writing to config.log, and then calls config.status.
+@@ -9159,7 +9187,7 @@
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+- $ac_cs_success || as_fn_exit 1
++ $ac_cs_success || as_fn_exit $?
+ fi
+ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+Index: openvpn-2.2.1/configure.ac
+===================================================================
+--- openvpn-2.2.1.orig/configure.ac 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/configure.ac 2011-12-13 12:23:07.348080508 +0100
+@@ -146,6 +146,12 @@
+ [MULTIHOME="yes"]
+ )
+
++AC_ARG_ENABLE(ipv6,
++ [ --disable-ipv6 Disable UDP/IPv6 support],
++ [PF_INET6="$enableval"],
++ [PF_INET6="yes"]
++)
++
+ AC_ARG_ENABLE(port-share,
+ [ --disable-port-share Disable TCP server port-share support (--port-share)],
+ [PORT_SHARE="$enableval"],
+@@ -566,6 +572,16 @@
+ AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL_CREATE, 1, [epoll_create function is defined]))
+ LDFLAGS="$OLDLDFLAGS"
+
++dnl ipv6 support
++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
+ dnl check for valgrind tool
+ dnl
+Index: openvpn-2.2.1/init.c
+===================================================================
+--- openvpn-2.2.1.orig/init.c 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/init.c 2011-12-13 12:23:07.351080471 +0100
+@@ -96,7 +96,7 @@
+ */
+ if (options->pull
+ && options->ping_rec_timeout_action == PING_UNDEF
+- && options->ce.proto == PROTO_UDPv4)
++ && proto_is_dgram(options->ce.proto))
+ {
+ options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART;
+ options->ping_rec_timeout_action = PING_RESTART;
+@@ -1150,7 +1150,12 @@
+ const char *detail = "SUCCESS";
+ if (c->c1.tuntap)
+ tun_local = c->c1.tuntap->local;
+- tun_remote = htonl (c->c1.link_socket_addr.actual.dest.sa.sin_addr.s_addr);
++ /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr
++ * to a meaningless ipv4 address.
++ * In any case, is somewhat inconsistent to send local tunnel
++ * addr with remote _endpoint_ addr (?)
++ */
++ tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr);
+ if (flags & ISC_ERRORS)
+ detail = "ERROR";
+ management_set_state (management,
+@@ -1566,7 +1571,7 @@
+ #ifdef ENABLE_OCC
+ if (found & OPT_P_EXPLICIT_NOTIFY)
+ {
+- if (c->options.ce.proto != PROTO_UDPv4 && c->options.explicit_exit_notification)
++ if (!proto_is_udp(c->options.ce.proto) && c->options.explicit_exit_notification)
+ {
+ msg (D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp");
+ c->options.explicit_exit_notification = 0;
+@@ -1661,13 +1666,22 @@
+ switch (c->options.ce.proto)
+ {
+ case PROTO_UDPv4:
++#ifdef USE_PF_INET6
++ case PROTO_UDPv6:
++#endif
+ if (proxy)
+ sec = c->options.ce.connect_retry_seconds;
+ break;
+ case PROTO_TCPv4_SERVER:
++#ifdef USE_PF_INET6
++ case PROTO_TCPv6_SERVER:
++#endif
+ sec = 1;
+ break;
+ case PROTO_TCPv4_CLIENT:
++#ifdef USE_PF_INET6
++ case PROTO_TCPv6_CLIENT:
++#endif
+ sec = c->options.ce.connect_retry_seconds;
+ break;
+ }
+@@ -2807,7 +2821,7 @@
+ #ifdef WIN32
+ msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows");
+ #else
+- if (c->options.ce.proto != PROTO_UDPv4)
++ if (!proto_is_udp(c->options.ce.proto))
+ msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP");
+ else
+ {
+@@ -3083,7 +3097,11 @@
+ /* link_socket_mode allows CM_CHILD_TCP
+ instances to inherit acceptable fds
+ from a top-level parent */
+- if (c->options.ce.proto == PROTO_TCPv4_SERVER)
++ if (c->options.ce.proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || c->options.ce.proto == PROTO_TCPv6_SERVER
++#endif
++ )
+ {
+ if (c->mode == CM_TOP)
+ link_socket_mode = LS_MODE_TCP_LISTEN;
+@@ -3358,17 +3376,8 @@
+ {
+ CLEAR (*dest);
+
+- switch (src->options.ce.proto)
+- {
+- case PROTO_UDPv4:
+- dest->mode = CM_CHILD_UDP;
+- break;
+- case PROTO_TCPv4_SERVER:
+- dest->mode = CM_CHILD_TCP;
+- break;
+- default:
+- ASSERT (0);
+- }
++ /* proto_is_dgram will ASSERT(0) if proto is invalid */
++ dest->mode = proto_is_dgram(src->options.ce.proto)? CM_CHILD_UDP : CM_CHILD_TCP;
+
+ dest->gc = gc_new ();
+
+@@ -3474,7 +3483,7 @@
+ dest->c2.es_owned = false;
+
+ dest->c2.event_set = NULL;
+- if (src->options.ce.proto == PROTO_UDPv4)
++ if (proto_is_dgram(src->options.ce.proto))
+ do_event_set_init (dest, false);
+ }
+
+Index: openvpn-2.2.1/manage.c
+===================================================================
+--- openvpn-2.2.1.orig/manage.c 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/manage.c 2011-12-13 12:23:07.354080432 +0100
+@@ -1957,9 +1957,9 @@
+ /*
+ * Initialize socket address
+ */
+- ms->local.sa.sin_family = AF_INET;
+- ms->local.sa.sin_addr.s_addr = 0;
+- ms->local.sa.sin_port = htons (port);
++ ms->local.addr.in4.sin_family = AF_INET;
++ ms->local.addr.in4.sin_addr.s_addr = 0;
++ ms->local.addr.in4.sin_port = htons (port);
+
+ /*
+ * Run management over tunnel, or
+@@ -1971,7 +1971,7 @@
+ }
+ else
+ {
+- ms->local.sa.sin_addr.s_addr = getaddr
++ ms->local.addr.in4.sin_addr.s_addr = getaddr
+ (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
+ }
+ }
+@@ -2427,7 +2427,7 @@
+ && man->connection.state == MS_INITIAL)
+ {
+ /* listen on our local TUN/TAP IP address */
+- man->settings.local.sa.sin_addr.s_addr = htonl (tun_local_ip);
++ man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip);
+ man_connection_init (man);
+ }
+
+Index: openvpn-2.2.1/mroute.c
+===================================================================
+--- openvpn-2.2.1.orig/mroute.c 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/mroute.c 2011-12-13 12:23:07.354080432 +0100
+@@ -226,25 +226,47 @@
+ const struct openvpn_sockaddr *osaddr,
+ bool use_port)
+ {
+- if (osaddr->sa.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, &osaddr->sa.sin_addr.s_addr, 4);
+- memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
++ memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
++ memcpy (addr->addr + 4, &osaddr->addr.in4.sin_port, 2);
+ }
+ else
+ {
+ addr->type = MR_ADDR_IPV4;
+ addr->netbits = 0;
+ addr->len = 4;
+- memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
++ memcpy (addr->addr, &osaddr->addr.in4.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
++ }
+ return false;
+ }
+
+Index: openvpn-2.2.1/mtcp.c
+===================================================================
+--- openvpn-2.2.1.orig/mtcp.c 2011-06-24 08:13:38.000000000 +0200
++++ openvpn-2.2.1/mtcp.c 2011-12-13 12:23:07.358080384 +0100
+@@ -150,6 +150,11 @@
+ 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);
++ ASSERT (mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET
++#ifdef USE_PF_INET6
++ || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6
++#endif
++ );
+ if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true))
+ {
+ msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined");
+Index: openvpn-2.2.1/multi.c
+===================================================================
+--- openvpn-2.2.1.orig/multi.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/multi.c 2011-12-13 12:23:07.359080371 +0100
+@@ -1058,8 +1058,8 @@
+ struct mroute_addr addr;
+
+ CLEAR (remote_si);
+- remote_si.sa.sin_family = AF_INET;
+- remote_si.sa.sin_addr.s_addr = htonl (a);
++ remote_si.addr.in4.sin_family = AF_INET;
++ remote_si.addr.in4.sin_addr.s_addr = htonl (a);
+ ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false));
+
+ if (netbits >= 0)
+@@ -2496,9 +2496,9 @@
+ int count = 0;
+
+ CLEAR (saddr);
+- saddr.sa.sin_family = AF_INET;
+- saddr.sa.sin_addr.s_addr = htonl (addr);
+- saddr.sa.sin_port = htons (port);
++ saddr.addr.in4.sin_family = AF_INET;
++ saddr.addr.in4.sin_addr.s_addr = htonl (addr);
++ saddr.addr.in4.sin_port = htons (port);
+ if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true))
+ {
+ hash_iterator_init (m->iter, &hi);
+@@ -2675,16 +2675,24 @@
+ {
+ ASSERT (top->options.mode == MODE_SERVER);
+
+- switch (top->options.ce.proto) {
+- case PROTO_UDPv4:
+- tunnel_server_udp (top);
+- break;
+- case PROTO_TCPv4_SERVER:
+- tunnel_server_tcp (top);
+- break;
+- default:
+- ASSERT (0);
+- }
++#ifdef USE_PF_INET6
++ if (proto_is_dgram(top->options.ce.proto))
++ tunnel_server_udp(top);
++ else
++ tunnel_server_tcp(top);
++#else
++ switch (top->options.ce.proto)
++ {
++ case PROTO_UDPv4:
++ tunnel_server_udp (top);
++ break;
++ case PROTO_TCPv4_SERVER:
++ tunnel_server_tcp (top);
++ break;
++ default:
++ ASSERT (0);
++ }
++#endif
+ }
+
+ #else
+Index: openvpn-2.2.1/occ.c
+===================================================================
+--- openvpn-2.2.1.orig/occ.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/occ.c 2011-12-13 12:23:07.362080332 +0100
+@@ -369,7 +369,7 @@
+ c->c2.max_send_size_remote,
+ c->c2.max_recv_size_local);
+ if (!c->options.fragment
+- && c->options.ce.proto == PROTO_UDPv4
++ && (proto_is_dgram(c->options.ce.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))
+Index: openvpn-2.2.1/openvpn.8
+===================================================================
+--- openvpn-2.2.1.orig/openvpn.8 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/openvpn.8 2011-12-13 12:23:07.367080271 +0100
+@@ -5463,13 +5463,16 @@
+ script execution.
+ .\"*********************************************************
+ .TP
+-.B trusted_ip
++.B trusted_ip (or trusted_ip6)
+ Actual IP address of connecting client or peer which has been authenticated.
+ Set prior to execution of
+ .B \-\-ipchange, \-\-client-connect,
+ and
+ .B \-\-client-disconnect
+ scripts.
++If using ipv6 endpoints (udp6, tcp6),
++.B trusted_ip6
++will be set instead.
+ .\"*********************************************************
+ .TP
+ .B trusted_port
+@@ -5481,7 +5484,7 @@
+ scripts.
+ .\"*********************************************************
+ .TP
+-.B untrusted_ip
++.B untrusted_ip (or untrusted_ip6)
+ Actual IP address of connecting client or peer which has not been authenticated
+ yet. Sometimes used to
+ .B nmap
+@@ -5493,6 +5496,9 @@
+ and
+ .B \-\-auth-user-pass-verify
+ scripts.
++If using ipv6 endpoints (udp6, tcp6),
++.B untrusted_ip6
++will be set instead.
+ .\"*********************************************************
+ .TP
+ .B untrusted_port
+Index: openvpn-2.2.1/options.c
+===================================================================
+--- openvpn-2.2.1.orig/options.c 2011-12-13 12:22:25.000000000 +0100
++++ openvpn-2.2.1/options.c 2011-12-13 12:23:07.374080184 +0100
+@@ -79,6 +79,12 @@
+ #ifdef ENABLE_EUREPHIA
+ " [eurephia]"
+ #endif
++#if ENABLE_IP_PKTINFO
++ " [MH]"
++#endif
++#ifdef USE_PF_INET6
++ " [PF_INET6]"
++#endif
+ " built on " __DATE__
+ ;
+
+@@ -101,6 +107,9 @@
+ "--proto p : Use protocol p for communicating with peer.\n"
+ " p = udp (default), tcp-server, or tcp-client\n"
+ "--proto-force p : only consider protocol p in list of connection profiles.\n"
++#ifdef USE_PF_INET6
++ " p = udp6, tcp6-server, or tcp6-client (ipv6)\n"
++#endif
+ "--connect-retry n : For --proto tcp-client, number of seconds to wait\n"
+ " between connection retries (default=%d).\n"
+ "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
+@@ -1707,11 +1716,27 @@
+ * Sanity check on TCP mode options
+ */
+
+- if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT)
+- msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client");
+-
+- if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT)
+- msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client");
++ if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT
++#ifdef USE_PF_INET6
++ && ce->proto != PROTO_TCPv6_CLIENT
++#endif
++ )
++ msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client"
++#ifdef USE_PF_INET6
++ " or tcp6-client"
++#endif
++ );
++
++ if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT
++#ifdef USE_PF_INET6
++ && ce->proto != PROTO_TCPv6_CLIENT
++#endif
++ )
++ msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client"
++#ifdef USE_PF_INET6
++ " or tcp6-client"
++#endif
++ );
+
+ /*
+ * Sanity check on MTU parameters
+@@ -1720,7 +1745,7 @@
+ 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 (ce->proto != PROTO_UDPv4 && options->mtu_test)
++ if (!proto_is_udp(ce->proto) && options->mtu_test)
+ msg (M_USAGE, "--mtu-test only makes sense with --proto udp");
+ #endif
+
+@@ -1733,7 +1758,8 @@
+ * Sanity check on --local, --remote, and --ifconfig
+ */
+
+- if (string_defined_equal (ce->local, ce->remote)
++ if (proto_is_net(ce->proto)
++ && string_defined_equal (ce->local, ce->remote)
+ && ce->local_port == ce->remote_port)
+ msg (M_USAGE, "--remote and --local addresses are the same");
+
+@@ -1798,16 +1824,20 @@
+ */
+
+ #ifdef ENABLE_FRAGMENT
+- if (ce->proto != PROTO_UDPv4 && options->fragment)
++ if (!proto_is_udp(ce->proto) && options->fragment)
+ msg (M_USAGE, "--fragment can only be used with --proto udp");
+ #endif
+
+ #ifdef ENABLE_OCC
+- if (ce->proto != PROTO_UDPv4 && options->explicit_exit_notification)
++ if (!proto_is_udp(ce->proto) && options->explicit_exit_notification)
+ msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");
+ #endif
+
+- if (!ce->remote && ce->proto == PROTO_TCPv4_CLIENT)
++ if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT
++#ifdef USE_PF_INET6
++ || ce->proto == PROTO_TCPv6_CLIENT
++#endif
++ ))
+ msg (M_USAGE, "--remote MUST be used in TCP Client mode");
+
+ #ifdef ENABLE_HTTP_PROXY
+@@ -1825,7 +1855,12 @@
+ msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
+ #endif
+
+- if (ce->proto == PROTO_TCPv4_SERVER && connection_list_defined (options))
++ if ((ce->proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || ce->proto == PROTO_TCPv6_SERVER
++#endif
++ )
++ && connection_list_defined (options))
+ msg (M_USAGE, "TCP server mode allows at most one --remote address");
+
+ #if P2MP_SERVER
+@@ -1839,11 +1874,28 @@
+ 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 (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
+- msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
++ if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || ce->proto == PROTO_TCPv6_SERVER
++#endif
++ ))
++ msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"
++#ifdef USE_PF_INET6
++ " or proto tcp6-server"
++#endif
++ );
+ #if PORT_SHARE
+- if ((options->port_share_host || options->port_share_port) && ce->proto != PROTO_TCPv4_SERVER)
+- msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)");
++ if ((options->port_share_host || options->port_share_port) &&
++ (ce->proto != PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ && ce->proto != PROTO_TCPv6_SERVER
++#endif
++ ))
++ msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server"
++#ifdef USE_PF_INET6
++ " or tcp6-server"
++#endif
++ ")");
+ #endif
+ if (!options->tls_server)
+ msg (M_USAGE, "--mode server requires --tls-server");
+@@ -1871,9 +1923,17 @@
+ 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 (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
+- msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
+- if (ce->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
++ if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || ce->proto == PROTO_TCPv6_SERVER
++#endif
++ ))
++ msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"
++#ifdef USE_PF_INET6
++ " or --proto tcp6-server"
++#endif
++ );
++ if (!proto_is_udp(ce->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 || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
+ msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
+@@ -1964,7 +2024,7 @@
+ /*
+ * Check consistency of replay options
+ */
+- if ((ce->proto != PROTO_UDPv4)
++ if ((!proto_is_udp(ce->proto))
+ && (options->replay_window != defaults.replay_window
+ || options->replay_time != defaults.replay_time))
+ msg (M_USAGE, "--replay-window only makes sense with --proto udp");
+@@ -2137,6 +2197,10 @@
+ {
+ if (ce->proto == PROTO_TCPv4)
+ ce->proto = PROTO_TCPv4_CLIENT;
++#ifdef USE_PF_INET6
++ else if (ce->proto == PROTO_TCPv6)
++ ce->proto = PROTO_TCPv6_CLIENT;
++#endif
+ }
+ #endif
+
+Index: openvpn-2.2.1/ps.c
+===================================================================
+--- openvpn-2.2.1.orig/ps.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/ps.c 2011-12-13 12:23:07.375080171 +0100
+@@ -320,9 +320,9 @@
+ const int port)
+ {
+ CLEAR (*osaddr);
+- osaddr->sa.sin_family = AF_INET;
+- osaddr->sa.sin_addr.s_addr = htonl (addr);
+- osaddr->sa.sin_port = htons (port);
++ osaddr->addr.in4.sin_family = AF_INET;
++ osaddr->addr.in4.sin_addr.s_addr = htonl (addr);
++ osaddr->addr.in4.sin_port = htons (port);
+ }
+
+ static inline void
+Index: openvpn-2.2.1/route.c
+===================================================================
+--- openvpn-2.2.1.orig/route.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/route.c 2011-12-13 12:23:07.377080145 +0100
+@@ -581,13 +581,23 @@
+ if (!local)
+ {
+ /* route remote host to original default gateway */
+- add_route3 (rl->spec.remote_host,
+- ~0,
+- rl->spec.net_gateway,
+- tt,
+- flags,
+- es);
+- rl->did_local = true;
++#ifdef USE_PF_INET6
++ /* if remote_host is not ipv4 (ie: ipv6), just skip
++ * adding this special /32 route */
++ if (rl->spec.remote_host != IPV4_INVALID_ADDR) {
++#endif
++ add_route3 (rl->spec.remote_host,
++ ~0,
++ rl->spec.net_gateway,
++ tt,
++ flags,
++ es);
++ rl->did_local = true;
++#ifdef USE_PF_INET6
++ } else {
++ dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled");
++ }
++#endif
+ }
+
+ /* route DHCP/DNS server traffic through original default gateway */
+Index: openvpn-2.2.1/socket.c
+===================================================================
+--- openvpn-2.2.1.orig/socket.c 2011-12-13 12:22:23.000000000 +0100
++++ openvpn-2.2.1/socket.c 2011-12-13 12:23:07.381080096 +0100
+@@ -36,10 +36,16 @@
+ #include "memdbg.h"
+
+ const int proto_overhead[] = { /* indexed by PROTO_x */
+- IPv4_UDP_HEADER_SIZE,
++ 0,
++ IPv4_UDP_HEADER_SIZE, /* IPv4 */
+ 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
+ };
+
+ /*
+@@ -276,6 +282,201 @@
+ return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr;
+ }
+
++#ifdef USE_PF_INET6
++/*
++ * Translate IPv6 addr or hostname into struct addrinfo
++ * If resolve error, try again for
++ * resolve_retry_seconds seconds.
++ */
++bool
++getaddr6 (unsigned int flags,
++ const char *hostname,
++ int resolve_retry_seconds,
++ volatile int *signal_received,
++ int *gai_err,
++ struct sockaddr_in6 *in6)
++{
++ bool success;
++ struct addrinfo hints, *ai;
++ int status;
++ int sigrec = 0;
++ int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
++ struct gc_arena gc = gc_new ();
++
++ ASSERT(in6);
++
++ if (!hostname)
++ hostname = "::";
++
++ if (flags & GETADDR_RANDOMIZE)
++ hostname = hostname_randomize(hostname, &gc);
++
++ if (flags & GETADDR_MSG_VIRT_OUT)
++ msglevel |= M_MSG_VIRT_OUT;
++
++ CLEAR (ai);
++ success = false;
++
++ if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
++ && !signal_received)
++ signal_received = &sigrec;
++
++ /* try numeric ipv6 addr first */
++ CLEAR(hints);
++ hints.ai_family = AF_INET6;
++ hints.ai_flags = AI_NUMERICHOST;
++ if ((status = getaddrinfo(hostname, NULL, &hints, &ai))==0)
++ {
++ *in6 = *((struct sockaddr_in6 *)(ai->ai_addr));
++ freeaddrinfo(ai);
++ ai = NULL;
++ }
++ if (gai_err)
++ *gai_err = status;
++
++
++ if (status != 0) /* parse as IPv6 address failed? */
++ {
++ const int fail_wait_interval = 5; /* seconds */
++ int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval);
++ const char *fmt;
++ int level = 0;
++ int err;
++
++ ai = NULL;
++
++ fmt = "RESOLVE: Cannot resolve host address: %s: %s";
++ if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
++ && !resolve_retry_seconds)
++ fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)";
++
++ if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
++ {
++ msg (msglevel, "RESOLVE: Cannot parse IPv6 address: %s", hostname);
++ goto done;
++ }
++
++#ifdef ENABLE_MANAGEMENT
++ if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
++ {
++ if (management)
++ management_set_state (management,
++ OPENVPN_STATE_RESOLVE,
++ NULL,
++ (in_addr_t)0,
++ (in_addr_t)0);
++ }
++#endif
++
++ /*
++ * Resolve hostname
++ */
++ while (true)
++ {
++ /* try hostname lookup */
++ hints.ai_flags = 0;
++ hints.ai_socktype = dnsflags_to_socktype(flags);
++ dmsg (D_SOCKET_DEBUG, "GETADDR6 flags=0x%04x ai_family=%d ai_socktype=%d",
++ flags, hints.ai_family, hints.ai_socktype);
++ err = getaddrinfo(hostname, NULL, &hints, &ai);
++
++ if (gai_err)
++ *gai_err = err;
++
++ if (signal_received)
++ {
++ get_signal (signal_received);
++ if (*signal_received) /* were we interrupted by a signal? */
++ {
++ if (0 == err) {
++ ASSERT(ai);
++ freeaddrinfo(ai);
++ ai = NULL;
++ }
++ if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
++ {
++ msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
++ *signal_received = 0;
++ }
++ else
++ goto done;
++ }
++ }
++
++ /* success? */
++ if (0 == err)
++ break;
++
++ /* resolve lookup failed, should we
++ continue or fail? */
++
++ level = msglevel;
++ if (resolve_retries > 0)
++ level = D_RESOLVE_ERRORS;
++
++ msg (level,
++ fmt,
++ hostname,
++ gai_strerror(err));
++
++ if (--resolve_retries <= 0)
++ goto done;
++
++ openvpn_sleep (fail_wait_interval);
++ }
++
++ ASSERT(ai);
++
++ if (!ai->ai_next)
++ *in6 = *((struct sockaddr_in6*)(ai->ai_addr));
++ else
++ /* more than one address returned */
++ {
++ struct addrinfo *ai_cursor;
++ int n = 0;
++ /* count address list */
++ for (ai_cursor = ai; ai_cursor; ai_cursor = ai_cursor->ai_next) n++;
++ ASSERT (n >= 2);
++
++ msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d ipv6 addresses, choosing one by random",
++ hostname,
++ n);
++
++ /* choose address randomly, for basic load-balancing capability */
++ n--;
++ n %= get_random();
++ for (ai_cursor = ai; n; ai_cursor = ai_cursor->ai_next) n--;
++ *in6 = *((struct sockaddr_in6*)(ai_cursor->ai_addr));
++ }
++
++ freeaddrinfo(ai);
++ ai = NULL;
++
++ /* hostname resolve succeeded */
++ success = true;
++ }
++ else
++ {
++ /* IP address parse succeeded */
++ success = true;
++ }
++
++ done:
++ if (signal_received && *signal_received)
++ {
++ int level = 0;
++ if (flags & GETADDR_FATAL_ON_SIGNAL)
++ level = M_FATAL;
++ else if (flags & GETADDR_WARN_ON_SIGNAL)
++ level = M_WARN;
++ msg (level, "RESOLVE: signal received during DNS resolution attempt");
++ }
++
++ gc_free (&gc);
++ return success;
++}
++#endif /* USE_PF_INET6 */
++
+ /*
+ * We do our own inet_aton because the glibc function
+ * isn't very good about error checking.
+@@ -410,20 +611,53 @@
+ bool *changed,
+ const unsigned int sockflags)
+ {
+- if (host && addr)
++ switch(addr->addr.sa.sa_family)
+ {
+- const in_addr_t new_addr = getaddr (
+- sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
+- host,
+- 1,
+- NULL,
+- NULL);
+- if (new_addr && addr->sa.sin_addr.s_addr != new_addr)
++ case AF_INET:
++ if (host && addr)
+ {
+- addr->sa.sin_addr.s_addr = new_addr;
+- *changed = true;
++ const in_addr_t new_addr = getaddr (
++ sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
++ host,
++ 1,
++ NULL,
++ NULL);
++ if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr)
++ {
++ addr->addr.in4.sin_addr.s_addr = new_addr;
++ *changed = true;
++ }
+ }
+- }
++ break;
++#ifdef USE_PF_INET6
++ case AF_INET6:
++ if (host && addr)
++ {
++ struct sockaddr_in6 sin6;
++ CLEAR(sin6);
++ int success = getaddr6 (
++ sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
++ host,
++ 1,
++ NULL,
++ NULL,
++ &sin6);
++ if ( success )
++ {
++ if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr))
++ {
++ int port = addr->addr.in6.sin6_port;
++ /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */
++ addr->addr.in6 = sin6;
++ addr->addr.in6.sin6_port = port;
++ }
++ }
++ }
++ break;
++#endif
++ default:
++ ASSERT(0);
++ }
+ }
+
+ static int
+@@ -610,12 +844,62 @@
+ else if (flags & SF_USE_IP_PKTINFO)
+ {
+ int pad = 1;
+- setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad));
++#ifdef IP_PKTINFO
++ if (setsockopt (sd, SOL_IP, IP_PKTINFO,
++ (void*)&pad, sizeof(pad)) < 0)
++ msg(M_SOCKERR, "UDP: failed setsockopt for IP_PKTINFO");
++#elif defined(IP_RECVDSTADDR)
++ if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
++ (void*)&pad, sizeof(pad)) < 0)
++ msg(M_SOCKERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
++#else
++#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
++#endif
++ }
++#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;
++ if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
++ (void*)&pad, sizeof(pad)) < 0)
++ msg(M_SOCKERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+ }
+ #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
+ static void
+ create_socket (struct link_socket *sock)
+ {
+@@ -623,6 +907,7 @@
+ if (sock->info.proto == PROTO_UDPv4)
+ {
+ sock->sd = create_socket_udp (sock->sockflags);
++ sock->sockflags |= SF_GETADDRINFO_DGRAM;
+
+ #ifdef ENABLE_SOCKS
+ if (sock->socks_proxy)
+@@ -634,6 +919,18 @@
+ {
+ 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->sockflags);
++ sock->sockflags |= SF_GETADDRINFO_DGRAM;
++ }
++#endif
+ else
+ {
+ ASSERT (0);
+@@ -671,7 +968,12 @@
+ struct link_socket_actual *act,
+ const bool nowait)
+ {
+- socklen_t remote_len = sizeof (act->dest.sa);
++ /* 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->dest.addr.sa.sa_family);
++ socklen_t remote_len = sizeof(act->dest.addr);
+ socket_descriptor_t new_sd = SOCKET_UNDEFINED;
+
+ CLEAR (*act);
+@@ -679,7 +981,7 @@
+ #ifdef HAVE_GETPEERNAME
+ if (nowait)
+ {
+- new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
++ new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len);
+
+ if (!socket_defined (new_sd))
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");
+@@ -692,7 +994,7 @@
+ #endif
+ else
+ {
+- new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
++ new_sd = accept (sd, &act->dest.addr.sa, &remote_len);
+ }
+
+ #if 0 /* For debugging only, test the effect of accept() failures */
+@@ -708,7 +1010,8 @@
+ {
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd);
+ }
+- else if (remote_len != sizeof (act->dest.sa))
++ /* only valid if we have remote_len_af!=0 */
++ else if (remote_len_af && remote_len != remote_len_af)
+ {
+ msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
+ openvpn_close_socket (new_sd);
+@@ -809,7 +1112,7 @@
+ {
+ struct gc_arena gc = gc_new ();
+
+- if (bind (sd, (struct sockaddr *) &local->sa, sizeof (local->sa)))
++ if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family)))
+ {
+ const int errnum = openvpn_errno_socket ();
+ msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
+@@ -830,7 +1133,7 @@
+
+ #ifdef CONNECT_NONBLOCK
+ set_nonblock (sd);
+- status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
++ status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ if (status)
+ status = openvpn_errno_socket ();
+ if (status == EINPROGRESS)
+@@ -888,7 +1191,7 @@
+ }
+ }
+ #else
+- status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
++ status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ if (status)
+ status = openvpn_errno_socket ();
+ #endif
+@@ -966,7 +1269,20 @@
+ if (*signal_received)
+ goto done;
+
+- *sd = create_socket_tcp ();
++#ifdef USE_PF_INET6
++ switch(local->addr.sa.sa_family)
++ {
++ case PF_INET6:
++ *sd = create_socket_tcp6 ();
++ break;
++ case PF_INET:
++#endif
++ *sd = create_socket_tcp ();
++#ifdef USE_PF_INET6
++ break;
++ }
++#endif
++
+ if (bind_local)
+ socket_bind (*sd, local, "TCP Client");
+ update_remote (remote_dynamic, remote, remote_changed, sockflags);
+@@ -1031,15 +1347,54 @@
+ /* resolve local address if undefined */
+ if (!addr_defined (&sock->info.lsa->local))
+ {
+- sock->info.lsa->local.sa.sin_family = AF_INET;
+- sock->info.lsa->local.sa.sin_addr.s_addr =
+- (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
++#ifdef USE_PF_INET6
++ /* may return AF_{INET|INET6} guessed from local_host */
++ switch(addr_guess_family(sock->info.proto, sock->local_host))
++ {
++ case AF_INET:
++#endif
++ sock->info.lsa->local.addr.in4.sin_family = AF_INET;
++ sock->info.lsa->local.addr.in4.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.addr.in4.sin_port = htons (sock->local_port);
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
++ {
++ int success;
++ int err;
++ CLEAR(sock->info.lsa->local.addr.in6);
++ if (sock->local_host)
++ {
++ success = getaddr6(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
+ sock->local_host,
+ 0,
+ NULL,
+- NULL)
+- : htonl (INADDR_ANY));
+- sock->info.lsa->local.sa.sin_port = htons (sock->local_port);
++ &err,
++ &sock->info.lsa->local.addr.in6);
++ }
++ else
++ {
++ sock->info.lsa->local.addr.in6.sin6_family = AF_INET6;
++ sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any;
++ success = true;
++ }
++ if (!success)
++ {
++ msg (M_FATAL, "getaddr6() failed for local \"%s\": %s",
++ sock->local_host,
++ gai_strerror(err));
++ }
++ sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port);
++ }
++ break;
++ }
++#endif /* USE_PF_INET6 */
+ }
+
+ /* bind to local address/port */
+@@ -1062,14 +1417,32 @@
+ volatile int *signal_received)
+ {
+ struct gc_arena gc = gc_new ();
++#ifdef USE_PF_INET6
++ int af;
++#endif
+
+ if (!sock->did_resolve_remote)
+ {
+ /* resolve remote address if undefined */
+ if (!addr_defined (&sock->info.lsa->remote))
+ {
+- sock->info.lsa->remote.sa.sin_family = AF_INET;
+- sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
++#ifdef USE_PF_INET6
++ af = addr_guess_family(sock->info.proto, sock->remote_host);
++ switch(af)
++ {
++ case AF_INET:
++#endif
++ sock->info.lsa->remote.addr.in4.sin_family = AF_INET;
++ sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0;
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
++ CLEAR(sock->info.lsa->remote.addr.in6);
++ sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6;
++ sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any;
++ break;
++ }
++#endif
+
+ if (sock->remote_host)
+ {
+@@ -1112,13 +1485,31 @@
+ ASSERT (0);
+ }
+
+- sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr (
+- flags,
+- sock->remote_host,
+- retry,
+- &status,
+- signal_received);
+-
++#ifdef USE_PF_INET6
++ switch(af)
++ {
++ case AF_INET:
++#endif
++ sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr (
++ flags,
++ sock->remote_host,
++ retry,
++ &status,
++ signal_received);
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
++ status = getaddr6 (
++ flags,
++ sock->remote_host,
++ retry,
++ signal_received,
++ NULL,
++ &sock->info.lsa->remote.addr.in6);
++ break;
++ }
++#endif
++
+ dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
+ flags,
+ phase,
+@@ -1138,8 +1529,19 @@
+ goto done;
+ }
+ }
+-
+- sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port);
++#ifdef USE_PF_INET6
++ switch(af)
++ {
++ case AF_INET:
++#endif
++ sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port);
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
++ sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port);
++ break;
++ }
++#endif
+ }
+
+ /* should we re-use previous active remote address? */
+@@ -1256,7 +1658,11 @@
+ if (mode == LS_MODE_TCP_ACCEPT_FROM)
+ {
+ ASSERT (accept_from);
+- ASSERT (sock->info.proto == PROTO_TCPv4_SERVER);
++ ASSERT (sock->info.proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || sock->info.proto == PROTO_TCPv6_SERVER
++#endif
++ );
+ ASSERT (!sock->inetd);
+ sock->sd = accept_from->sd;
+ }
+@@ -1313,7 +1719,11 @@
+ /* were we started by inetd or xinetd? */
+ if (sock->inetd)
+ {
+- ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT);
++ ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT
++#ifdef USE_PF_INET6
++ && sock->info.proto != PROTO_TCPv6_CLIENT
++#endif
++ );
+ ASSERT (socket_defined (inetd_socket_descriptor));
+ sock->sd = inetd_socket_descriptor;
+ }
+@@ -1366,7 +1776,34 @@
+ /* were we started by inetd or xinetd? */
+ if (sock->inetd)
+ {
+- if (sock->info.proto == PROTO_TCPv4_SERVER)
++ if (sock->info.proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ || sock->info.proto == PROTO_TCPv6_SERVER
++#endif
++ ) {
++ /* AF_INET as default (and fallback) for inetd */
++ sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
++#ifdef USE_PF_INET6
++#ifdef HAVE_GETSOCKNAME
++ {
++ /* inetd: hint family type for dest = local's */
++ struct openvpn_sockaddr local_addr;
++ socklen_t addrlen = sizeof(local_addr);
++ if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &addrlen) == 0) {
++ sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
++ dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
++ proto2ascii(sock->info.proto, false), local_addr.addr.sa.sa_family,
++ sock->sd);
++ } else
++ msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
++ proto2ascii(sock->info.proto, false), sock->sd);
++ }
++#else
++ msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
++ "function, using AF_INET",
++ proto2ascii(sock->info.proto, false));
++#endif
++#endif
+ sock->sd =
+ socket_listen_accept (sock->sd,
+ &sock->info.lsa->actual,
+@@ -1376,6 +1813,7 @@
+ false,
+ sock->inetd == INETD_NOWAIT,
+ signal_received);
++ }
+ ASSERT (!remote_changed);
+ if (*signal_received)
+ goto done;
+@@ -1388,7 +1826,11 @@
+ goto done;
+
+ /* TCP client/server */
+- if (sock->info.proto == PROTO_TCPv4_SERVER)
++ if (sock->info.proto == PROTO_TCPv4_SERVER
++#ifdef USE_PF_INET6
++ ||sock->info.proto == PROTO_TCPv6_SERVER
++#endif
++ )
+ {
+ switch (sock->mode)
+ {
+@@ -1423,7 +1865,11 @@
+ ASSERT (0);
+ }
+ }
+- else if (sock->info.proto == PROTO_TCPv4_CLIENT)
++ else if (sock->info.proto == PROTO_TCPv4_CLIENT
++#ifdef USE_PF_INET6
++ ||sock->info.proto == PROTO_TCPv6_CLIENT
++#endif
++ )
+ {
+
+ #ifdef GENERAL_PROXY_SUPPORT
+@@ -1510,8 +1956,8 @@
+ sock->remote_port = sock->proxy_dest_port;
+ sock->did_resolve_remote = false;
+
+- sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0;
+- sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
++ addr_zero_host(&sock->info.lsa->actual.dest);
++ addr_zero_host(&sock->info.lsa->remote);
+
+ resolve_remote (sock, 1, NULL, signal_received);
+
+@@ -1526,7 +1972,7 @@
+ if (remote_changed)
+ {
+ msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
+- sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr;
++ addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest);
+ }
+ }
+
+@@ -1708,13 +2154,20 @@
+ {
+ struct gc_arena gc = gc_new ();
+
+- 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_socket_actual (from_addr, &gc),
+- (int)from_addr->dest.sa.sin_family,
+- print_sockaddr (&info->lsa->remote, &gc));
++ switch(from_addr->dest.addr.sa.sa_family)
++ {
++ case AF_INET:
++#ifdef USE_PF_INET6
++ case AF_INET6:
++#endif
++ 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_socket_actual (from_addr, &gc),
++ (int)from_addr->dest.addr.sa.sa_family,
++ print_sockaddr (&info->lsa->remote, &gc));
++ break;
++ }
+ buf->len = 0;
+-
+ gc_free (&gc);
+ }
+
+@@ -1729,10 +2182,25 @@
+ {
+ 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
++ *
++ */
++#ifdef USE_PF_INET6
++ if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
++ return IPV4_INVALID_ADDR;
++#else
++ ASSERT (lsa->actual.dest.addr.sa.sa_family == AF_INET);
++#endif
++
+ if (link_socket_actual_defined (&lsa->actual))
+- return ntohl (lsa->actual.dest.sa.sin_addr.s_addr);
++ return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
+ else if (addr_defined (&lsa->remote))
+- return ntohl (lsa->remote.sa.sin_addr.s_addr);
++ return ntohl (lsa->remote.addr.in4.sin_addr.s_addr);
+ else
+ return 0;
+ }
+@@ -1959,26 +2427,61 @@
+ const unsigned int flags,
+ struct gc_arena *gc)
+ {
+- if (addr)
++ struct buffer out = alloc_buf_gc (128, gc);
++ bool addr_is_defined;
++ addr_is_defined = addr_defined (addr);
++ if (!addr_is_defined) {
++ return "[undef]";
++ }
++#ifdef USE_PF_INET6
++ switch(addr->addr.sa.sa_family)
+ {
+- struct buffer out = alloc_buf_gc (64, gc);
+- const int port = ntohs (addr->sa.sin_port);
++ case AF_INET:
++#endif
++ {
++ const int port= ntohs (addr->addr.in4.sin_port);
++ buf_puts (&out, "[AF_INET]");
+
+- if (!(flags & PS_DONT_SHOW_ADDR))
+- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
++ if (!(flags & PS_DONT_SHOW_ADDR))
++ buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]"));
+
+- if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
+- && port)
++ if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
++ && port)
++ {
++ if (separator)
++ buf_printf (&out, "%s", separator);
++
++ buf_printf (&out, "%d", port);
++ }
++ }
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
+ {
+- if (separator)
+- buf_printf (&out, "%s", separator);
++ const int port= ntohs (addr->addr.in6.sin6_port);
++ char buf[INET6_ADDRSTRLEN] = "";
++ 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);
++ buf_printf (&out, "%d", port);
++ }
+ }
+- return BSTR (&out);
++ break;
++ default:
++ ASSERT(0);
+ }
+- else
+- return "[NULL]";
++#endif
++ return BSTR (&out);
+ }
+
+ const char *
+@@ -1987,6 +2490,10 @@
+ return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
+ }
+
++#ifndef IF_NAMESIZE
++#define IF_NAMESIZE 16
++#endif
++
+ const char *
+ print_link_socket_actual_ex (const struct link_socket_actual *act,
+ const char *separator,
+@@ -1995,15 +2502,54 @@
+ {
+ if (act)
+ {
++ char ifname[IF_NAMESIZE] = "[undef]";
+ struct buffer out = alloc_buf_gc (128, gc);
+ buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
+ #if ENABLE_IP_PKTINFO
+- if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr)
++ if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
+ {
+- struct openvpn_sockaddr sa;
+- CLEAR (sa);
+- sa.sa.sin_addr = act->pi.ipi_spec_dst;
+- buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc));
++#ifdef USE_PF_INET6
++ switch(act->dest.addr.sa.sa_family)
++ {
++ case AF_INET:
++#endif
++ {
++ struct openvpn_sockaddr sa;
++ CLEAR (sa);
++ sa.addr.in4.sin_family = AF_INET;
++#ifdef IP_PKTINFO
++ sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
++ if_indextoname(act->pi.in4.ipi_ifindex, ifname);
++#elif defined(IP_RECVDSTADDR)
++ sa.addr.in4.sin_addr = act->pi.in4;
++ ifname[0]=0;
++#else
++#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
++#endif
++ buf_printf (&out, " (via %s%%%s)",
++ print_sockaddr_ex (&sa, separator, 0, gc),
++ ifname);
++ }
++#ifdef USE_PF_INET6
++ break;
++ case AF_INET6:
++ {
++ struct sockaddr_in6 sin6;
++ char buf[INET6_ADDRSTRLEN] = "[undef]";
++ CLEAR(sin6);
++ sin6.sin6_family = AF_INET6;
++ sin6.sin6_addr = act->pi.in6.ipi6_addr;
++ if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
++ if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6),
++ buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0)
++ buf_printf (&out, " (via %s%%%s)", buf, ifname);
++ else
++ buf_printf (&out, " (via [getnameinfo() err]%%%s)", ifname);
++ }
++ break;
++ }
++#endif /* USE_PF_INET6 */
++
+ }
+ #endif
+ return BSTR (&out);
+@@ -2038,18 +2584,40 @@
+ {
+ char name_buf[256];
+
+- 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);
++#ifdef USE_PF_INET6
++ char buf[128];
++ switch(addr->addr.sa.sa_family)
++ {
++ case AF_INET:
++#endif
++ 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);
+
+- setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr));
++ setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr));
+
+- if ((flags & SA_IP_PORT) && addr->sa.sin_port)
+- {
+- openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
+- setenv_int (es, name_buf, ntohs (addr->sa.sin_port));
++ if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
++ {
++ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
++ setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port));
++ }
++#ifdef USE_PF_INET6
++ break;
++ 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);
++
++ if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
++ {
++ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
++ setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port));
++ }
++ break;
+ }
++#endif
+ }
+
+ void
+@@ -2059,7 +2627,8 @@
+ {
+ struct openvpn_sockaddr si;
+ CLEAR (si);
+- si.sa.sin_addr.s_addr = htonl (addr);
++ si.addr.in4.sin_family = AF_INET;
++ si.addr.in4.sin_addr.s_addr = htonl (addr);
+ setenv_sockaddr (es, name_prefix, &si, flags);
+ }
+ }
+@@ -2080,16 +2649,63 @@
+ struct proto_names {
+ const char *short_form;
+ const char *display_form;
++ bool is_dgram;
++ bool is_net;
++ unsigned short 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
+ };
+
++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;
++}
++
++unsigned short
++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)
+ {
+@@ -2129,6 +2745,45 @@
+ return BSTR (&out);
+ }
+
++int
++addr_guess_family(int proto, const char *name)
++{
++#ifdef USE_PF_INET6
++ unsigned short ret;
++#endif
++ if (proto)
++ {
++ return proto_sa_family(proto); /* already stamped */
++ }
++#ifdef USE_PF_INET6
++ else
++ {
++ struct addrinfo hints , *ai;
++ int err;
++ CLEAR(hints);
++ hints.ai_flags = AI_NUMERICHOST;
++ err = getaddrinfo(name, NULL, &hints, &ai);
++ if ( 0 == err )
++ {
++ 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";
++ }
++ return "AF_UNSPEC";
++}
++
+ /*
+ * Given a local proto, return local proto
+ * if !remote, or compatible remote proto
+@@ -2143,10 +2798,15 @@
+ ASSERT (proto >= 0 && proto < PROTO_N);
+ if (remote)
+ {
+- if (proto == PROTO_TCPv4_SERVER)
+- return PROTO_TCPv4_CLIENT;
+- if (proto == PROTO_TCPv4_CLIENT)
+- return PROTO_TCPv4_SERVER;
++ switch (proto)
++ {
++ case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT;
++ case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER;
++#ifdef USE_PF_INET6
++ case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT;
++ case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER;
++#endif
++ }
+ }
+ return proto;
+ }
+@@ -2205,10 +2865,29 @@
+ #if ENABLE_IP_PKTINFO
+
+ #pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
+-struct openvpn_pktinfo
++struct openvpn_in4_pktinfo
++{
++ struct cmsghdr cmsghdr;
++#ifdef HAVE_IN_PKTINFO
++ struct in_pktinfo pi4;
++#endif
++#ifdef IP_RECVDSTADDR
++ struct in_addr pi4;
++#endif
++};
++#ifdef USE_PF_INET6
++struct openvpn_in6_pktinfo
+ {
+ struct cmsghdr cmsghdr;
+- struct in_pktinfo in_pktinfo;
++ struct in6_pktinfo pi6;
++};
++#endif
++
++union openvpn_pktinfo {
++ struct openvpn_in4_pktinfo msgpi4;
++#ifdef USE_PF_INET6
++ struct openvpn_in6_pktinfo msgpi6;
++#endif
+ };
+ #pragma pack()
+
+@@ -2219,18 +2898,18 @@
+ struct link_socket_actual *from)
+ {
+ struct iovec iov;
+- struct openvpn_pktinfo opi;
++ union openvpn_pktinfo opi;
+ struct msghdr mesg;
+- socklen_t fromlen = sizeof (from->dest.sa);
++ socklen_t fromlen = sizeof (from->dest.addr);
+
+ iov.iov_base = BPTR (buf);
+ iov.iov_len = maxsize;
+ mesg.msg_iov = &iov;
+ mesg.msg_iovlen = 1;
+- mesg.msg_name = &from->dest.sa;
++ mesg.msg_name = &from->dest.addr;
+ mesg.msg_namelen = fromlen;
+ mesg.msg_control = &opi;
+- mesg.msg_controllen = sizeof (opi);
++ mesg.msg_controllen = sizeof opi;
+ buf->len = recvmsg (sock->sd, &mesg, 0);
+ if (buf->len >= 0)
+ {
+@@ -2239,14 +2918,39 @@
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ if (cmsg != NULL
+ && CMSG_NXTHDR (&mesg, cmsg) == NULL
++#ifdef IP_PKTINFO
+ && cmsg->cmsg_level == SOL_IP
+ && cmsg->cmsg_type == IP_PKTINFO
+- && cmsg->cmsg_len >= sizeof (opi))
++#elif defined(IP_RECVDSTADDR)
++ && cmsg->cmsg_level == IPPROTO_IP
++ && cmsg->cmsg_type == IP_RECVDSTADDR
++#else
++#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
++#endif
++ && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
+ {
++#ifdef IP_PKTINFO
+ struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+- from->pi.ipi_ifindex = pkti->ipi_ifindex;
+- from->pi.ipi_spec_dst = pkti->ipi_spec_dst;
++ from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
++ from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
++#elif defined(IP_RECVDSTADDR)
++ from->pi.in4 = *(struct in_addr*) CMSG_DATA (cmsg);
++#else
++#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
++#endif
+ }
++#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;
+ }
+@@ -2258,18 +2962,20 @@
+ int maxsize,
+ struct link_socket_actual *from)
+ {
+- socklen_t fromlen = sizeof (from->dest.sa);
+- from->dest.sa.sin_addr.s_addr = 0;
++ socklen_t fromlen = sizeof (from->dest.addr);
++ socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto));
++ addr_zero_host(&from->dest);
+ ASSERT (buf_safe (buf, maxsize));
+ #if ENABLE_IP_PKTINFO
+- if (sock->sockflags & SF_USE_IP_PKTINFO)
++ /* Both PROTO_UDPv4 and PROTO_UDPv6 */
++ if (proto_is_udp(sock->info.proto) && sock->sockflags & 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,
+- (struct sockaddr *) &from->dest.sa, &fromlen);
+- if (fromlen != sizeof (from->dest.sa))
+- bad_address_length (fromlen, sizeof (from->dest.sa));
++ &from->dest.addr.sa, &fromlen);
++ if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
++ bad_address_length (fromlen, expectedlen);
+ return buf->len;
+ }
+
+@@ -2306,26 +3012,64 @@
+ struct iovec iov;
+ struct msghdr mesg;
+ struct cmsghdr *cmsg;
+- struct in_pktinfo *pkti;
+- struct openvpn_pktinfo opi;
+
+ iov.iov_base = BPTR (buf);
+ iov.iov_len = BLEN (buf);
+ mesg.msg_iov = &iov;
+ mesg.msg_iovlen = 1;
+- mesg.msg_name = &to->dest.sa;
+- mesg.msg_namelen = sizeof (to->dest.sa);
+- 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.ipi_ifindex;
+- pkti->ipi_spec_dst = to->pi.ipi_spec_dst;
+- pkti->ipi_addr.s_addr = 0;
++ switch (sock->info.lsa->remote.addr.sa.sa_family)
++ {
++ case AF_INET:
++ {
++ struct openvpn_in4_pktinfo msgpi4;
++ mesg.msg_name = &to->dest.addr.sa;
++ mesg.msg_namelen = sizeof (struct sockaddr_in);
++ mesg.msg_control = &msgpi4;
++ mesg.msg_controllen = sizeof msgpi4;
++ mesg.msg_flags = 0;
++ cmsg = CMSG_FIRSTHDR (&mesg);
++ cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
++#ifdef HAVE_IN_PKTINFO
++ cmsg->cmsg_level = SOL_IP;
++ cmsg->cmsg_type = IP_PKTINFO;
++ {
++ struct in_pktinfo *pkti;
++ pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
++ pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
++ pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
++ pkti->ipi_addr.s_addr = 0;
++ }
++#elif defined(IP_RECVDSTADDR)
++ cmsg->cmsg_level = IPPROTO_IP;
++ cmsg->cmsg_type = IP_RECVDSTADDR;
++ *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
++#else
++#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
++#endif
++ break;
++ }
++#ifdef USE_PF_INET6
++ case AF_INET6:
++ {
++ struct openvpn_in6_pktinfo msgpi6;
++ struct in6_pktinfo *pkti6;
++ mesg.msg_name = &to->dest.addr.sa;
++ mesg.msg_namelen = sizeof (struct sockaddr_in6);
++ mesg.msg_control = &msgpi6;
++ mesg.msg_controllen = sizeof msgpi6;
++ mesg.msg_flags = 0;
++ cmsg = CMSG_FIRSTHDR (&mesg);
++ cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
++ 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);
+ }
+
+@@ -2346,11 +3090,11 @@
+ int status;
+
+ /* reset buf to its initial state */
+- if (sock->info.proto == PROTO_UDPv4)
++ if (proto_is_udp(sock->info.proto))
+ {
+ sock->reads.buf = sock->reads.buf_init;
+ }
+- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
++ else if (proto_is_tcp(sock->info.proto))
+ {
+ stream_buf_get_next (&sock->stream_buf, &sock->reads.buf);
+ }
+@@ -2370,10 +3114,15 @@
+ ASSERT (ResetEvent (sock->reads.overlapped.hEvent));
+ sock->reads.flags = 0;
+
+- if (sock->info.proto == PROTO_UDPv4)
++ if (proto_is_udp(sock->info.proto))
+ {
+ sock->reads.addr_defined = true;
+- sock->reads.addrlen = sizeof (sock->reads.addr);
++#ifdef USE_PF_INET6
++ if (sock->info.proto == PROTO_UDPv6)
++ sock->reads.addrlen = sizeof (sock->reads.addr6);
++ else
++#endif
++ sock->reads.addrlen = sizeof (sock->reads.addr);
+ status = WSARecvFrom(
+ sock->sd,
+ wsabuf,
+@@ -2385,7 +3134,7 @@
+ &sock->reads.overlapped,
+ NULL);
+ }
+- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
++ else if (proto_is_tcp(sock->info.proto))
+ {
+ sock->reads.addr_defined = false;
+ status = WSARecv(
+@@ -2405,8 +3154,14 @@
+
+ if (!status) /* operation completed immediately? */
+ {
++#ifdef USE_PF_INET6
++ int addrlen = af_addr_size(sock->info.lsa->local.addr.sa.sa_family);
++ if (sock->reads.addr_defined && sock->reads.addrlen != addrlen)
++ bad_address_length (sock->reads.addrlen, addrlen);
++#else
+ if (sock->reads.addr_defined && sock->reads.addrlen != sizeof (sock->reads.addr))
+ bad_address_length (sock->reads.addrlen, sizeof (sock->reads.addr));
++#endif
+
+ sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
+
+@@ -2465,12 +3220,22 @@
+ ASSERT (ResetEvent (sock->writes.overlapped.hEvent));
+ sock->writes.flags = 0;
+
+- if (sock->info.proto == PROTO_UDPv4)
++ if (proto_is_udp(sock->info.proto))
+ {
+ /* set destination address for UDP writes */
+ sock->writes.addr_defined = true;
+- sock->writes.addr = to->dest.sa;
+- sock->writes.addrlen = sizeof (sock->writes.addr);
++#ifdef USE_PF_INET6
++ if (sock->info.proto == PROTO_UDPv6)
++ {
++ sock->writes.addr6 = to->dest.addr.in6;
++ sock->writes.addrlen = sizeof (sock->writes.addr6);
++ }
++ else
++#endif
++ {
++ sock->writes.addr = to->dest.addr.in4;
++ sock->writes.addrlen = sizeof (sock->writes.addr);
++ }
+
+ status = WSASendTo(
+ sock->sd,
+@@ -2483,7 +3248,7 @@
+ &sock->writes.overlapped,
+ NULL);
+ }
+- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
++ else if (proto_is_tcp(sock->info.proto))
+ {
+ /* destination address for TCP writes was established on connection initiation */
+ sock->writes.addr_defined = false;
+@@ -2622,13 +3387,44 @@
+ if (from)
+ {
+ if (ret >= 0 && io->addr_defined)
++#ifdef USE_PF_INET6
++ {
++ /* TODO(jjo): streamline this mess */
++ /* in this func we dont have relevant info about the PF_ of this
++ * endpoint, as link_socket_actual will be zero for the 1st received packet
++ *
++ * Test for inets PF_ possible sizes
++ */
++ switch (io->addrlen)
++ {
++ case sizeof(struct sockaddr_in):
++ case sizeof(struct sockaddr_in6):
++ /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 */
++ case sizeof(struct sockaddr_in6)-4:
++ break;
++ default:
++ bad_address_length (io->addrlen, af_addr_size(io->addr.sin_family));
++ }
++
++ switch (io->addr.sin_family)
++ {
++ case AF_INET:
++ from->dest.addr.in4 = io->addr;
++ break;
++ case AF_INET6:
++ from->dest.addr.in6 = io->addr6;
++ break;
++ }
++ }
++#else
+ {
+ if (io->addrlen != sizeof (io->addr))
+ bad_address_length (io->addrlen, sizeof (io->addr));
+- from->dest.sa = io->addr;
++ from->dest.addr.in4 = io->addr;
+ }
++#endif
+ else
+- CLEAR (from->dest.sa);
++ CLEAR (from->dest.addr);
+ }
+
+ if (buf)
+Index: openvpn-2.2.1/socket.h
+===================================================================
+--- openvpn-2.2.1.orig/socket.h 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/socket.h 2011-12-13 12:23:07.382080084 +0100
+@@ -70,7 +70,13 @@
+ struct openvpn_sockaddr
+ {
+ /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */
+- struct sockaddr_in sa;
++ union {
++ struct sockaddr sa;
++ struct sockaddr_in in4;
++#ifdef USE_PF_INET6
++ struct sockaddr_in6 in6;
++#endif
++ } addr;
+ };
+
+ /* actual address of remote, based on source address of received packets */
+@@ -79,7 +85,17 @@
+ /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
+ struct openvpn_sockaddr dest;
+ #if ENABLE_IP_PKTINFO
+- struct in_pktinfo pi;
++ union {
++#ifdef HAVE_IN_PKTINFO
++ struct in_pktinfo in4;
++#endif
++#ifdef IP_RECVDSTADDR
++ struct in_addr in4;
++#endif
++#ifdef USE_PF_INET6
++ struct in6_pktinfo in6;
++#endif
++ } pi;
+ #endif
+ };
+
+@@ -199,6 +215,7 @@
+ # define SF_TCP_NODELAY (1<<1)
+ # define SF_PORT_SHARE (1<<2)
+ # define SF_HOST_RANDOMIZE (1<<3)
++# define SF_GETADDRINFO_DGRAM (1<<4)
+ unsigned int sockflags;
+
+ /* for stream sockets */
+@@ -371,6 +388,12 @@
+
+ void bad_address_length (int actual, int expected);
+
++#ifdef USE_PF_INET6
++/* IPV4_INVALID_ADDR: returned by link_socket_current_remote()
++ * to ease redirect-gateway logic for ipv4 tunnels on ipv6 endpoints
++ */
++#define IPV4_INVALID_ADDR 0xffffffff
++#endif
+ in_addr_t link_socket_current_remote (const struct link_socket_info *info);
+
+ void link_socket_connection_initiated (const struct buffer *buf,
+@@ -410,6 +433,14 @@
+ socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
+ struct link_socket_actual *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);
++
+
+ #if UNIX_SOCK_SUPPORT
+
+@@ -455,6 +486,11 @@
+ #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8)
+ #define GETADDR_RANDOMIZE (1<<9)
+
++/* [ab]use flags bits to get socktype info downstream */
++/* TODO(jjo): resolve tradeoff between hackiness|args-overhead */
++#define GETADDR_DGRAM (1<<10)
++#define dnsflags_to_socktype(flags) ((flags & GETADDR_DGRAM) ? SOCK_DGRAM : SOCK_STREAM)
++
+ in_addr_t getaddr (unsigned int flags,
+ const char *hostname,
+ int resolve_retry_seconds,
+@@ -472,23 +508,38 @@
+ * 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
++/*
++ * 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,
++#ifdef USE_PF_INET6
++ PROTO_UDPv6,
++ PROTO_TCPv6_SERVER,
++ PROTO_TCPv6_CLIENT,
++ PROTO_TCPv6,
++#endif
++ 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
+
+ extern const int proto_overhead[];
+
+@@ -518,7 +569,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
+@@ -533,7 +584,36 @@
+ static inline bool
+ addr_defined (const struct openvpn_sockaddr *addr)
+ {
+- return addr->sa.sin_addr.s_addr != 0;
++ if (!addr) return 0;
++ switch (addr->addr.sa.sa_family) {
++ case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0;
++#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 link_socket_actual *lsa)
++{
++#if ENABLE_IP_PKTINFO
++ if (!lsa) return 0;
++ switch (lsa->dest.addr.sa.sa_family) {
++#ifdef HAVE_IN_PKTINFO
++ case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
++#endif
++#ifdef IP_RECVDSTADDR
++ case AF_INET: return lsa->pi.in4.s_addr != 0;
++#endif
++#ifdef USE_PF_INET6
++ case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
++#endif
++ default: return 0;
++ }
++#else
++ ASSERT(0);
++#endif
++ return false;
+ }
+
+ static inline bool
+@@ -545,20 +625,50 @@
+ static inline bool
+ addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
+ {
+- return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr;
++ switch(a1->addr.sa.sa_family) {
++ case AF_INET:
++ return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
++#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 openvpn_sockaddr *s)
++addr_host (const struct openvpn_sockaddr *addr)
+ {
+- return ntohl (s->sa.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)
++ if(addr->addr.sa.sa_family != AF_INET)
++ return 0;
++#else
++ ASSERT(addr->addr.sa.sa_family == AF_INET);
++#endif
++ return ntohl (addr->addr.in4.sin_addr.s_addr);
+ }
+
+ static inline bool
+ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
+ {
+- return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr
+- && a1->sa.sin_port == a2->sa.sin_port;
++ switch(a1->addr.sa.sa_family) {
++ case AF_INET:
++ return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
++ && a1->addr.in4.sin_port == a2->addr.in4.sin_port;
++#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
+@@ -571,6 +681,74 @@
+ : addr_port_match (a1, a2);
+ }
+
++static inline void
++addr_zero_host(struct openvpn_sockaddr *addr)
++{
++ switch(addr->addr.sa.sa_family) {
++ case AF_INET:
++ addr->addr.in4.sin_addr.s_addr = 0;
++ break;
++#ifdef USE_PF_INET6
++ case AF_INET6:
++ memset(&addr->addr.in6.sin6_addr, 0, sizeof (struct in6_addr));
++ break;
++#endif
++ }
++}
++
++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.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr;
++ break;
++#ifdef USE_PF_INET6
++ case AF_INET6:
++ dst->addr.in6.sin6_addr = src->addr.in6.sin6_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(unsigned short 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", af);
++ ASSERT(0);
++#endif
++ return 0;
++ }
++#else /* only AF_INET */
++ return sizeof(struct sockaddr_in);
++#endif
++}
++
+ static inline bool
+ link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2)
+ {
+@@ -627,14 +805,18 @@
+ {
+ if (buf->len > 0)
+ {
+- if (from_addr->dest.sa.sin_family != AF_INET)
+- return false;
+- if (!link_socket_actual_defined (from_addr))
+- return false;
+- if (info->remote_float || !addr_defined (&info->lsa->remote))
+- return true;
+- if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
+- return true;
++ switch (from_addr->dest.addr.sa.sa_family) {
++#ifdef USE_PF_INET6
++ case AF_INET6:
++#endif
++ case AF_INET:
++ if (!link_socket_actual_defined (from_addr))
++ return false;
++ if (info->remote_float || !addr_defined (&info->lsa->remote))
++ return true;
++ if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
++ return true;
++ }
+ }
+ return false;
+ }
+@@ -740,7 +922,7 @@
+ int maxsize,
+ struct link_socket_actual *from)
+ {
+- if (sock->info.proto == PROTO_UDPv4)
++ if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
+ {
+ int res;
+
+@@ -751,10 +933,10 @@
+ #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->dest.sa = sock->info.lsa->actual.dest.sa;
++ addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest);
+ return link_socket_read_tcp (sock, buf);
+ }
+ else
+@@ -809,13 +991,14 @@
+ struct buffer *buf,
+ struct link_socket_actual *to);
+
+- if (sock->sockflags & SF_USE_IP_PKTINFO)
++ if (proto_is_udp(sock->info.proto) && (sock->sockflags & 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,
+- (struct sockaddr *) &to->dest.sa,
+- (socklen_t) sizeof (to->dest.sa));
++ (struct sockaddr *) &to->dest.addr.sa,
++ (socklen_t) af_addr_size(to->dest.addr.sa.sa_family));
+ }
+
+ static inline int
+@@ -846,11 +1029,11 @@
+ struct buffer *buf,
+ struct link_socket_actual *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);
+ }
+Index: openvpn-2.2.1/socks.c
+===================================================================
+--- openvpn-2.2.1.orig/socks.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/socks.c 2011-12-13 12:23:07.386080032 +0100
+@@ -299,9 +299,9 @@
+
+ if (addr != NULL)
+ {
+- addr->sa.sin_family = AF_INET;
+- addr->sa.sin_addr.s_addr = htonl (INADDR_ANY);
+- addr->sa.sin_port = htons (0);
++ addr->addr.in4.sin_family = AF_INET;
++ addr->addr.in4.sin_addr.s_addr = htonl (INADDR_ANY);
++ addr->addr.in4.sin_port = htons (0);
+ }
+
+ while (len < 4 + alen + 2)
+@@ -388,8 +388,8 @@
+ /* ATYP == 1 (IP V4 address) */
+ if (atyp == '\x01' && addr != NULL)
+ {
+- memcpy (&addr->sa.sin_addr, buf + 4, sizeof (addr->sa.sin_addr));
+- memcpy (&addr->sa.sin_port, buf + 8, sizeof (addr->sa.sin_port));
++ memcpy (&addr->addr.in4.sin_addr, buf + 4, sizeof (addr->addr.in4.sin_addr));
++ memcpy (&addr->addr.in4.sin_port, buf + 8, sizeof (addr->addr.in4.sin_port));
+ }
+
+
+@@ -507,8 +507,8 @@
+ if (atyp != 1) /* ATYP == 1 (IP V4) */
+ goto error;
+
+- buf_read (buf, &from->dest.sa.sin_addr, sizeof (from->dest.sa.sin_addr));
+- buf_read (buf, &from->dest.sa.sin_port, sizeof (from->dest.sa.sin_port));
++ buf_read (buf, &from->dest.addr.in4.sin_addr, sizeof (from->dest.addr.in4.sin_addr));
++ buf_read (buf, &from->dest.addr.in4.sin_port, sizeof (from->dest.addr.in4.sin_port));
+
+ return;
+
+@@ -540,8 +540,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->dest.sa.sin_addr, sizeof (to->dest.sa.sin_addr));
+- buf_write (&head, &to->dest.sa.sin_port, sizeof (to->dest.sa.sin_port));
++ buf_write (&head, &to->dest.addr.in4.sin_addr, sizeof (to->dest.addr.in4.sin_addr));
++ buf_write (&head, &to->dest.addr.in4.sin_port, sizeof (to->dest.addr.in4.sin_port));
+
+ return 10;
+ }
+Index: openvpn-2.2.1/syshead.h
+===================================================================
+--- openvpn-2.2.1.orig/syshead.h 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/syshead.h 2011-12-13 12:23:07.389079996 +0100
+@@ -28,6 +28,10 @@
+ /*
+ * Only include if not during configure
+ */
++#ifdef WIN32
++/* USE_PF_INET6: win32 ipv6 exists only after 0x0501 (XP) */
++#define WINVER 0x0501
++#endif
+ #ifndef PACKAGE_NAME
+ #include "config.h"
+ #endif
+@@ -339,6 +343,9 @@
+ #ifdef WIN32
+ #include <iphlpapi.h>
+ #include <wininet.h>
++/* The following two headers are needed of USE_PF_INET6 */
++#include <winsock2.h>
++#include <ws2tcpip.h>
+ #endif
+
+ #ifdef HAVE_SYS_MMAN_H
+@@ -383,9 +390,10 @@
+ #endif
+
+ /*
+- * Does this platform support linux-style IP_PKTINFO?
++ * Does this platform support linux-style IP_PKTINFO
++ * or bsd-style IP_RECVDSTADDR ?
+ */
+-#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)
++#if defined(ENABLE_MULTIHOME) && ((defined(HAVE_IN_PKTINFO)&&defined(IP_PKTINFO)) || defined(IP_RECVDSTADDR)) && 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
+Index: openvpn-2.2.1/tun.c
+===================================================================
+--- openvpn-2.2.1.orig/tun.c 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/tun.c 2011-12-13 12:23:07.394079932 +0100
+@@ -1688,7 +1688,9 @@
+ strerror(errno));
+ }
+
++#ifdef IFF_MULTICAST /* openbsd 4.x doesn't have this */
+ info.flags |= IFF_MULTICAST;
++#endif
+
+ if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) {
+ msg (M_WARN | M_ERRNO, "Can't set interface info: %s",
+Index: openvpn-2.2.1/win32.h
+===================================================================
+--- openvpn-2.2.1.orig/win32.h 2011-06-24 08:13:39.000000000 +0200
++++ openvpn-2.2.1/win32.h 2011-12-13 12:23:07.396079908 +0100
+@@ -195,7 +195,10 @@
+ DWORD flags;
+ int status;
+ bool addr_defined;
+- struct sockaddr_in addr;
++ union {
++ struct sockaddr_in addr;
++ struct sockaddr_in6 addr6;
++ };
+ int addrlen;
+ struct buffer buf_init;
+ struct buffer buf;