diff --git a/jjo-tests/libtest.sh b/jjo-tests/libtest.sh new file mode 100755 index 0000000..ab0d4b5 --- /dev/null +++ b/jjo-tests/libtest.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +typeset -i test_num=0 # increments w/each test_define +typeset test_msg # prefix: "test nr#" for msgs +typeset test_name # test name given +typeset test_sanename # test name with all whitespace (and alike) replaced by '_' + +TEST_CLEANUP=":" + +say () { + echo "$@" >&3 +} +err () { + echo "$@" >&4 +} +debug () { + echo "$@" >&4 +} +test_define() { + test_name="$*" + test_sanename="$(echo -n $test_name| tr -c '[A-Za-z0-9._]' _ )" + test_num=test_num+1 + test_msg="test $test_num" + test_bg_cleanup +} +test_expect_success () { + local msg="$1" + test $# -ge 2 || { err "usage error: test_expect_failure msg cmd args ..."; return 1; } + say -n "$test_msg: -- $msg (expecting success) " + shift + (eval "$@" 4>&1) && { say -e "\n$test_msg: OK %%% $test_sanename" ; return 0 ; } + say -e "\n$test_msg: FAILED %%% $test_sanename" + return 1 +} + +test_expect_failure () { + local msg="$1" + test $# -ge 2 || { err "usage error: test_expect_failure msg cmd args ..."; return 1;} + say -n "$test_msg: -- $msg (expecting failure) " + shift + (eval "$@") && { say -e "\n$test_msg: FAILED %%% $test_sanename" >&3 ; return 0 ; } + say -e "\n$test_msg: OK %%% $test_sanename" + return 1 +} + +test_bg_egrep() { + local nsecs="$1" + local txt="$2" + local ret + shift 2 + test_expect_success "$test_name" \ + "set -m ; $@ &> $t/out-$test_sanename & + s=1; + for i in \$(seq 1 $nsecs);do + say -n '.' + kill -0 %1 || { egrep failed $t/out-$test_sanename >&4; break; } + o=\$(egrep \"$txt\" $t/out-$test_sanename ) && { debug \$o; s=0; break; } + sleep 1; + done; + kill %1 + wait + exit \$s + " 2>/dev/null 4>$t/err + ret=$? + test $ret -eq 0 && return 0 + say "$test_msg: see: $t/out-$test_sanename*" + return $ret +} +# run command in *current* shell ignoring stderr, evals args passed +quiet2() { + #backup fd=2 + exec 250>&2 + exec 2>/dev/null + eval "$@" + #close auxfd + exec 2>&250 + exec 250>&- +} +test_bg_prev(){ local out=$t/out-$test_sanename-prev; $@ >& $out & } +test_bg_cleanup() { quiet2 "$TEST_CLEANUP;${@:-:};kill % 2>/dev/null;wait" ;} +test_set_cleanup () { TEST_CLEANUP="${*:-:}" ;} + +t=/tmp +exec 3>&1 +exec 4>&2 + +#========= + +ln -sf $PWD/openvpn $t/openvpn-test +export OPENVPN=$t/openvpn-test + +test_set_cleanup "killall $OPENVPN" + +trap 'test_bg_cleanup;exit' 0 2 15 + +test_define "UDP6 loopback" +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-udp6-0-loopback-self.sh + +test_define "UDP6 loopback byname" +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-udp6-0-loopback-byname.sh + +test_define "TCP6 loopback" +test_bg_prev ../jjo-tests/run-tcp6-0-loopback-server.sh +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-tcp6-0-loopback-client.sh + +test_define "TCP6 loopback byname" +test_bg_prev ../jjo-tests/run-tcp6-0-loopback-server-byname.sh +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-tcp6-0-loopback-client-byname.sh + +test_define "UDP4 loopback" +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-udp4-0-loopback-self.sh + +test_define "TCP4 loopback" +test_bg_prev ../jjo-tests/run-tcp4-0-loopback-server.sh +test_bg_egrep 30 "Initialization Sequence Completed" ../jjo-tests/run-tcp4-0-loopback-client.sh diff --git a/jjo-tests/qemu-ifup-2.jjo.sh b/jjo-tests/qemu-ifup-2.jjo.sh new file mode 100755 index 0000000..60418ad --- /dev/null +++ b/jjo-tests/qemu-ifup-2.jjo.sh @@ -0,0 +1,12 @@ +#!/bin/sh -x +#sudo sh -c "/sbin/ifconfig $1 hw ether 00:00:00:00:00:01; /sbin/ifconfig $1 192.168.254.1" +export PATH=/sbin:/usr/sbin:$PATH +NUM=2 +DEV=qemutun$NUM +sudo sh -x < 0) + { + strncpynt ((char *)ptr,str, cap); + *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ + buf->len += (int) strlen ((char *)ptr); + } +} + + /* * This is necessary due to certain buggy implementations of snprintf, * that don't guarantee null termination for size > 0. diff --git a/openvpn/configure.ac b/openvpn/configure.ac index 8843a2c..8cea204 100644 --- a/openvpn/configure.ac +++ b/openvpn/configure.ac @@ -101,6 +101,12 @@ AC_ARG_ENABLE(multihome, [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"], @@ -406,6 +412,16 @@ LDFLAGS="$LDFLAGS -Wl,--fatal-warnings" AC_CHECK_FUNCS(epoll_create, AC_DEFINE([HAVE_EPOLL_CREATE], 1, [])) 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 diff --git a/openvpn/helper.c b/openvpn/helper.c index d2b3d6f..459f00d 100644 --- a/openvpn/helper.c +++ b/openvpn/helper.c @@ -358,6 +358,10 @@ #endif /* P2MP_SERVER */ if (o->proto == PROTO_TCPv4) o->proto = PROTO_TCPv4_CLIENT; +#ifdef USE_PF_INET6 + else if (o->proto == PROTO_TCPv6) + o->proto = PROTO_TCPv6_CLIENT; +#endif } #endif /* P2MP */ diff --git a/openvpn/init.c b/openvpn/init.c index 244f03c..0d929e4 100644 --- a/openvpn/init.c +++ b/openvpn/init.c @@ -703,7 +703,7 @@ #ifdef ENABLE_MANAGEMENT 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); + 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, @@ -1105,7 +1105,7 @@ do_deferred_options (struct context *c, #ifdef ENABLE_OCC if (found & OPT_P_EXPLICIT_NOTIFY) { - if (c->options.proto != PROTO_UDPv4 && c->options.explicit_exit_notification) + if (!proto_is_udp(c->options.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; @@ -1200,12 +1200,21 @@ #endif switch (c->options.proto) { case PROTO_UDPv4: +#ifdef USE_PF_INET6 + case PROTO_UDPv6: +#endif if (proxy) sec = c->options.connect_retry_seconds; break; +#ifdef USE_PF_INET6 + case PROTO_TCPv6_SERVER: +#endif case PROTO_TCPv4_SERVER: sec = 1; break; +#ifdef USE_PF_INET6 + case PROTO_TCPv6_CLIENT: +#endif case PROTO_TCPv4_CLIENT: sec = c->options.connect_retry_seconds; break; @@ -2292,7 +2301,7 @@ do_setup_fast_io (struct context *c) #ifdef WIN32 msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else - if (c->options.proto != PROTO_UDPv4) + if (!proto_is_udp(c->options.proto)) msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP"); else { @@ -2549,7 +2558,11 @@ init_instance (struct context *c, const /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ +#ifdef USE_PF_INET6 + if (c->options.proto == PROTO_TCPv4_SERVER || c->options.proto == PROTO_TCPv6_SERVER) +#else if (c->options.proto == PROTO_TCPv4_SERVER) +#endif { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; @@ -2809,17 +2822,7 @@ inherit_context_child (struct context *d { CLEAR (*dest); - switch (src->options.proto) - { - case PROTO_UDPv4: - dest->mode = CM_CHILD_UDP; - break; - case PROTO_TCPv4_SERVER: - dest->mode = CM_CHILD_TCP; - break; - default: - ASSERT (0); - } + dest->mode = proto_is_dgram(src->options.proto)? CM_CHILD_UDP : CM_CHILD_TCP; dest->gc = gc_new (); @@ -2924,7 +2927,7 @@ #endif dest->c2.buffers_owned = false; dest->c2.event_set = NULL; - if (src->options.proto == PROTO_UDPv4) + if (proto_is_dgram(src->options.proto)) do_event_set_init (dest, false); } diff --git a/openvpn/manage.c b/openvpn/manage.c index 993afa2..2615137 100644 --- a/openvpn/manage.c +++ b/openvpn/manage.c @@ -1351,9 +1351,9 @@ man_settings_init (struct man_settings * /* * 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 @@ -1365,7 +1365,7 @@ man_settings_init (struct man_settings * } 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); } @@ -1634,7 +1634,7 @@ management_post_tunnel_open (struct mana && 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); } diff --git a/openvpn/mroute.c b/openvpn/mroute.c index a7d1215..8d85518 100644 --- a/openvpn/mroute.c +++ b/openvpn/mroute.c @@ -175,25 +175,47 @@ bool mroute_extract_openvpn_sockaddr (st 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; } @@ -268,7 +290,37 @@ mroute_addr_print (const struct mroute_a } break; case MR_ADDR_IPV6: +#ifdef USE_PF_INET6 + { + struct buffer buf; + struct sockaddr_in6 sin6; + int port; + char buf6[INET6_ADDRSTRLEN] = ""; + memset(&sin6, 0, sizeof sin6); + sin6.sin6_family = AF_INET6; + buf_set_read (&buf, maddr.addr, maddr.len); + if (buf_read(&buf, &sin6.sin6_addr, sizeof (sin6.sin6_addr))) + { + if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), + buf6, sizeof (buf6), NULL, 0, NI_NUMERICHOST) != 0) + { + buf_printf (&out, "MR_ADDR_IPV6 getnameinfo() err"); + break; + } + buf_puts (&out, buf6); + if (maddr.type & MR_WITH_NETBITS) + buf_printf (&out, "/%d", maddr.netbits); + if (maddr.type & MR_WITH_PORT) + { + port = buf_read_u16 (&buf); + if (port >= 0) + buf_printf (&out, ":%d", port); + } + } + } +#else /* old pre IPV6 1-line code: */ buf_printf (&out, "IPV6"); +#endif break; default: buf_printf (&out, "UNKNOWN"); diff --git a/openvpn/mtcp.c b/openvpn/mtcp.c index 6ec9974..5011688 100644 --- a/openvpn/mtcp.c +++ b/openvpn/mtcp.c @@ -159,6 +159,7 @@ multi_tcp_instance_specific_init (struct 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); 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"); diff --git a/openvpn/multi.c b/openvpn/multi.c index ee74a46..bfd79b3 100644 --- a/openvpn/multi.c +++ b/openvpn/multi.c @@ -990,8 +990,8 @@ multi_learn_in_addr_t (struct multi_cont 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) @@ -2224,9 +2224,9 @@ management_callback_kill_by_addr (void * 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, true); @@ -2287,18 +2287,13 @@ tunnel_server (struct context *top) { ASSERT (top->options.mode == MODE_SERVER); - switch (top->options.proto) { - case PROTO_UDPv4: - tunnel_server_udp (top); - break; - case PROTO_TCPv4_SERVER: - tunnel_server_tcp (top); - break; - default: - ASSERT (0); - } + if (proto_is_dgram(top->options.proto)) + tunnel_server_udp(top); + else + tunnel_server_tcp(top); } + #else static void dummy(void) {} #endif /* P2MP_SERVER */ diff --git a/openvpn/occ.c b/openvpn/occ.c index 6b136dc..3ec7784 100644 --- a/openvpn/occ.c +++ b/openvpn/occ.c @@ -375,7 +375,7 @@ process_received_occ_msg (struct context c->c2.max_send_size_remote, c->c2.max_recv_size_local); if (!c->options.fragment - && c->options.proto == PROTO_UDPv4 + && (proto_is_dgram(c->options.proto)) && c->c2.max_send_size_local > TUN_MTU_MIN && (c->c2.max_recv_size_remote < c->c2.max_send_size_local || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) diff --git a/openvpn/options.c b/openvpn/options.c index 94da98e..1490009 100644 --- a/openvpn/options.c +++ b/openvpn/options.c @@ -73,6 +73,12 @@ #endif #ifdef USE_PTHREAD " [PTHREAD]" #endif +#ifdef ENABLE_IP_PKTINFO + " [MH]" +#endif +#ifdef USE_PF_INET6 + " [PF_INET6]" +#endif " built on " __DATE__ ; @@ -93,6 +99,9 @@ static const char usage_message[] = "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" "--proto p : Use protocol p for communicating with peer.\n" " p = udp (default), tcp-server, or tcp-client\n" +#ifdef USE_PF_INET6 + " p = udp6, tcp6-server, or tcp6-client (IPv6)\n" +#endif "--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" @@ -1421,10 +1430,10 @@ #endif * Sanity check on TCP mode options */ - if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT) + if (options->connect_retry_defined && options->proto != PROTO_TCPv4_CLIENT && options->proto != PROTO_TCPv6_CLIENT) msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client"); - if (options->connect_timeout_defined && options->proto != PROTO_TCPv4_CLIENT) + if (options->connect_timeout_defined && options->proto != PROTO_TCPv4_CLIENT && options->proto != PROTO_TCPv6_CLIENT) msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client"); /* @@ -1434,7 +1443,7 @@ #endif msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); #ifdef ENABLE_OCC - if (options->proto != PROTO_UDPv4 && options->mtu_test) + if (!proto_is_udp(options->proto) && options->mtu_test) msg (M_USAGE, "--mtu-test only makes sense with --proto udp"); #endif @@ -1479,7 +1488,8 @@ #endif const char *remote = l->array[i].hostname; const int remote_port = l->array[i].port; - if (string_defined_equal (options->local, remote) + if (proto_is_net(options->proto) + && string_defined_equal (options->local, remote) && options->local_port == remote_port) msg (M_USAGE, "--remote and --local addresses are the same"); @@ -1508,7 +1518,7 @@ #endif if (!options->remote_list && !options->bind_local) msg (M_USAGE, "--nobind doesn't make sense unless used with --remote"); - if (options->proto == PROTO_TCPv4_CLIENT && !options->local && !options->local_port_defined && !options->bind_defined) + if ((options->proto == PROTO_TCPv4_CLIENT||options->proto == PROTO_TCPv6_CLIENT) && !options->local && !options->local_port_defined && !options->bind_defined) options->bind_local = false; #ifdef ENABLE_SOCKS @@ -1565,16 +1575,16 @@ #endif */ #ifdef ENABLE_FRAGMENT - if (options->proto != PROTO_UDPv4 && options->fragment) + if (!proto_is_udp(options->proto) && options->fragment) msg (M_USAGE, "--fragment can only be used with --proto udp"); #endif #ifdef ENABLE_OCC - if (options->proto != PROTO_UDPv4 && options->explicit_exit_notification) + if (!proto_is_udp(options->proto) && options->explicit_exit_notification) msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); #endif - if (!options->remote_list && options->proto == PROTO_TCPv4_CLIENT) + if (!options->remote_list && (options->proto == PROTO_TCPv4_CLIENT||options->proto == PROTO_TCPv6_CLIENT)) msg (M_USAGE, "--remote MUST be used in TCP Client mode"); #ifdef ENABLE_HTTP_PROXY @@ -1592,7 +1602,8 @@ #ifdef ENABLE_SOCKS msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); #endif - if (options->proto == PROTO_TCPv4_SERVER && remote_list_len (options->remote_list) > 1) + if ((options->proto == PROTO_TCPv4_SERVER||options->proto == PROTO_TCPv6_SERVER) + && remote_list_len (options->remote_list) > 1) msg (M_USAGE, "TCP server mode allows at most one --remote address"); #if P2MP_SERVER @@ -1617,7 +1628,7 @@ #endif msg (M_USAGE, "--mode server only works with --dev tun or --dev tap"); if (options->pull) msg (M_USAGE, "--pull cannot be used with --mode server"); - if (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER)) + if (!(proto_is_udp(options->proto) || options->proto == PROTO_TCPv4_SERVER || options->proto == PROTO_TCPv6_SERVER)) msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); #if PORT_SHARE if ((options->port_share_host || options->port_share_port) && options->proto != PROTO_TCPv4_SERVER) @@ -1645,9 +1656,9 @@ #endif msg (M_USAGE, "--inetd cannot be used with --mode server"); if (options->ipchange) msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); - if (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER)) - msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); - if (options->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per)) + if (!(proto_is_dgram(options->proto) || options->proto == PROTO_TCPv4_SERVER || options->proto == PROTO_TCPv6_SERVER )) + msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server (also udp6/tcp6)"); + if (!proto_is_udp(options->proto) && (options->cf_max || options->cf_per)) msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); if (!(dev == DEV_TYPE_TAP || (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"); @@ -1724,7 +1735,7 @@ #ifdef USE_CRYPTO /* * Check consistency of replay options */ - if ((options->proto != PROTO_UDPv4) + if ((!proto_is_udp(options->proto)) && (options->replay_window != defaults.replay_window || options->replay_time != defaults.replay_time)) msg (M_USAGE, "--replay-window only makes sense with --proto udp"); @@ -1913,7 +1924,7 @@ #if P2MP */ if (options->pull && options->ping_rec_timeout_action == PING_UNDEF - && options->proto == PROTO_UDPv4) + && proto_is_udp(options->proto)) { options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART; options->ping_rec_timeout_action = PING_RESTART; diff --git a/openvpn/ps.c b/openvpn/ps.c index 49b1a2c..472c626 100644 --- a/openvpn/ps.c +++ b/openvpn/ps.c @@ -337,9 +337,9 @@ sock_addr_set (struct openvpn_sockaddr * 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 diff --git a/openvpn/socket.c b/openvpn/socket.c index 70d8ffd..3074267 100644 --- a/openvpn/socket.c +++ b/openvpn/socket.c @@ -42,10 +42,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 }; /* @@ -260,20 +266,49 @@ struct openvpn_sockaddr *addr, bool *changed) { - if (host && addr) - { - const in_addr_t new_addr = getaddr ( - GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, - host, - 1, - NULL, - NULL); - if (new_addr && addr->sa.sin_addr.s_addr != new_addr) + switch(addr->addr.sa.sa_family) { + case AF_INET: + if (host && addr) + { + const in_addr_t new_addr = getaddr ( + GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, + host, + 1, + NULL, + NULL); + if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr) { - addr->sa.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: /* jjoFIXME: should adapt getaddr() for AF_INET6 */ + if (host && addr) + { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_PASSIVE; + hints.ai_family=AF_INET6; + if ((err=getaddrinfo(host, NULL, &hints, &ai))==0) + { + struct sockaddr_in6 *sin6=(struct sockaddr_in6*)ai->ai_addr; + if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &addr->addr.in6.sin6_addr)) + { + int port=addr->addr.in6.sin6_port; /* backup current port for easier copy, restore later */ + addr->addr.in6=*sin6; /* ipv6 requires also eg. sin6_scope_id => easy to full copy*/ + addr->addr.in6.sin6_port=port; + } + freeaddrinfo(ai); + } + } + break; +#endif + default: + ASSERT(0); + } } static int @@ -531,6 +566,44 @@ return sd; } +#ifdef USE_PF_INET6 +static socket_descriptor_t +create_socket_udp6 (const unsigned int flags) +{ + socket_descriptor_t sd; + + if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) + msg (M_SOCKERR, "UDP: Cannot create UDP6 socket"); +#if ENABLE_IP_PKTINFO + else if (flags & SF_USE_IP_PKTINFO) + { + int pad = 1; + setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, (void*)&pad, sizeof(pad)); + } +#endif + return sd; +} + +static socket_descriptor_t +create_socket_tcp6 (void) +{ + socket_descriptor_t sd; + + if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) + msg (M_SOCKERR, "Cannot create TCP6 socket"); + + /* set SO_REUSEADDR on socket */ + { + int on = 1; + if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof (on)) < 0) + msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); + } + + return sd; +} + +#endif static void create_socket (struct link_socket *sock) { @@ -549,6 +622,17 @@ { 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); + } +#endif else { ASSERT (0); @@ -586,7 +670,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); @@ -594,7 +683,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"); @@ -607,7 +696,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 */ @@ -623,7 +712,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); @@ -724,7 +814,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", @@ -745,7 +835,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) @@ -828,76 +918,99 @@ int retry = 0; #ifdef CONNECT_NONBLOCK - msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", - print_sockaddr (remote, &gc)); + msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", + print_sockaddr (remote, &gc)); #else - msg (M_INFO, "Attempting to establish TCP connection with %s", - print_sockaddr (remote, &gc)); + msg (M_INFO, "Attempting to establish TCP connection with %s", + print_sockaddr (remote, &gc)); #endif while (true) - { - int status; + { + int status; #ifdef ENABLE_MANAGEMENT - if (management) - management_set_state (management, - OPENVPN_STATE_TCP_CONNECT, - NULL, - (in_addr_t)0, - (in_addr_t)0); + if (management) + management_set_state (management, + OPENVPN_STATE_TCP_CONNECT, + NULL, + (in_addr_t)0, + (in_addr_t)0); #endif - status = openvpn_connect (*sd, remote, connect_timeout, signal_received); + status = openvpn_connect (*sd, remote, connect_timeout, signal_received); - get_signal (signal_received); - if (*signal_received) - goto done; - - if (!status) - break; - - msg (D_LINK_ERRORS, - "TCP: connect to %s failed, will try again in %d seconds: %s", - print_sockaddr (remote, &gc), - connect_retry_seconds, - strerror_ts (status, &gc)); - - gc_reset (&gc); - - openvpn_close_socket (*sd); - *sd = SOCKET_UNDEFINED; - - if (connect_retry_max > 0 && ++retry >= connect_retry_max) - { - *signal_received = SIGUSR1; - goto done; - } - - openvpn_sleep (connect_retry_seconds); - - get_signal (signal_received); - if (*signal_received) - goto done; + get_signal (signal_received); + if (*signal_received) + goto done; - if (remote_list) - { - remote_list_next (remote_list); - remote_dynamic = remote_list_host (remote_list); - remote->sa.sin_port = htons (remote_list_port (remote_list)); - *remote_changed = true; - } + if (!status) + break; - *sd = create_socket_tcp (); - if (bind_local) - socket_bind (*sd, local, "TCP Client"); - update_remote (remote_dynamic, remote, remote_changed); - } + msg (D_LINK_ERRORS, + "TCP: connect to %s failed, will try again in %d seconds: %s", + print_sockaddr (remote, &gc), + connect_retry_seconds, + strerror_ts (status, &gc)); + + + gc_reset (&gc); + + openvpn_close_socket (*sd); + *sd = SOCKET_UNDEFINED; + + if (connect_retry_max > 0 && ++retry >= connect_retry_max) + { + *signal_received = SIGUSR1; + goto done; + } + + openvpn_sleep (connect_retry_seconds); + + get_signal (signal_received); + if (*signal_received) + goto done; + + switch(remote->addr.sa.sa_family) { + case AF_INET: + if (remote_list) + { + remote_list_next (remote_list); + remote_dynamic = remote_list_host (remote_list); + remote->addr.in4.sin_port = htons (remote_list_port (remote_list)); + *remote_changed = true; + } + + *sd = create_socket_tcp (); + if (bind_local) + socket_bind (*sd, local, "TCP Client"); + update_remote (remote_dynamic, remote, remote_changed); + break; +#ifdef USE_PF_INET6 + case AF_INET6: + if (remote_list) + { + remote_list_next (remote_list); + remote_dynamic = remote_list_host (remote_list); + remote->addr.in6.sin6_port = htons (remote_list_port (remote_list)); + *remote_changed = true; + } + *sd = create_socket_tcp6 (); + if (bind_local) + socket_bind (*sd, local, "TCP6 Client"); + update_remote (remote_dynamic, remote, remote_changed); + break; +#endif + default: + msg(M_FATAL, "Only TCP is supported for connection oriented, sa_family=%d", + remote->addr.sa.sa_family); + } + } - msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + msg (M_INFO, "TCP connection established with %s", + print_sockaddr (remote, &gc)); - done: +done: gc_free (&gc); } @@ -952,17 +1065,44 @@ /* 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, - sock->local_host, - 0, - NULL, - NULL) - : htonl (INADDR_ANY)); - sock->info.lsa->local.sa.sin_port = htons (sock->local_port); + { + /* may return AF_{INET|INET6} guessed from local_host */ + switch(addr_guess_family(sock->info.proto, sock->local_host)) { + case AF_INET: + 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); + break; +#ifdef USE_PF_INET6 + case AF_INET6: + { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_PASSIVE; + hints.ai_family=AF_INET6; + /* if no local_host provided, ask for IN6ADDR_ANY ... */ + if ((err=getaddrinfo(sock->local_host? sock->local_host : "::", + NULL, &hints, &ai))==0) { + sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + } else { + msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s", + sock->local_host, + gai_strerror(err)); + } + sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); + } + break; +#endif } + } /* bind to local address/port */ if (sock->bind_local) @@ -986,103 +1126,128 @@ struct gc_arena gc = gc_new (); if (!sock->did_resolve_remote) + { + /* resolve remote address if undefined */ + if (!addr_defined (&sock->info.lsa->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; + switch(addr_guess_family(sock->info.proto, sock->remote_host)) + { + case AF_INET: + sock->info.lsa->remote.addr.in4.sin_family = AF_INET; + sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; if (sock->remote_host) - { - unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE; - int retry = 0; - bool status = false; + { + unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE; + int retry = 0; + bool status = false; - if (remote_list_len (sock->remote_list) > 1 && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) - { - if (phase == 2) - flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); - retry = 0; - } - else if (phase == 1) - { - if (sock->resolve_retry_seconds) - { - retry = 0; - } - else - { - flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); - retry = 0; - } - } - else if (phase == 2) - { - if (sock->resolve_retry_seconds) - { - flags |= GETADDR_FATAL; - retry = sock->resolve_retry_seconds; - } - else - { - ASSERT (0); - } - } + if (remote_list_len (sock->remote_list) > 1 && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) + { + if (phase == 2) + flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); + retry = 0; + } + else if (phase == 1) + { + if (sock->resolve_retry_seconds) + { + retry = 0; + } else - { - ASSERT (0); - } + { + flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); + retry = 0; + } + } + else if (phase == 2) + { + if (sock->resolve_retry_seconds) + { + flags |= GETADDR_FATAL; + retry = sock->resolve_retry_seconds; + } + else + { + ASSERT (0); + } + } + else + { + ASSERT (0); + } - sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr ( - flags, - sock->remote_host, - retry, - &status, - signal_received); - - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", - flags, - phase, - retry, - signal_received ? *signal_received : -1, - status); + sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( + flags, + sock->remote_host, + retry, + &status, + signal_received); + + dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); + if (signal_received) + { + if (*signal_received) + goto done; + } + if (!status) + { if (signal_received) - { - if (*signal_received) - goto done; - } - if (!status) - { - if (signal_received) - *signal_received = SIGUSR1; - goto done; - } + *signal_received = SIGUSR1; + goto done; } + } - sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port); - } - - /* should we re-use previous active remote address? */ - if (link_socket_actual_defined (&sock->info.lsa->actual)) - { - msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", - print_link_socket_actual (&sock->info.lsa->actual, &gc)); - if (remote_dynamic) - *remote_dynamic = NULL; - } - else - { - CLEAR (sock->info.lsa->actual); - sock->info.lsa->actual.dest = sock->info.lsa->remote; - } + sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); + break; - /* remember that we finished */ - sock->did_resolve_remote = true; +#ifdef USE_PF_INET6 + case AF_INET6: /* jjoFIXME: ipv6 signal logic */ + { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=0; + hints.ai_family=AF_INET6; + if ((err=getaddrinfo(sock->remote_host? sock->remote_host : "::" , NULL, &hints, &ai))==0) { + sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + } else { + msg (M_FATAL, "getaddrinfo() failed for remote \"%s\": %s", + sock->remote_host, + gai_strerror(err)); + } + sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); + } + break; +#endif + } + } + /* should we re-use previous active remote address? */ + if (link_socket_actual_defined (&sock->info.lsa->actual)) + { + msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", + print_link_socket_actual (&sock->info.lsa->actual, &gc)); + if (remote_dynamic) + *remote_dynamic = NULL; + } + else + { + CLEAR (sock->info.lsa->actual); + sock->info.lsa->actual.dest = sock->info.lsa->remote; } - done: + /* remember that we finished */ + sock->did_resolve_remote = true; + } + +done: gc_free (&gc); } @@ -1312,7 +1477,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) { @@ -1347,7 +1516,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 @@ -1432,8 +1605,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); @@ -1448,7 +1621,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); } } @@ -1620,13 +1793,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); } @@ -1641,10 +1821,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 + * + */ +#if defined ( USE_PF_INET6 ) + if(lsa->actual.dest.addr.sa.sa_family != AF_INET) + return 0; +#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; } @@ -1871,27 +2066,58 @@ const unsigned int flags, struct gc_arena *gc) { - if (addr) - { - struct buffer out = alloc_buf_gc (64, gc); - const int port = ntohs (addr->sa.sin_port); - - mutex_lock_static (L_INET_NTOA); - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); - mutex_unlock_static (L_INET_NTOA); + struct buffer out; + bool addr_is_defined; + if (!addr) { + return "[NULL]"; + } + addr_is_defined = addr_defined (addr); + switch(addr->addr.sa.sa_family) { + case AF_INET: + { + const int port= ntohs (addr->addr.in4.sin_port); + out = alloc_buf_gc (128, gc); + buf_puts (&out, "[AF_INET]"); + mutex_lock_static (L_INET_NTOA); + buf_puts (&out, (addr_is_defined ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]")); + mutex_unlock_static (L_INET_NTOA); - if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) + if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) + && port) { if (separator) buf_printf (&out, "%s", separator); buf_printf (&out, "%d", port); } - return BSTR (&out); - } - else - return "[NULL]"; + } + break; +#ifdef USE_PF_INET6 + case AF_INET6: + { + const int port= ntohs (addr->addr.in6.sin6_port); + char buf[INET6_ADDRSTRLEN] = "[undef]"; + out = alloc_buf_gc (128, gc); + buf_puts (&out, "[AF_INET6]"); + if (addr_is_defined) + { + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); + buf_puts (&out, buf); + } + if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) + && port) + { + if (separator) + buf_puts (&out, separator); + + buf_printf (&out, "%d", port); + } + } + break; +#endif + } + return BSTR (&out); } const char * @@ -1911,12 +2137,38 @@ 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)) { + switch(act->dest.addr.sa.sa_family) + { + case AF_INET: + { struct openvpn_sockaddr sa; CLEAR (sa); - sa.sa.sin_addr = act->pi.ipi_spec_dst; + sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); + } + break; +#ifdef USE_PF_INET6 + case AF_INET6: + { + struct sockaddr_in6 sin6; + char buf[INET6_ADDRSTRLEN] = "[undef]"; + memset(&sin6, 0, sizeof sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = act->pi.in6.ipi6_addr; + { + if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), + buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0) + buf_printf (&out, " (via %s)", buf); + else + buf_printf (&out, " (via [getnameinfo() err])"); + } + } + break; +#endif + } + } #endif return BSTR (&out); @@ -1952,21 +2204,37 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags) { char name_buf[256]; + char buf[128]; - 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); + switch(addr->addr.sa.sa_family) { + case AF_INET: + if (flags & SA_IP_PORT) + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); + else + openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); - mutex_lock_static (L_INET_NTOA); - setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr)); - mutex_unlock_static (L_INET_NTOA); + mutex_lock_static (L_INET_NTOA); + setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr)); + mutex_unlock_static (L_INET_NTOA); + + 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)); + } + break; +#ifdef USE_PF_INET6 + case AF_INET6: + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + setenv_str (es, name_buf, buf); - 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)); - } + setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); + break; +#endif + } } void @@ -1976,7 +2244,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); } } @@ -1997,16 +2266,63 @@ struct proto_names { const char *short_form; const char *display_form; + bool is_dgram; + bool is_net; + sa_family_t proto_af; }; /* Indexed by PROTO_x */ -static const struct proto_names proto_names[] = { - {"udp", "UDPv4"}, - {"tcp-server", "TCPv4_SERVER"}, - {"tcp-client", "TCPv4_CLIENT"}, - {"tcp", "TCPv4"} +static const struct proto_names proto_names[PROTO_N] = { + {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC}, + {"udp", "UDPv4",1,1, AF_INET}, + {"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, + {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, + {"tcp", "TCPv4",0,1, AF_INET}, +#ifdef USE_PF_INET6 + {"udp6" ,"UDPv6",1,1, AF_INET6}, + {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, + {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, + {"tcp6" ,"TCPv6",0,1, AF_INET6}, +#endif }; +bool +proto_is_net(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_net; +} +bool +proto_is_dgram(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_dgram; +} +bool +proto_is_udp(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].is_dgram&&proto_names[proto].is_net; +} +bool +proto_is_tcp(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; +} + +sa_family_t +proto_sa_family(int proto) +{ + if (proto < 0 || proto >= PROTO_N) + ASSERT(0); + return proto_names[proto].proto_af; +} + int ascii2proto (const char* proto_name) { @@ -2046,6 +2362,46 @@ return BSTR (&out); } +int +addr_guess_family(int proto, const char *name) +{ + sa_family_t ret; + if (proto) { + return proto_sa_family(proto); /* already stamped */ + } +#ifdef USE_PF_UNIX + else if (name && name[0] == '/') { + return AF_UNIX; + } +#endif +#ifdef USE_PF_INET6 + else { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof hints); + hints.ai_flags=AI_NUMERICHOST; + if ((err=getaddrinfo(name, NULL, &hints, &ai))==0) { + ret=ai->ai_family; + freeaddrinfo(ai); + return ret; + } + } +#endif + return AF_INET; /* default */ +} +const char * +addr_family_name (int af) +{ + switch (af) { + case AF_INET: return "AF_INET"; + case AF_INET6: return "AF_INET6"; +#ifdef USE_PF_UNIX + case AF_UNIX: return "AF_UNIX"; +#endif + } + return "AF_UNSPEC"; +} + /* * Given a local proto, return local proto * if !remote, or compatible remote proto @@ -2060,10 +2416,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; } @@ -2121,12 +2482,27 @@ #if ENABLE_IP_PKTINFO -struct openvpn_pktinfo +struct openvpn_in4_pktinfo { struct cmsghdr cmsghdr; - struct in_pktinfo in_pktinfo; + struct in_pktinfo pi; +}; +#ifdef USE_PF_INET6 +struct openvpn_in6_pktinfo +{ + struct cmsghdr cmsghdr; + struct in6_pktinfo pi6; +}; +#endif + +union openvpn_pktinfo { + struct openvpn_in4_pktinfo cmsgpi; +#ifdef USE_PF_INET6 + struct openvpn_in6_pktinfo cmsgpi6; +#endif }; + static socklen_t link_socket_read_udp_posix_recvmsg (struct link_socket *sock, struct buffer *buf, @@ -2134,15 +2510,15 @@ 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); @@ -2159,9 +2535,21 @@ && cmsg->cmsg_len >= sizeof (opi)) { 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; + } +#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; } @@ -2173,18 +2561,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; } @@ -2221,26 +2611,52 @@ 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 opi; + struct in_pktinfo *pkti; + mesg.msg_name = &to->dest.addr.sa; + mesg.msg_namelen = sizeof (struct sockaddr_in); + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (opi); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = sizeof (opi); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); + pkti->ipi_ifindex = to->pi.in4.ipi_ifindex; + pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst; + pkti->ipi_addr.s_addr = 0; + break; + } +#ifdef USE_PF_INET6 + case AF_INET6: { + struct openvpn_in6_pktinfo opi6; + struct in6_pktinfo *pkti6; + mesg.msg_name = &to->dest.addr.sa; + mesg.msg_namelen = sizeof (struct sockaddr_in6); + mesg.msg_control = &opi6; + mesg.msg_controllen = sizeof (opi6); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = sizeof (opi6); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); + pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; + pkti6->ipi6_addr = to->pi.in6.ipi6_addr; + break; + } +#endif + default: ASSERT(0); + } return sendmsg (sock->sd, &mesg, 0); } @@ -2384,7 +2800,7 @@ { /* set destination address for UDP writes */ sock->writes.addr_defined = true; - sock->writes.addr = to->dest.sa; + sock->writes.addr = to->dest.addr.in4; sock->writes.addrlen = sizeof (sock->writes.addr); status = WSASendTo( @@ -2540,10 +2956,10 @@ { if (io->addrlen != sizeof (io->addr)) bad_address_length (io->addrlen, sizeof (io->addr)); - from->dest.sa = io->addr; + from->dest.addr.sa = io->addr; } else - CLEAR (from->dest.sa); + CLEAR (from->dest.addr.sa); } if (buf) diff --git a/openvpn/socket.h b/openvpn/socket.h index 28bf41f..435cf38 100644 --- a/openvpn/socket.h +++ b/openvpn/socket.h @@ -81,7 +81,13 @@ #define ntohps(x) ntohs(x) 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 */ @@ -90,7 +96,12 @@ struct link_socket_actual int dummy; /* JYFIXME -- add offset to force a bug if dest not explicitly dereferenced */ struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO - struct in_pktinfo pi; + union { + struct in_pktinfo in4; +#ifdef USE_PF_INET6 + struct in6_pktinfo in6; +#endif + } pi; #endif }; @@ -411,6 +422,14 @@ socket_descriptor_t create_socket_tcp (v 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); + /* * DNS resolution @@ -436,23 +455,49 @@ in_addr_t getaddr (unsigned int flags, * Transport protocol naming and other details. */ -#define PROTO_UDPv4 0 -#define PROTO_TCPv4_SERVER 1 -#define PROTO_TCPv4_CLIENT 2 -#define PROTO_TCPv4 3 -#define PROTO_N 4 +#if 0 /* PRE UDPv6/TCPv6 code */ +#define PROTO_NONE 0 /* catch for uninitialized */ +#define PROTO_UDPv4 1 +#define PROTO_TCPv4_SERVER 2 +#define PROTO_TCPv4_CLIENT 3 +#define PROTO_TCPv4 4 +#define PROTO_UDPv6 5 +#define PROTO_TCPv6_SERVER 6 +#define PROTO_TCPv6_CLIENT 7 +#define PROTO_TCPv6 8 +#define PROTO_N 9 +#endif /* if 0 */ + +/* + * Use enum's instead of #define to allow for easier + * optional proto support + */ +enum proto_num { + PROTO_NONE, /* catch for uninitialized */ + PROTO_UDPv4, + PROTO_TCPv4_SERVER, + PROTO_TCPv4_CLIENT, + PROTO_TCPv4, + PROTO_UDPv6, + PROTO_TCPv6_SERVER, + PROTO_TCPv6_CLIENT, + PROTO_TCPv6, + PROTO_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[]; @@ -485,7 +530,7 @@ legal_ipv4_port (int port) 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 @@ -500,7 +545,30 @@ link_socket_connection_oriented (const s 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) { + case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; +#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 } static inline bool @@ -512,20 +580,50 @@ link_socket_actual_defined (const struct 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 @@ -538,6 +636,74 @@ addr_match_proto (const struct openvpn_s : 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(sa_family_t af) +{ +#if defined(USE_PF_INET6) || defined (USE_PF_UNIX) + switch(af) { + case AF_INET: return sizeof (struct sockaddr_in); +#ifdef USE_PF_UNIX + case AF_UNIX: return sizeof (struct sockaddr_un); +#endif +#ifdef USE_PF_INET6 + case AF_INET6: return sizeof (struct sockaddr_in6); +#endif + default: +#if 0 + /* could be called from socket_do_accept() with empty addr */ + msg (M_ERR, "Bad address family: %d\n", addr->sa_family); + ASSERT(0); +#endif + return 0; + } +#else /* only AF_INET */ + return sizeof(struct sockaddr_in); +#endif +} + static inline bool link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2) { @@ -594,14 +760,18 @@ link_socket_verify_incoming_addr (struct { 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; } @@ -707,7 +877,7 @@ link_socket_read (struct link_socket *so 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; @@ -718,10 +888,10 @@ #else #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 @@ -776,13 +946,14 @@ #if ENABLE_IP_PKTINFO 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 @@ -813,11 +984,11 @@ link_socket_write (struct link_socket *s 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); } diff --git a/openvpn/socks.c b/openvpn/socks.c index cc9d82f..7ec9a3e 100644 --- a/openvpn/socks.c +++ b/openvpn/socks.c @@ -175,9 +175,9 @@ recv_socks_reply (socket_descriptor_t sd 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) @@ -264,8 +264,8 @@ recv_socks_reply (socket_descriptor_t sd /* 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)); } @@ -383,8 +383,8 @@ socks_process_incoming_udp (struct buffe 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; @@ -416,8 +416,8 @@ socks_process_outgoing_udp (struct buffe 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; }