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;
