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