From 8335caf929f21b317a0243a12285e1f04361db25 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sun, 13 Sep 2009 13:43:04 +0200 Subject: [PATCH 01/37] * rebased openvpn-2.1_rc1b.jjo.20061206.d.patch * passes {udp,tcp}x{v4,v6} loopback tests * passes {udp,tcp}x{v6} remote tests --- buffer.c | 13 ++ configure.ac | 16 ++ init.c | 36 ++-- manage.c | 10 +- mroute.c | 60 +++++- mtcp.c | 1 + multi.c | 17 +- occ.c | 2 +- options.c | 41 ++-- ps.c | 6 +- socket.c | 591 ++++++++++++++++++++++++++++++++++++++++++--------- socket.h | 233 +++++++++++++++++--- socks.c | 18 +- 13 files changed, 855 insertions(+), 189 deletions(-) diff --git a/buffer.c b/buffer.c index e2f8caab..c43cb470 100644 --- a/buffer.c +++ b/buffer.c @@ -214,6 +214,19 @@ buf_printf (struct buffer *buf, const char *format, ...) return ret; } +void buf_puts(struct buffer *buf, const char *str) +{ + uint8_t *ptr = BEND (buf); + int cap = buf_forward_capacity (buf); + if (cap > 0) + { + strncpynt ((char *)ptr,str, cap); + *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ + buf->len += (int) strlen ((char *)ptr); + } +} + + /* * This is necessary due to certain buggy implementations of snprintf, * that don't guarantee null termination for size > 0. diff --git a/configure.ac b/configure.ac index e0847bcc..c3bd8e81 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,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"], @@ -566,6 +572,16 @@ LDFLAGS="$LDFLAGS -Wl,--fatal-warnings" 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 diff --git a/init.c b/init.c index a51b7d43..e9cb0899 100644 --- a/init.c +++ b/init.c @@ -96,7 +96,7 @@ update_options_ce_post (struct options *options) */ 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,7 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) 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, @@ -1569,7 +1569,7 @@ do_deferred_options (struct context *c, const unsigned int found) #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; @@ -1664,13 +1664,22 @@ socket_restart_pause (struct context *c) 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; } @@ -2810,7 +2819,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.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 { @@ -3086,7 +3095,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ +#ifdef USE_PF_INET6 + if (c->options.ce.proto == PROTO_TCPv4_SERVER || c->options.ce.proto == PROTO_TCPv6_SERVER) +#else if (c->options.ce.proto == PROTO_TCPv4_SERVER) +#endif { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; @@ -3361,17 +3374,8 @@ inherit_context_child (struct context *dest, { 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 (); @@ -3477,7 +3481,7 @@ inherit_context_top (struct context *dest, 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); } diff --git a/manage.c b/manage.c index 310a70eb..a4fd258c 100644 --- a/manage.c +++ b/manage.c @@ -1999,9 +1999,9 @@ man_settings_init (struct man_settings *ms, /* * 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 @@ -2013,7 +2013,7 @@ man_settings_init (struct man_settings *ms, } 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); } } @@ -2472,7 +2472,7 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i && 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/mroute.c b/mroute.c index 3debd80f..7477a510 100644 --- a/mroute.c +++ b/mroute.c @@ -226,25 +226,47 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, 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; } @@ -337,7 +359,37 @@ mroute_addr_print_ex (const struct mroute_addr *ma, } 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/mtcp.c b/mtcp.c index 314aa447..f8cc50ff 100644 --- a/mtcp.c +++ b/mtcp.c @@ -150,6 +150,7 @@ multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance 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/multi.c b/multi.c index cc3c4cb3..0196be9e 100644 --- a/multi.c +++ b/multi.c @@ -1058,8 +1058,8 @@ multi_learn_in_addr_t (struct multi_context *m, 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 @@ management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int por 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,6 +2675,12 @@ tunnel_server (struct context *top) { ASSERT (top->options.mode == MODE_SERVER); +#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); @@ -2685,6 +2691,7 @@ tunnel_server (struct context *top) default: ASSERT (0); } +#endif } #else diff --git a/occ.c b/occ.c index b84b18d9..bcf91cc2 100644 --- a/occ.c +++ b/occ.c @@ -369,7 +369,7 @@ process_received_occ_msg (struct context *c) 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)) diff --git a/options.c b/options.c index fca4a8e3..ec219298 100644 --- a/options.c +++ b/options.c @@ -79,6 +79,11 @@ const char title_string[] = #endif #ifdef ENABLE_EUREPHIA " [eurephia]" +#ifdef ENABLE_IP_PKTINFO + " [MH]" +#endif +#ifdef USE_PF_INET6 + " [PF_INET6]" #endif " built on " __DATE__ ; @@ -102,6 +107,9 @@ static const char usage_message[] = "--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" @@ -1695,10 +1703,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne * Sanity check on TCP mode options */ - if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT) + if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_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) + if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_CLIENT) msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client"); /* @@ -1708,7 +1716,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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 @@ -1721,7 +1729,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne * 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"); @@ -1786,16 +1795,16 @@ options_postprocess_verify_ce (const struct options *options, const struct conne */ #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 || ce->proto == PROTO_TCPv6_CLIENT)) msg (M_USAGE, "--remote MUST be used in TCP Client mode"); #ifdef ENABLE_HTTP_PROXY @@ -1813,7 +1822,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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 || ce->proto == PROTO_TCPv6_SERVER) + && connection_list_defined (options)) msg (M_USAGE, "TCP server mode allows at most one --remote address"); #if P2MP_SERVER @@ -1827,10 +1837,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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)) + if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->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) && ce->proto != PROTO_TCPv4_SERVER) + if ((options->port_share_host || options->port_share_port) && + (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER)) msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)"); #endif if (!options->tls_server) @@ -1859,9 +1870,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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)) + if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_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_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"); @@ -1954,7 +1965,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne /* * 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"); @@ -2127,6 +2138,10 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) { 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 diff --git a/ps.c b/ps.c index 9b9723cb..049b39fb 100644 --- a/ps.c +++ b/ps.c @@ -320,9 +320,9 @@ sock_addr_set (struct openvpn_sockaddr *osaddr, 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/socket.c b/socket.c index a49940d0..67bd2eb6 100644 --- a/socket.c +++ b/socket.c @@ -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 }; /* @@ -410,6 +416,8 @@ update_remote (const char* host, bool *changed, const unsigned int sockflags) { + switch(addr->addr.sa.sa_family) { + case AF_INET: if (host && addr) { const in_addr_t new_addr = getaddr ( @@ -418,12 +426,39 @@ update_remote (const char* host, 1, NULL, NULL); - if (new_addr && addr->sa.sin_addr.s_addr != new_addr) + 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: /* TODO(jjo): should adapt getaddr() + sf2gaf() 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 @@ -616,6 +651,44 @@ create_socket_udp (const unsigned int flags) 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) { @@ -634,6 +707,17 @@ create_socket (struct link_socket *sock) { 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); @@ -671,7 +755,12 @@ socket_do_accept (socket_descriptor_t sd, 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 +768,7 @@ socket_do_accept (socket_descriptor_t sd, #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 +781,7 @@ socket_do_accept (socket_descriptor_t sd, #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 +797,8 @@ socket_do_accept (socket_descriptor_t sd, { 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 +899,7 @@ socket_bind (socket_descriptor_t sd, { 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 +920,7 @@ openvpn_connect (socket_descriptor_t sd, #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) @@ -1030,17 +1120,44 @@ resolve_bind_local (struct link_socket *sock) /* 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) @@ -1068,8 +1185,11 @@ resolve_remote (struct link_socket *sock, /* 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) { @@ -1112,7 +1232,7 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr ( + sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( flags, sock->remote_host, retry, @@ -1139,7 +1259,29 @@ resolve_remote (struct link_socket *sock, } } - sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port); + sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); + break; +#ifdef USE_PF_INET6 + case AF_INET6: /* TODO(jjo): 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? */ @@ -1384,7 +1526,11 @@ link_socket_init_phase2 (struct link_socket *sock, 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) { @@ -1419,7 +1565,11 @@ link_socket_init_phase2 (struct link_socket *sock, 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 @@ -1506,8 +1656,8 @@ link_socket_init_phase2 (struct link_socket *sock, 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); @@ -1522,7 +1672,7 @@ link_socket_init_phase2 (struct link_socket *sock, 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 +1858,20 @@ link_socket_bad_incoming_addr (struct buffer *buf, { 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 +1886,25 @@ link_socket_current_remote (const struct link_socket_info *info) { 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; } @@ -1959,26 +2131,58 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, 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); + 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_DONT_SHOW_ADDR)) - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]")); - - 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 * @@ -1998,12 +2202,38 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, 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); @@ -2037,19 +2267,37 @@ void 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); - setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr)); + 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 @@ -2059,7 +2307,8 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c { 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 +2329,63 @@ setenv_link_socket_actual (struct env_set *es, 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) { @@ -2129,6 +2425,38 @@ proto2ascii_all (struct gc_arena *gc) 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_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"; + } + return "AF_UNSPEC"; +} + /* * Given a local proto, return local proto * if !remote, or compatible remote proto @@ -2143,10 +2471,15 @@ proto_remote (int proto, bool remote) 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 +2538,24 @@ link_socket_read_tcp (struct link_socket *sock, #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; - 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 }; #pragma pack() @@ -2219,15 +2566,15 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, 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); @@ -2244,9 +2591,21 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, && 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; } @@ -2258,18 +2617,20 @@ link_socket_read_udp_posix (struct link_socket *sock, 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 +2667,52 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, 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); } @@ -2469,7 +2856,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li { /* 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( @@ -2625,10 +3012,10 @@ socket_finalize (SOCKET s, { 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/socket.h b/socket.h index eef98d1b..ba8cd6e6 100644 --- a/socket.h +++ b/socket.h @@ -70,7 +70,13 @@ typedef uint16_t packet_size_type; 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,12 @@ struct link_socket_actual /*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 { + struct in_pktinfo in4; +#ifdef USE_PF_INET6 + struct in6_pktinfo in6; +#endif + } pi; #endif }; @@ -410,6 +421,14 @@ socket_descriptor_t create_socket_tcp (void); 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 @@ -472,23 +491,49 @@ in_addr_t getaddr_multi (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[]; @@ -518,7 +563,7 @@ is_proto_tcp(const int p) 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 +578,30 @@ link_socket_connection_oriented (const struct link_socket *sock) 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 @@ -545,20 +613,50 @@ link_socket_actual_defined (const struct link_socket_actual *act) 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 +669,74 @@ addr_match_proto (const struct openvpn_sockaddr *a1, : 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) { @@ -627,14 +793,18 @@ link_socket_verify_incoming_addr (struct buffer *buf, { 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 +910,7 @@ link_socket_read (struct link_socket *sock, 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 +921,10 @@ link_socket_read (struct link_socket *sock, #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 +979,14 @@ link_socket_write_udp_posix (struct link_socket *sock, 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 +1017,11 @@ link_socket_write (struct link_socket *sock, 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/socks.c b/socks.c index 82872743..949d2560 100644 --- a/socks.c +++ b/socks.c @@ -299,9 +299,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) @@ -388,8 +388,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)); } @@ -507,8 +507,8 @@ socks_process_incoming_udp (struct buffer *buf, 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 @@ socks_process_outgoing_udp (struct buffer *buf, 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; } From ea93a078053e2911b30a80685d82897159aee488 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 14 Sep 2009 18:31:42 +0200 Subject: [PATCH 02/37] * created getaddr6(), use it from resolve_remote() next: merge ipv{4,6} signal logic into one inside resolve_remote() * passes {loopback,remote}{udp,tcp}{4,6} tests --- socket.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 265 insertions(+), 15 deletions(-) diff --git a/socket.c b/socket.c index 67bd2eb6..a632f847 100644 --- a/socket.c +++ b/socket.c @@ -282,6 +282,188 @@ getaddr_multi (unsigned int flags, 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, + 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 (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 (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; + err = getaddrinfo(hostname, NULL, &hints, &ai); + + 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 (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; + return success; +} +#endif /* USE_PF_INET6 */ + /* * We do our own inet_aton because the glibc function * isn't very good about error checking. @@ -445,10 +627,11 @@ update_remote (const char* host, 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)) + 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*/ + 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; } freeaddrinfo(ai); @@ -1147,6 +1330,7 @@ resolve_bind_local (struct link_socket *sock) NULL, &hints, &ai))==0) { sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); freeaddrinfo(ai); + ai = NULL; } else { msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s", sock->local_host, @@ -1264,19 +1448,85 @@ resolve_remote (struct link_socket *sock, #ifdef USE_PF_INET6 case AF_INET6: /* TODO(jjo): 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)); + if (sock->remote_host) + { + unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); + int retry = 0; + bool status = false; + + if (sock->connection_profiles_defined && 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); + } + } + else + { + ASSERT (0); + } + + status = getaddr6 ( + flags, + sock->remote_host, + retry, + signal_received, + &sock->info.lsa->remote.addr.in6); + + 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) + *signal_received = SIGUSR1; + goto done; + } } + else + { + /* + * no ipv6 hostname given: + * shortcut instead of calling getaddrinfo("::", ...) + */ + + 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; + } + sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); } break; From 97ba084bc8b8cc5cc817c14c6032a313a493fa87 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 14 Sep 2009 21:51:54 +0200 Subject: [PATCH 03/37] * migrated all getaddrinfo() to getaddr6 * tests Ok: {loopback,remote}{udp,tcp}{4,6} --- socket.c | 234 ++++++++++++++++++++++++------------------------------- 1 file changed, 101 insertions(+), 133 deletions(-) diff --git a/socket.c b/socket.c index a632f847..229c0b0f 100644 --- a/socket.c +++ b/socket.c @@ -293,6 +293,7 @@ getaddr6 (unsigned int flags, const char *hostname, int resolve_retry_seconds, volatile int *signal_received, + int *gai_err, struct sockaddr_in6 *in6) { bool success; @@ -304,6 +305,9 @@ getaddr6 (unsigned int flags, ASSERT(in6); + if (!hostname) + hostname = "::"; + if (flags & GETADDR_RANDOMIZE) hostname = hostname_randomize(hostname, &gc); @@ -321,11 +325,15 @@ getaddr6 (unsigned int flags, 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 ((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? */ { @@ -368,6 +376,8 @@ getaddr6 (unsigned int flags, /* try hostname lookup */ hints.ai_flags = 0; err = getaddrinfo(hostname, NULL, &hints, &ai); + if (gai_err) + *gai_err = err; if (signal_received) { @@ -459,7 +469,6 @@ getaddr6 (unsigned int flags, } gc_free (&gc); - //return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; return success; } #endif /* USE_PF_INET6 */ @@ -616,27 +625,29 @@ update_remote (const char* host, } break; #ifdef USE_PF_INET6 - case AF_INET6: /* TODO(jjo): should adapt getaddr() + sf2gaf() for AF_INET6 */ + case 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; - /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */ - addr->addr.in6 = *sin6; - addr->addr.in6.sin6_port = port; - } - freeaddrinfo(ai); - } - } + { + 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: @@ -1320,22 +1331,30 @@ resolve_bind_local (struct link_socket *sock) #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); - ai = NULL; - } else { - msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s", - sock->local_host, - gai_strerror(err)); - } + 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, + &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; @@ -1363,17 +1382,27 @@ resolve_remote (struct link_socket *sock, volatile int *signal_received) { struct gc_arena gc = gc_new (); + int af; if (!sock->did_resolve_remote) { /* resolve remote address if undefined */ if (!addr_defined (&sock->info.lsa->remote)) { - 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; + af = addr_guess_family(sock->info.proto, sock->remote_host); + switch(af) { + case AF_INET: + sock->info.lsa->remote.addr.in4.sin_family = AF_INET; + sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; + break; +#ifdef USE_PF_INET6 + 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) { @@ -1416,85 +1445,28 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } + switch(af) { + case AF_INET: 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) - *signal_received = SIGUSR1; - goto done; - } - } - - sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); - break; + break; #ifdef USE_PF_INET6 - case AF_INET6: /* TODO(jjo): ipv6 signal logic */ - { - if (sock->remote_host) - { - unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); - int retry = 0; - bool status = false; - - if (sock->connection_profiles_defined && 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); - } - } - else - { - ASSERT (0); - } - + 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, @@ -1515,23 +1487,17 @@ resolve_remote (struct link_socket *sock, goto done; } } - else + switch(af) { - /* - * no ipv6 hostname given: - * shortcut instead of calling getaddrinfo("::", ...) - */ - - 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; - } - - sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); - } - break; + case AF_INET: + sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); + break; +#ifdef USE_PF_INET6 + 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? */ @@ -2688,11 +2654,13 @@ addr_guess_family(int proto, const char *name) 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; - } + err = getaddrinfo(name, NULL, &hints, &ai); + if ( 0 == err ) + { + ret=ai->ai_family; + freeaddrinfo(ai); + return ret; + } } #endif return AF_INET; /* default */ From d9c04efcdffc610163dcca988578cfe677c3af15 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 15 Sep 2009 09:22:46 +0200 Subject: [PATCH 04/37] * socket.c: use USE_PF_INET6 in switch constructs to actually toss them out, GNU indentation for my deltas --- socket.c | 450 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 235 insertions(+), 215 deletions(-) diff --git a/socket.c b/socket.c index 229c0b0f..f3a893d0 100644 --- a/socket.c +++ b/socket.c @@ -607,23 +607,24 @@ update_remote (const char* host, bool *changed, const unsigned int sockflags) { - switch(addr->addr.sa.sa_family) { - case AF_INET: - 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->addr.in4.sin_addr.s_addr != new_addr) + case AF_INET: + if (host && addr) { - addr->addr.in4.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; + break; #ifdef USE_PF_INET6 case AF_INET6: if (host && addr) @@ -651,7 +652,7 @@ update_remote (const char* host, break; #endif default: - ASSERT(0); + ASSERT(0); } } @@ -1314,53 +1315,54 @@ resolve_bind_local (struct link_socket *sock) /* resolve local address if undefined */ if (!addr_defined (&sock->info.lsa->local)) - { - /* 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: + { + /* may return AF_{INET|INET6} guessed from local_host */ + switch(addr_guess_family(sock->info.proto, sock->local_host)) { - 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, - &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; + 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: + { + 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, + &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 + } } - } /* bind to local address/port */ if (sock->bind_local) @@ -1382,27 +1384,32 @@ resolve_remote (struct link_socket *sock, 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)) { - af = addr_guess_family(sock->info.proto, sock->remote_host); - switch(af) { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_family = AF_INET; - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; - break; #ifdef USE_PF_INET6 - 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; + 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) { @@ -1445,27 +1452,30 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - switch(af) { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( - flags, - sock->remote_host, - retry, - &status, - signal_received); - break; #ifdef USE_PF_INET6 - case AF_INET6: - status = getaddr6 ( - flags, - sock->remote_host, - retry, - signal_received, - NULL, - &sock->info.lsa->remote.addr.in6); - break; + 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", @@ -1487,17 +1497,19 @@ resolve_remote (struct link_socket *sock, goto done; } } +#ifdef USE_PF_INET6 switch(af) { case AF_INET: +#endif sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); - break; #ifdef USE_PF_INET6 + break; case AF_INET6: sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); break; -#endif } +#endif } /* should we re-use previous active remote address? */ @@ -1783,9 +1795,9 @@ link_socket_init_phase2 (struct link_socket *sock, } else if (sock->info.proto == PROTO_TCPv4_CLIENT #ifdef USE_PF_INET6 - ||sock->info.proto == PROTO_TCPv6_CLIENT + ||sock->info.proto == PROTO_TCPv6_CLIENT #endif - ) + ) { #ifdef GENERAL_PROXY_SUPPORT @@ -2075,18 +2087,18 @@ link_socket_bad_incoming_addr (struct buffer *buf, struct gc_arena gc = gc_new (); 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)); + "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); } @@ -2112,7 +2124,7 @@ link_socket_current_remote (const struct link_socket_info *info) */ #if defined ( USE_PF_INET6 ) if(lsa->actual.dest.addr.sa.sa_family != AF_INET) - return 0; + return 0; #else ASSERT(lsa->actual.dest.addr.sa.sa_family == AF_INET); #endif @@ -2353,51 +2365,54 @@ print_sockaddr_ex (const struct openvpn_sockaddr *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_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) - { - if (separator) - buf_printf (&out, "%s", separator); - - buf_printf (&out, "%d", port); - } - } - 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; + switch(addr->addr.sa.sa_family) + { + case AF_INET: +#endif + { + 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_is_defined && (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: + { + 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); } @@ -2421,34 +2436,34 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, 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.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; + case AF_INET: + { + struct openvpn_sockaddr sa; + CLEAR (sa); + 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 @@ -2485,8 +2500,11 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv char name_buf[256]; char buf[128]; - switch(addr->addr.sa.sa_family) { +#ifdef USE_PF_INET6 + 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 @@ -2497,23 +2515,23 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv 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; + { + 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); + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); setenv_str (es, name_buf, buf); openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); break; + } #endif - } } void @@ -2891,46 +2909,48 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, mesg.msg_iov = &iov; mesg.msg_iovlen = 1; 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; - } + { + 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; - } + 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); } From 51afc8b8865fe09f76b81ae341e693a5b16199f2 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 15 Sep 2009 16:48:46 +0200 Subject: [PATCH 05/37] * support --disable-ipv6 build properly: - tests now are pass (and fail) properly for ipv6/4 builds * more GNU indenting --- init.c | 6 +++--- mroute.c | 2 +- multi.c | 21 ++++++++++---------- options.c | 44 +++++++++++++++++++++++++++++++++-------- socket.c | 59 +++++++++++++++++++++++++++++++------------------------ socket.h | 15 ++------------ 6 files changed, 86 insertions(+), 61 deletions(-) diff --git a/init.c b/init.c index e9cb0899..ee479cf9 100644 --- a/init.c +++ b/init.c @@ -3095,11 +3095,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* 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 #ifdef USE_PF_INET6 - if (c->options.ce.proto == PROTO_TCPv4_SERVER || c->options.ce.proto == PROTO_TCPv6_SERVER) -#else - if (c->options.ce.proto == PROTO_TCPv4_SERVER) + || c->options.ce.proto == PROTO_TCPv6_SERVER #endif + ) { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; diff --git a/mroute.c b/mroute.c index 7477a510..a2c66f3c 100644 --- a/mroute.c +++ b/mroute.c @@ -387,7 +387,7 @@ mroute_addr_print_ex (const struct mroute_addr *ma, } } } -#else /* old pre IPV6 1-line code: */ +#else /* old, pre USE_PF_INET6 code */ buf_printf (&out, "IPV6"); #endif break; diff --git a/multi.c b/multi.c index 0196be9e..df73cb9c 100644 --- a/multi.c +++ b/multi.c @@ -2681,16 +2681,17 @@ tunnel_server (struct context *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); - } + 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 } diff --git a/options.c b/options.c index ec219298..ea42f3cb 100644 --- a/options.c +++ b/options.c @@ -108,7 +108,7 @@ static const char usage_message[] = " 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" + " 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" @@ -1703,10 +1703,18 @@ options_postprocess_verify_ce (const struct options *options, const struct conne * Sanity check on TCP mode options */ - if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_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"); - if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_CLIENT) + 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"); /* @@ -1804,7 +1812,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); #endif - if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv6_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 @@ -1822,7 +1834,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); #endif - if ((ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER) + 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"); @@ -1837,11 +1853,19 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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 (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_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"); #if PORT_SHARE if ((options->port_share_host || options->port_share_port) && - (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER)) + (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)"); #endif if (!options->tls_server) @@ -1870,7 +1894,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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 (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER )) + 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"); 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."); diff --git a/socket.c b/socket.c index f3a893d0..01c18e9c 100644 --- a/socket.c +++ b/socket.c @@ -1316,10 +1316,12 @@ resolve_bind_local (struct link_socket *sock) /* resolve local address if undefined */ if (!addr_defined (&sock->info.lsa->local)) { +#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, @@ -1329,8 +1331,8 @@ resolve_bind_local (struct link_socket *sock) NULL) : htonl (INADDR_ANY)); sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port); - break; #ifdef USE_PF_INET6 + break; case AF_INET6: { int success; @@ -1360,8 +1362,8 @@ resolve_bind_local (struct link_socket *sock) sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); } break; -#endif } +#endif /* USE_PF_INET6 */ } /* bind to local address/port */ @@ -1756,7 +1758,7 @@ link_socket_init_phase2 (struct link_socket *sock, /* TCP client/server */ if (sock->info.proto == PROTO_TCPv4_SERVER #ifdef USE_PF_INET6 - ||sock->info.proto == PROTO_TCPv6_SERVER + ||sock->info.proto == PROTO_TCPv6_SERVER #endif ) { @@ -1795,7 +1797,7 @@ link_socket_init_phase2 (struct link_socket *sock, } else if (sock->info.proto == PROTO_TCPv4_CLIENT #ifdef USE_PF_INET6 - ||sock->info.proto == PROTO_TCPv6_CLIENT + ||sock->info.proto == PROTO_TCPv6_CLIENT #endif ) { @@ -2122,7 +2124,7 @@ link_socket_current_remote (const struct link_socket_info *info) * by now just ignore it * */ -#if defined ( USE_PF_INET6 ) +#ifdef USE_PF_INET6 if(lsa->actual.dest.addr.sa.sa_family != AF_INET) return 0; #else @@ -2435,17 +2437,19 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, #if ENABLE_IP_PKTINFO if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) { +#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_addr = act->pi.in4.ipi_spec_dst; buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); } - break; #ifdef USE_PF_INET6 + break; case AF_INET6: { struct sockaddr_in6 sin6; @@ -2462,8 +2466,8 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, } } break; -#endif } +#endif /* USE_PF_INET6 */ } #endif @@ -2663,33 +2667,36 @@ int addr_guess_family(int proto, const char *name) { sa_family_t ret; - if (proto) { - return proto_sa_family(proto); /* already stamped */ - } + if (proto) + { + return proto_sa_family(proto); /* already stamped */ + } #ifdef USE_PF_INET6 - else { - struct addrinfo hints , *ai; - int err; - memset(&hints, 0, sizeof hints); - hints.ai_flags=AI_NUMERICHOST; - err = getaddrinfo(name, NULL, &hints, &ai); - if ( 0 == err ) - { - ret=ai->ai_family; - freeaddrinfo(ai); - return ret; - } - } + else + { + struct addrinfo hints , *ai; + int err; + memset(&hints, 0, sizeof 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"; + switch (af) + { + case AF_INET: return "AF_INET"; case AF_INET6: return "AF_INET6"; - } + } return "AF_UNSPEC"; } diff --git a/socket.h b/socket.h index ba8cd6e6..718805a6 100644 --- a/socket.h +++ b/socket.h @@ -491,19 +491,6 @@ in_addr_t getaddr_multi (unsigned int flags, * Transport protocol naming and other details. */ -#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 @@ -514,10 +501,12 @@ enum proto_num { 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 }; From 97549c67678bb9b5196d4a87971e9fde6147cce0 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 15 Sep 2009 22:42:46 +0200 Subject: [PATCH 06/37] * important fix for tcp6 reconnection was incorrectly creating a PF_INET socket --- socket.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/socket.c b/socket.c index 01c18e9c..344c0dd2 100644 --- a/socket.c +++ b/socket.c @@ -1251,7 +1251,20 @@ socket_connect (socket_descriptor_t *sd, 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); From 387df51180cf9139abfbc33b141fd395a58633b5 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 17 Sep 2009 23:46:01 +0200 Subject: [PATCH 07/37] * added README.ipv6.txt --- README.ipv6.txt | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 README.ipv6.txt diff --git a/README.ipv6.txt b/README.ipv6.txt new file mode 100644 index 00000000..0d4c462f --- /dev/null +++ b/README.ipv6.txt @@ -0,0 +1,67 @@ +[ Last updated: 17-Sep-2009. ] +This README covers UDP/IPv6 v0.4.x ( --udp6 and --tcp6-xxxxxx ) support +for openvpn-2.1. + +Available under GPLv2 from + http://github.com/jjo/openvpn-ipv6 + +* Working: + - tcp6->tcp6; tested on GNU/Linux + - upd6->upd6; tested on GNU/Linux + - upd4->upd6 (ipv6 bound) + +* 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 --dev tun1 \ + --ifconfig 10.4.0.1 10.4.0.2 --verb 5 --secret key + + On june: + openvpn --proto udp6 --remote --dev tun1 \ + --ifconfig 10.4.0.2 10.4.0.1 --verb 5 --secret key + + Same for --proto tcp6-client, tcp6-server. + +* 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: + - 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 + +-- +JuanJo Ciarlante jjo () google () com +: : +. Linux IP Aliasing author . +. Modular algo (AES et all) support for FreeSWAN/OpenSWAN author . +:... plus other scattered free software bits in the wild ...: From 4d3df224e1210f732b84cf4273fb57993361d4ba Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 19 Sep 2009 18:33:40 +0200 Subject: [PATCH 08/37] * fixed win32 non-ipv6 build --- buffer.c | 6 +++++- buffer.h | 5 +++++ socket.c | 16 +++++++++------- socket.h | 3 ++- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/buffer.c b/buffer.c index c43cb470..f69ec709 100644 --- a/buffer.c +++ b/buffer.c @@ -214,8 +214,10 @@ buf_printf (struct buffer *buf, const char *format, ...) return ret; } -void buf_puts(struct buffer *buf, const char *str) +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) @@ -223,7 +225,9 @@ void buf_puts(struct buffer *buf, const char *str) 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; } diff --git a/buffer.h b/buffer.h index 3b24d09e..0a394a72 100644 --- a/buffer.h +++ b/buffer.h @@ -276,6 +276,11 @@ bool buf_printf (struct buffer *buf, const char *format, ...) #endif ; +/* + * 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 */ diff --git a/socket.c b/socket.c index 344c0dd2..3340314f 100644 --- a/socket.c +++ b/socket.c @@ -1173,7 +1173,7 @@ openvpn_connect (socket_descriptor_t sd, } } #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 @@ -2515,9 +2515,9 @@ void 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]; #ifdef USE_PF_INET6 + char buf[128]; switch(addr->addr.sa.sa_family) { case AF_INET: @@ -2582,7 +2582,7 @@ struct proto_names { const char *display_form; bool is_dgram; bool is_net; - sa_family_t proto_af; + unsigned short proto_af; }; /* Indexed by PROTO_x */ @@ -2629,7 +2629,7 @@ proto_is_tcp(int proto) return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; } -sa_family_t +unsigned short proto_sa_family(int proto) { if (proto < 0 || proto >= PROTO_N) @@ -2679,7 +2679,9 @@ proto2ascii_all (struct gc_arena *gc) int addr_guess_family(int proto, const char *name) { - sa_family_t ret; +#ifdef USE_PF_INET6 + unsigned short ret; +#endif if (proto) { return proto_sa_family(proto); /* already stamped */ @@ -3270,10 +3272,10 @@ socket_finalize (SOCKET s, { if (io->addrlen != sizeof (io->addr)) bad_address_length (io->addrlen, sizeof (io->addr)); - from->dest.addr.sa = io->addr; + from->dest.addr.in4 = io->addr; } else - CLEAR (from->dest.addr.sa); + CLEAR (from->dest.addr); } if (buf) diff --git a/socket.h b/socket.h index 718805a6..def8104e 100644 --- a/socket.h +++ b/socket.h @@ -591,6 +591,7 @@ addr_defined_ipi (const struct link_socket_actual *lsa) #else ASSERT(0); #endif + return false; } static inline bool @@ -702,7 +703,7 @@ addr_inet4or6(struct sockaddr *addr) int addr_guess_family(int proto, const char *name); static inline int -af_addr_size(sa_family_t af) +af_addr_size(unsigned short af) { #if defined(USE_PF_INET6) || defined (USE_PF_UNIX) switch(af) { From b7f203c8cfd2c0e412afd6f5ca0aa4eb62a031d2 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 19 Sep 2009 21:36:46 +0200 Subject: [PATCH 09/37] * ipv6 on win32 "milestone": 1st snapshot that passes all unittests --- socket.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++------ socket.h | 2 +- syshead.h | 7 ++++ win32.h | 5 ++- 4 files changed, 98 insertions(+), 11 deletions(-) diff --git a/socket.c b/socket.c index 3340314f..3024ea4e 100644 --- a/socket.c +++ b/socket.c @@ -2993,11 +2993,19 @@ socket_recv_queue (struct link_socket *sock, int maxsize) int status; /* reset buf to its initial state */ - if (sock->info.proto == PROTO_UDPv4) + if (sock->info.proto == PROTO_UDPv4 +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_UDPv6 +#endif + ) { sock->reads.buf = sock->reads.buf_init; } - else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) + else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER +#endif + ) { stream_buf_get_next (&sock->stream_buf, &sock->reads.buf); } @@ -3017,10 +3025,19 @@ socket_recv_queue (struct link_socket *sock, int maxsize) ASSERT (ResetEvent (sock->reads.overlapped.hEvent)); sock->reads.flags = 0; - if (sock->info.proto == PROTO_UDPv4) + if (sock->info.proto == PROTO_UDPv4 +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_UDPv6 +#endif + ) { 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, @@ -3032,7 +3049,12 @@ socket_recv_queue (struct link_socket *sock, int maxsize) &sock->reads.overlapped, NULL); } - else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) + else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER +#endif + ) + { sock->reads.addr_defined = false; status = WSARecv( @@ -3052,8 +3074,14 @@ socket_recv_queue (struct link_socket *sock, int maxsize) 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; @@ -3112,12 +3140,26 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li ASSERT (ResetEvent (sock->writes.overlapped.hEvent)); sock->writes.flags = 0; - if (sock->info.proto == PROTO_UDPv4) + if (sock->info.proto == PROTO_UDPv4 +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_UDPv6 +#endif + ) { /* set destination address for UDP writes */ sock->writes.addr_defined = true; - sock->writes.addr = to->dest.addr.in4; - 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, @@ -3130,7 +3172,11 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li &sock->writes.overlapped, NULL); } - else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER) + else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER +#ifdef USE_PF_INET6 + || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER +#endif + ) { /* destination address for TCP writes was established on connection initiation */ sock->writes.addr_defined = false; @@ -3269,11 +3315,42 @@ socket_finalize (SOCKET s, 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.addr.in4 = io->addr; } +#endif else CLEAR (from->dest.addr); } diff --git a/socket.h b/socket.h index def8104e..092d448f 100644 --- a/socket.h +++ b/socket.h @@ -717,7 +717,7 @@ af_addr_size(unsigned short af) default: #if 0 /* could be called from socket_do_accept() with empty addr */ - msg (M_ERR, "Bad address family: %d\n", addr->sa_family); + msg (M_ERR, "Bad address family: %d\n", af); ASSERT(0); #endif return 0; diff --git a/syshead.h b/syshead.h index 30ff5561..d5895310 100644 --- a/syshead.h +++ b/syshead.h @@ -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 #include +/* The following two headers are needed of USE_PF_INET6 */ +#include +#include #endif #ifdef HAVE_SYS_MMAN_H diff --git a/win32.h b/win32.h index fcc3062d..6184206e 100644 --- a/win32.h +++ b/win32.h @@ -195,7 +195,10 @@ struct overlapped_io { 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; From 485540cac415423266a6a2fc3b69bcdbe1e62916 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 19 Sep 2009 21:58:15 +0200 Subject: [PATCH 10/37] * document ipv6 milestone status --- README.ipv6.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.ipv6.txt b/README.ipv6.txt index 0d4c462f..67be89bd 100644 --- a/README.ipv6.txt +++ b/README.ipv6.txt @@ -6,9 +6,9 @@ Available under GPLv2 from http://github.com/jjo/openvpn-ipv6 * Working: - - tcp6->tcp6; tested on GNU/Linux - - upd6->upd6; tested on GNU/Linux - - upd4->upd6 (ipv6 bound) + - upd6,tcp6: tested on GNU/Linux, win32 + - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): tested on GNU/Linux, win32 + (gives a warning on local!=remote proto matching) * Setup: ./configure --enable-ipv6 (by default) @@ -55,6 +55,9 @@ Available under GPLv2 from proto_is_udp(), proto_is_dgram(), proto_is_net() * TODO: + - Should not use random for listening in IPv6 "by name", as eg + ip6-localhost could return any ifindex, or "randomly" behave as + if it were IPV6_V6ONLY (caught this in my unittesting) - 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 From a1bea685f06cd5eddf63ddbf9cc3495805395c11 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 19 Sep 2009 22:07:25 +0200 Subject: [PATCH 11/37] * doc update w/unittests results --- README.ipv6.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.ipv6.txt b/README.ipv6.txt index 67be89bd..3a894f02 100644 --- a/README.ipv6.txt +++ b/README.ipv6.txt @@ -6,9 +6,15 @@ Available under GPLv2 from http://github.com/jjo/openvpn-ipv6 * Working: - - upd6,tcp6: tested on GNU/Linux, win32 - - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): tested on GNU/Linux, win32 + OK: + - upd6,tcp6: GNU/Linux, win32 + - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux (gives a warning on local!=remote proto matching) + NOT: + - tcp4->tcp6 (ipv4/6 mapped): win32 + fails w/connection refused + + * Setup: ./configure --enable-ipv6 (by default) @@ -58,6 +64,8 @@ Available under GPLv2 from - Should not use random for listening in IPv6 "by name", as eg ip6-localhost could return any ifindex, or "randomly" behave as if it were IPV6_V6ONLY (caught this in my unittesting) + - win32: find out about mapped addresses, as I can't make it work + with bound at ::1 and connect to 127.0.0.1 - 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 From e47877099ebe7d98eb74c2b3efff902a77d0253f Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 24 Sep 2009 19:59:32 +0200 Subject: [PATCH 12/37] * make possible to x-compile openvpn/win32 in Linux --- install-win32/makeopenvpn | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) mode change 100644 => 100755 install-win32/makeopenvpn diff --git a/install-win32/makeopenvpn b/install-win32/makeopenvpn old mode 100644 new mode 100755 index c1a805dd..0f06a016 --- a/install-win32/makeopenvpn +++ b/install-win32/makeopenvpn @@ -5,21 +5,41 @@ H=`pwd` # get version.nsi definitions . autodefs/defs.sh -if gcc --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ -d "$PKCS11_HELPER_DIR" ]; then +[ -z "$CC" ] && CC=gcc +LZO_INC_DIR=$H/$LZO_DIR/include +LZO_LIB_DIR=$H/$LZO_DIR +PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/usr/local/include +PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/usr/local/lib +XAUTOCONF="" + +case "`uname -o 2>/dev/null`" in + *inux) + # cross-compiling, make dude's life easier + XAUTOCONF="--host=i586-mingw32msvc --build=i386-linux" + export CC=i586-mingw32msvc-gcc + export CXXCPP=i586-mingw32msvc-cpp + export CXX=i586-mingw32msvc-g++ + # when cross-compiling from src, you'll typically get: + LZO_LIB_DIR=$H/$LZO_DIR/src/.libs + PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/include/pkcs11-helper-1.0/ + PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/lib/.libs/ + ;; +esac +if $CC --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ -d "$PKCS11_HELPER_DIR" ]; then # build OpenVPN binary if ! [ -f Makefile ]; then autoreconf -i -v \ - && ./configure \ + && ./configure $XAUTOCONF \ --enable-strict \ --prefix=$H/windest \ MAN2HTML=true \ --with-ssl-headers=$H/$OPENSSL_DIR/include \ --with-ssl-lib=$H/$OPENSSL_DIR/out \ - --with-lzo-headers=$H/$LZO_DIR/include \ - --with-lzo-lib=$H/$LZO_DIR \ - --with-pkcs11-helper-headers=$H/$PKCS11_HELPER_DIR/usr/local/include \ - --with-pkcs11-helper-lib=$H/$PKCS11_HELPER_DIR/usr/local/lib + --with-lzo-headers=$LZO_INC_DIR \ + --with-lzo-lib=$LZO_LIB_DIR \ + --with-pkcs11-helper-headers=$PKCS11_INC_DIR \ + --with-pkcs11-helper-lib=$PKCS11_LIB_DIR fi make -j $MAKE_JOBS && make install From 6d1b80bdeb5e0df3dee6a8bc05d7e3f622371c1c Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 24 Sep 2009 20:09:55 +0200 Subject: [PATCH 13/37] * correctly setup hints.ai_socktype for getaddrinfo(), althought sorta hacky, see TODO.ipv6. --- README.ipv6.txt | 10 +--------- TODO.ipv6 | 11 +++++++++++ socket.c | 16 ++++++++++------ socket.h | 6 ++++++ 4 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 TODO.ipv6 diff --git a/README.ipv6.txt b/README.ipv6.txt index 3a894f02..f9b61713 100644 --- a/README.ipv6.txt +++ b/README.ipv6.txt @@ -60,15 +60,7 @@ Available under GPLv2 from addr_copy(), addr_zero(), ...etc proto_is_udp(), proto_is_dgram(), proto_is_net() -* TODO: - - Should not use random for listening in IPv6 "by name", as eg - ip6-localhost could return any ifindex, or "randomly" behave as - if it were IPV6_V6ONLY (caught this in my unittesting) - - win32: find out about mapped addresses, as I can't make it work - with bound at ::1 and connect to 127.0.0.1 - - 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 +* TODO: See TODO.ipv6 -- JuanJo Ciarlante jjo () google () com diff --git a/TODO.ipv6 b/TODO.ipv6 new file mode 100644 index 00000000..c19e42cc --- /dev/null +++ b/TODO.ipv6 @@ -0,0 +1,11 @@ +* 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 +* the getaddr()/getaddr6() interface is not prepared for handling socktype + "tagging", currently I abuse the sockflags bits for getting the ai_socktype + downstream. +* win32: find out about mapped addresses, as I can't make it work + with bound at ::1 and connect to 127.0.0.1 +* 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 diff --git a/socket.c b/socket.c index 3024ea4e..96d26026 100644 --- a/socket.c +++ b/socket.c @@ -52,13 +52,12 @@ const int proto_overhead[] = { /* indexed by PROTO_x */ * Convert sockflags/getaddr_flags into getaddr_flags */ static unsigned int -sf2gaf(const unsigned int getaddr_flags, +sf2gaf(unsigned int getaddr_flags, const unsigned int sockflags) { - if (sockflags & SF_HOST_RANDOMIZE) - return getaddr_flags | GETADDR_RANDOMIZE; - else - return getaddr_flags; + getaddr_flags |= (sockflags & SF_GETADDRINFO_DGRAM) ? GETADDR_DGRAM : 0; + getaddr_flags |= (sockflags & SF_HOST_RANDOMIZE) ? GETADDR_RANDOMIZE : 0; + return getaddr_flags; } /* @@ -375,7 +374,11 @@ getaddr6 (unsigned int flags, { /* 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; @@ -891,6 +894,7 @@ create_socket (struct link_socket *sock) 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) @@ -911,6 +915,7 @@ create_socket (struct link_socket *sock) else if (sock->info.proto == PROTO_UDPv6) { sock->sd = create_socket_udp6 (sock->sockflags); + sock->sockflags |= SF_GETADDRINFO_DGRAM; } #endif else @@ -1492,7 +1497,6 @@ resolve_remote (struct link_socket *sock, } #endif - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", flags, phase, diff --git a/socket.h b/socket.h index 092d448f..f864ab19 100644 --- a/socket.h +++ b/socket.h @@ -210,6 +210,7 @@ struct link_socket # 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 */ @@ -474,6 +475,11 @@ struct resolve_list { #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, From d7627b1a5197a8634e011bb100849c45a612602d Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Fri, 25 Sep 2009 23:20:41 +0200 Subject: [PATCH 14/37] * renamed README.ipv6{.txt,} --- README.ipv6.txt => README.ipv6 | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.ipv6.txt => README.ipv6 (100%) diff --git a/README.ipv6.txt b/README.ipv6 similarity index 100% rename from README.ipv6.txt rename to README.ipv6 From bf006408d08253f1b86c491e44e75ef8ca2e3e9b Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 28 Sep 2009 12:16:26 +0200 Subject: [PATCH 15/37] * updated {README,TODO}.ipv6 from feedback at openvpn-devel mlist --- README.ipv6 | 22 +++++++++++++--------- TODO.ipv6 | 30 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/README.ipv6 b/README.ipv6 index f9b61713..612c23c9 100644 --- a/README.ipv6 +++ b/README.ipv6 @@ -5,16 +5,20 @@ for openvpn-2.1. Available under GPLv2 from http://github.com/jjo/openvpn-ipv6 -* Working: - OK: - - upd6,tcp6: GNU/Linux, win32 - - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux - (gives a warning on local!=remote proto matching) - NOT: - - tcp4->tcp6 (ipv4/6 mapped): win32 - fails w/connection refused - +, also thanks to Bernhard Schmidt, you'll find deb packages +for latest Ubuntu distros at: + https://launchpad.net/~berni/+archive/ipv6/+packages +* Status: + o OK: + - upd6,tcp6: GNU/Linux, win32 + - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux + (gives a warning on local!=remote proto matching) + o NOT: + - tcp4->tcp6 (ipv4/6 mapped): win32 + fails w/connection refused + o NOT tested: + - mgmt console * Setup: ./configure --enable-ipv6 (by default) diff --git a/TODO.ipv6 b/TODO.ipv6 index c19e42cc..55602f9d 100644 --- a/TODO.ipv6 +++ b/TODO.ipv6 @@ -1,11 +1,19 @@ -* 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 -* the getaddr()/getaddr6() interface is not prepared for handling socktype - "tagging", currently I abuse the sockflags bits for getting the ai_socktype - downstream. -* win32: find out about mapped addresses, as I can't make it work - with bound at ::1 and connect to 127.0.0.1 -* 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 +* 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 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 + +* 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 + From 2d7da344969a83d7b0e1dfadeddae1271f07fe4c Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 28 Sep 2009 13:47:16 +0200 Subject: [PATCH 16/37] * init.c: document the ENABLE_MANAGEMENT place to work on --- TODO.ipv6 | 3 +++ init.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/TODO.ipv6 b/TODO.ipv6 index 55602f9d..edeb5507 100644 --- a/TODO.ipv6 +++ b/TODO.ipv6 @@ -17,3 +17,6 @@ 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 diff --git a/init.c b/init.c index ee479cf9..4cab0b3d 100644 --- a/init.c +++ b/init.c @@ -1150,6 +1150,8 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) const char *detail = "SUCCESS"; if (c->c1.tuntap) tun_local = c->c1.tuntap->local; + /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr + * to a meaningless ipv4 address */ tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr); if (flags & ISC_ERRORS) detail = "ERROR"; From ead3784086e76add44d53b0ffa87e3a8bd3fa8c7 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 28 Sep 2009 19:51:54 +0200 Subject: [PATCH 17/37] * init.c: small in-doc tweaks --- init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/init.c b/init.c index 4cab0b3d..ed508b82 100644 --- a/init.c +++ b/init.c @@ -1151,7 +1151,10 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) if (c->c1.tuntap) tun_local = c->c1.tuntap->local; /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr - * to a meaningless ipv4 address */ + * 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"; From aa8e9576bbd2ecd094276521ad9cf88227a119c9 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 1 Oct 2009 00:15:12 +0200 Subject: [PATCH 18/37] * fix multi-tcp crash (corrected assertion) --- mtcp.c | 6 +++++- socket.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mtcp.c b/mtcp.c index f8cc50ff..ade2cfb1 100644 --- a/mtcp.c +++ b/mtcp.c @@ -150,7 +150,11 @@ multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance 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); + 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"); diff --git a/socket.c b/socket.c index 96d26026..2bb7141a 100644 --- a/socket.c +++ b/socket.c @@ -1645,7 +1645,11 @@ link_socket_init_phase1 (struct link_socket *sock, 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; } From e293510f9bb878faabb244f03ef4af97ddc67aad Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 5 Oct 2009 00:18:34 +0200 Subject: [PATCH 19/37] * TODO.ipv6 update --- TODO.ipv6 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.ipv6 b/TODO.ipv6 index edeb5507..dbf539ef 100644 --- a/TODO.ipv6 +++ b/TODO.ipv6 @@ -13,6 +13,10 @@ 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 From fc9a44e24299386b26f610a204656e30885c1ab5 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 5 Oct 2009 12:24:20 +0200 Subject: [PATCH 20/37] * socket.c: better buf logic in print_sockaddr_ex --- socket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/socket.c b/socket.c index 2bb7141a..943cb582 100644 --- a/socket.c +++ b/socket.c @@ -2382,7 +2382,7 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, const unsigned int flags, struct gc_arena *gc) { - struct buffer out; + struct buffer out = alloc_buf_gc (128, gc); bool addr_is_defined; if (!addr) { return "[NULL]"; @@ -2395,7 +2395,6 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, #endif { 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]")); @@ -2416,7 +2415,6 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, { 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) { @@ -2434,6 +2432,8 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, } } break; + default: + ASSERT(0); } #endif return BSTR (&out); From 4af2d42d85e619e508645682bef3904f5d6e39af Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 5 Oct 2009 14:44:20 +0200 Subject: [PATCH 21/37] * fixed segfault for undef address family in print_sockaddr_ex (thanks Marcel!) --- socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/socket.c b/socket.c index 943cb582..52b7b688 100644 --- a/socket.c +++ b/socket.c @@ -2384,10 +2384,10 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, { struct buffer out = alloc_buf_gc (128, gc); bool addr_is_defined; - if (!addr) { - return "[NULL]"; + addr_is_defined = addr_defined (addr); + if (!addr_is_defined) { + return "[undef]"; } - addr_is_defined = addr_defined (addr); #ifdef USE_PF_INET6 switch(addr->addr.sa.sa_family) { @@ -2414,7 +2414,7 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, case AF_INET6: { const int port= ntohs (addr->addr.in6.sin6_port); - char buf[INET6_ADDRSTRLEN] = "[undef]"; + char buf[INET6_ADDRSTRLEN] = ""; buf_puts (&out, "[AF_INET6]"); if (addr_is_defined) { From 51b3ca62973b9c795c51c43ac37603e78a3c7c60 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 12 Oct 2009 11:31:33 +0200 Subject: [PATCH 22/37] * doc updates --- README.ipv6 | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/README.ipv6 b/README.ipv6 index 612c23c9..9702a26e 100644 --- a/README.ipv6 +++ b/README.ipv6 @@ -1,13 +1,18 @@ -[ Last updated: 17-Sep-2009. ] -This README covers UDP/IPv6 v0.4.x ( --udp6 and --tcp6-xxxxxx ) support -for openvpn-2.1. +[ Last updated: 11-Oct-2009. ] -Available under GPLv2 from - http://github.com/jjo/openvpn-ipv6 +OpenVPN-2.1 over UDP6/TCP6 README for v0.4.x patch releases: +( --udp6 and --tcp6-{client,server} ) -, also thanks to Bernhard Schmidt, you'll find deb packages -for latest Ubuntu distros at: - https://launchpad.net/~berni/+archive/ipv6/+packages +* 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 * Status: o OK: @@ -15,12 +20,11 @@ for latest Ubuntu distros at: - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux (gives a warning on local!=remote proto matching) o NOT: - - tcp4->tcp6 (ipv4/6 mapped): win32 - fails w/connection refused + - win32: tcp4->tcp6 (ipv4/6 mapped) fails w/connection refused o NOT tested: - mgmt console -* Setup: +* Build setup: ./configure --enable-ipv6 (by default) * Usage: @@ -34,11 +38,11 @@ for latest Ubuntu distros at: On june: openvpn --proto udp6 --remote --dev tun1 \ --ifconfig 10.4.0.2 10.4.0.1 --verb 5 --secret key - + Same for --proto tcp6-client, tcp6-server. * Main code changes summary: - - socket.h: New struct openvpn_sockaddr type that holds sockaddrs and pktinfo, + - 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 { @@ -48,18 +52,18 @@ for latest Ubuntu distros at: 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 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() @@ -67,8 +71,9 @@ for latest Ubuntu distros at: * TODO: See TODO.ipv6 -- -JuanJo Ciarlante jjo () google () com +JuanJo Ciarlante jjo () google () com ............................ : : . Linux IP Aliasing author . . Modular algo (AES et all) support for FreeSWAN/OpenSWAN author . -:... plus other scattered free software bits in the wild ...: +. OpenVPN over IPv6 support . +:...... plus other scattered free software bits in the wild ...: From ebce9fba41421c948e1399bfe29bfa028d936076 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 20 Oct 2009 22:38:26 +0200 Subject: [PATCH 23/37] * openbsd: no IFF_MULTICAST, #ifdef around it --- tun.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tun.c b/tun.c index 59e87dc7..f8ebbb55 100644 --- a/tun.c +++ b/tun.c @@ -1697,7 +1697,9 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 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", From 1ad6fc2976c6e5eedb248769e4b1f48e33c75346 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 20 Oct 2009 22:38:50 +0200 Subject: [PATCH 24/37] * no new funcionality, just small cleanups: - cmdline options help: add tcp6/udp6 missing messages - win32: expand usage of proto_is_udp(), proto_is_tcp() - replace some memset(&obj, 0, sizeof obj) by openvpn's CLEAR(obj) --- TODO.ipv6 | 4 ++++ mroute.c | 2 +- options.c | 30 +++++++++++++++++++++++++----- socket.c | 47 +++++++++++------------------------------------ 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/TODO.ipv6 b/TODO.ipv6 index dbf539ef..565cbf62 100644 --- a/TODO.ipv6 +++ b/TODO.ipv6 @@ -1,3 +1,5 @@ +[ Last updated: 20-Oct-2009. ] + * All platforms: o mgmt console: as currently passes straight in_addr_t bits around @@ -5,6 +7,8 @@ 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. diff --git a/mroute.c b/mroute.c index a2c66f3c..56e01a2f 100644 --- a/mroute.c +++ b/mroute.c @@ -365,7 +365,7 @@ mroute_addr_print_ex (const struct mroute_addr *ma, struct sockaddr_in6 sin6; int port; char buf6[INET6_ADDRSTRLEN] = ""; - memset(&sin6, 0, sizeof sin6); + CLEAR(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))) diff --git a/options.c b/options.c index ea42f3cb..83017b81 100644 --- a/options.c +++ b/options.c @@ -1708,14 +1708,22 @@ options_postprocess_verify_ce (const struct options *options, const struct conne && ce->proto != PROTO_TCPv6_CLIENT #endif ) - msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client"); + 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"); + 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 @@ -1858,7 +1866,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne || ce->proto == PROTO_TCPv6_SERVER #endif )) - msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); + 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 @@ -1866,7 +1878,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne && ce->proto != PROTO_TCPv6_SERVER #endif )) - msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)"); + 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"); @@ -1899,7 +1915,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne || ce->proto == PROTO_TCPv6_SERVER #endif )) - msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"); + 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) diff --git a/socket.c b/socket.c index 52b7b688..bade47e1 100644 --- a/socket.c +++ b/socket.c @@ -2146,10 +2146,10 @@ link_socket_current_remote (const struct link_socket_info *info) * */ #ifdef USE_PF_INET6 - if(lsa->actual.dest.addr.sa.sa_family != AF_INET) + if (lsa->actual.dest.addr.sa.sa_family != AF_INET) return 0; #else - ASSERT(lsa->actual.dest.addr.sa.sa_family == AF_INET); + ASSERT (lsa->actual.dest.addr.sa.sa_family == AF_INET); #endif if (link_socket_actual_defined (&lsa->actual)) @@ -2475,7 +2475,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, { struct sockaddr_in6 sin6; char buf[INET6_ADDRSTRLEN] = "[undef]"; - memset(&sin6, 0, sizeof sin6); + CLEAR(sin6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = act->pi.in6.ipi6_addr; { @@ -2699,8 +2699,8 @@ addr_guess_family(int proto, const char *name) { struct addrinfo hints , *ai; int err; - memset(&hints, 0, sizeof hints); - hints.ai_flags=AI_NUMERICHOST; + CLEAR(hints); + hints.ai_flags = AI_NUMERICHOST; err = getaddrinfo(name, NULL, &hints, &ai); if ( 0 == err ) { @@ -3001,19 +3001,11 @@ socket_recv_queue (struct link_socket *sock, int maxsize) int status; /* reset buf to its initial state */ - if (sock->info.proto == PROTO_UDPv4 -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_UDPv6 -#endif - ) + 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 -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER -#endif - ) + else if (proto_is_tcp(sock->info.proto)) { stream_buf_get_next (&sock->stream_buf, &sock->reads.buf); } @@ -3033,11 +3025,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize) ASSERT (ResetEvent (sock->reads.overlapped.hEvent)); sock->reads.flags = 0; - if (sock->info.proto == PROTO_UDPv4 -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_UDPv6 -#endif - ) + if (proto_is_udp(sock->info.proto)) { sock->reads.addr_defined = true; #ifdef USE_PF_INET6 @@ -3057,12 +3045,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize) &sock->reads.overlapped, NULL); } - else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER -#endif - ) - + else if (proto_is_tcp(sock->info.proto)) { sock->reads.addr_defined = false; status = WSARecv( @@ -3148,11 +3131,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li ASSERT (ResetEvent (sock->writes.overlapped.hEvent)); sock->writes.flags = 0; - if (sock->info.proto == PROTO_UDPv4 -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_UDPv6 -#endif - ) + if (proto_is_udp(sock->info.proto)) { /* set destination address for UDP writes */ sock->writes.addr_defined = true; @@ -3180,11 +3159,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li &sock->writes.overlapped, NULL); } - else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER -#ifdef USE_PF_INET6 - || sock->info.proto == PROTO_TCPv6_CLIENT || sock->info.proto == PROTO_TCPv6_SERVER -#endif - ) + else if (proto_is_tcp(sock->info.proto)) { /* destination address for TCP writes was established on connection initiation */ sock->writes.addr_defined = false; From efa85c8b086121dc5df0e07b110751077e3d1ec4 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 10 Nov 2009 23:46:46 +0100 Subject: [PATCH 25/37] * (prototype) fix for supporting "redirect-gateway" for tunneled ipv4 over ipv6 endpoints --- route.c | 18 +++++++++++------- socket.c | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/route.c b/route.c index b5092fe3..f3ed974c 100644 --- a/route.c +++ b/route.c @@ -581,13 +581,17 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u 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; + if (rl->spec.remote_host != 0xffffffff) { + add_route3 (rl->spec.remote_host, + ~0, + rl->spec.net_gateway, + tt, + flags, + es); + rl->did_local = true; + } else { + dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled"); + } } /* route DHCP/DNS server traffic through original default gateway */ diff --git a/socket.c b/socket.c index bade47e1..2d46d3f3 100644 --- a/socket.c +++ b/socket.c @@ -2147,7 +2147,7 @@ link_socket_current_remote (const struct link_socket_info *info) */ #ifdef USE_PF_INET6 if (lsa->actual.dest.addr.sa.sa_family != AF_INET) - return 0; + return 0xffffffff; #else ASSERT (lsa->actual.dest.addr.sa.sa_family == AF_INET); #endif From 9d4c64b584173789780431e5fd5acf977cf72e9d Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Wed, 11 Nov 2009 15:35:31 +0100 Subject: [PATCH 26/37] * polished redirect-gateway (ipv4 on ipv6 endpoints) support --- route.c | 2 +- socket.c | 2 +- socket.h | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/route.c b/route.c index f3ed974c..cf103340 100644 --- a/route.c +++ b/route.c @@ -581,7 +581,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u if (!local) { /* route remote host to original default gateway */ - if (rl->spec.remote_host != 0xffffffff) { + if (rl->spec.remote_host != IPV4_INVALID_ADDR) { add_route3 (rl->spec.remote_host, ~0, rl->spec.net_gateway, diff --git a/socket.c b/socket.c index 2d46d3f3..72da7927 100644 --- a/socket.c +++ b/socket.c @@ -2147,7 +2147,7 @@ link_socket_current_remote (const struct link_socket_info *info) */ #ifdef USE_PF_INET6 if (lsa->actual.dest.addr.sa.sa_family != AF_INET) - return 0xffffffff; + return IPV4_INVALID_ADDR; #else ASSERT (lsa->actual.dest.addr.sa.sa_family == AF_INET); #endif diff --git a/socket.h b/socket.h index f864ab19..5f1e800a 100644 --- a/socket.h +++ b/socket.h @@ -383,6 +383,12 @@ void setenv_link_socket_actual (struct env_set *es, 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, From d4b9b74dff705d0bd2fefcd30ae99ec1c162f9e3 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Wed, 11 Nov 2009 17:25:09 +0100 Subject: [PATCH 27/37] * updated doc --- README.ipv6 | 4 ++-- TODO.ipv6 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.ipv6 b/README.ipv6 index 9702a26e..8c8b3b4f 100644 --- a/README.ipv6 +++ b/README.ipv6 @@ -1,4 +1,4 @@ -[ Last updated: 11-Oct-2009. ] +[ Last updated: 11-Nov-2009. ] OpenVPN-2.1 over UDP6/TCP6 README for v0.4.x patch releases: ( --udp6 and --tcp6-{client,server} ) @@ -16,7 +16,7 @@ OpenVPN-2.1 over UDP6/TCP6 README for v0.4.x patch releases: * Status: o OK: - - upd6,tcp6: GNU/Linux, win32 + - upd6,tcp6: GNU/Linux, win32, openbsd-4.6 - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux (gives a warning on local!=remote proto matching) o NOT: diff --git a/TODO.ipv6 b/TODO.ipv6 index 565cbf62..966af2d3 100644 --- a/TODO.ipv6 +++ b/TODO.ipv6 @@ -1,4 +1,4 @@ -[ Last updated: 20-Oct-2009. ] +[ Last updated: 11-Nov-2009. ] * All platforms: o mgmt console: as currently passes straight in_addr_t bits around From 6caf7f3da06b8a75bf3451f49378f2f8eb8c53be Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 12 Nov 2009 11:54:13 +0100 Subject: [PATCH 28/37] * fix --disable-ipv6 build --- route.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/route.c b/route.c index cf103340..76a4b106 100644 --- a/route.c +++ b/route.c @@ -581,7 +581,11 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u if (!local) { /* route remote host to original default gateway */ +#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, @@ -589,9 +593,11 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u 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 */ From 4c25c5e3633faaa04bce79b4c20f86445c2515e1 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 17 Nov 2009 20:00:05 +0100 Subject: [PATCH 29/37] * doc updates --- README.ipv6 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.ipv6 b/README.ipv6 index 8c8b3b4f..5d17b918 100644 --- a/README.ipv6 +++ b/README.ipv6 @@ -1,6 +1,6 @@ -[ Last updated: 11-Nov-2009. ] +[ Last updated: 16-Nov-2009. ] -OpenVPN-2.1 over UDP6/TCP6 README for v0.4.x patch releases: +OpenVPN-2.1 over UDP6/TCP6 README for ipv6-0.4.x patch releases: ( --udp6 and --tcp6-{client,server} ) * Availability @@ -13,6 +13,8 @@ OpenVPN-2.1 over UDP6/TCP6 README for v0.4.x patch releases: - 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: From 3ac2ac72e5fb286c9d8663a346075cae157f1762 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 28 Nov 2009 09:19:14 -0800 Subject: [PATCH 30/37] * rebased to v2.1.1 release * document {un,}trusted_ip6 in manpage --- openvpn.8 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openvpn.8 b/openvpn.8 index 182e5d52..2b60c12f 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -5402,13 +5402,16 @@ or 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 @@ -5420,7 +5423,7 @@ and 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 @@ -5432,6 +5435,9 @@ Set prior to execution of and .B \-\-auth-user-pass-verify scripts. +If using ipv6 endpoints (udp6, tcp6), +.B untrusted_ip6 +will be set instead. .\"********************************************************* .TP .B untrusted_port From a69846411ae68dbd03b7552e33a63622bfbfc18b Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sat, 20 Feb 2010 20:28:40 +0100 Subject: [PATCH 31/37] * undo mroute.c changes related to ipv6 payload, nothing to do w/ipv6 transport afterall. --- mroute.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/mroute.c b/mroute.c index 56e01a2f..a0f8e4e3 100644 --- a/mroute.c +++ b/mroute.c @@ -359,37 +359,7 @@ mroute_addr_print_ex (const struct mroute_addr *ma, } break; case MR_ADDR_IPV6: -#ifdef USE_PF_INET6 - { - struct buffer buf; - struct sockaddr_in6 sin6; - int port; - char buf6[INET6_ADDRSTRLEN] = ""; - CLEAR(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 USE_PF_INET6 code */ buf_printf (&out, "IPV6"); -#endif break; default: buf_printf (&out, "UNKNOWN"); From 830038fce4a30f317eb265079f91d9555981ad76 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Thu, 23 Sep 2010 01:15:35 +0200 Subject: [PATCH 32/37] * fix --multihome for ipv4: cmsg_len must compare against in_pktinfo size, not the full 4+6 union, also use saner variable names. --- socket.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/socket.c b/socket.c index 72da7927..577ef93b 100644 --- a/socket.c +++ b/socket.c @@ -2466,6 +2466,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, { struct openvpn_sockaddr sa; CLEAR (sa); + sa.addr.in4.sin_family = AF_INET; sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); } @@ -2807,7 +2808,7 @@ link_socket_read_tcp (struct link_socket *sock, struct openvpn_in4_pktinfo { struct cmsghdr cmsghdr; - struct in_pktinfo pi; + struct in_pktinfo pi4; }; #ifdef USE_PF_INET6 struct openvpn_in6_pktinfo @@ -2818,9 +2819,9 @@ struct openvpn_in6_pktinfo #endif union openvpn_pktinfo { - struct openvpn_in4_pktinfo cmsgpi; + struct openvpn_in4_pktinfo msgpi4; #ifdef USE_PF_INET6 - struct openvpn_in6_pktinfo cmsgpi6; + struct openvpn_in6_pktinfo msgpi6; #endif }; #pragma pack() @@ -2843,7 +2844,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, 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) { @@ -2854,7 +2855,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, && CMSG_NXTHDR (&mesg, cmsg) == NULL && cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO - && cmsg->cmsg_len >= sizeof (opi)) + && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo)) { struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; @@ -2942,15 +2943,15 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, { case AF_INET: { - struct openvpn_in4_pktinfo opi; + struct openvpn_in4_pktinfo msgpi4; 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_control = &msgpi4; + mesg.msg_controllen = sizeof msgpi4; mesg.msg_flags = 0; cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (opi); + cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); @@ -2962,15 +2963,15 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, #ifdef USE_PF_INET6 case AF_INET6: { - struct openvpn_in6_pktinfo opi6; + 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 = &opi6; - mesg.msg_controllen = sizeof (opi6); + mesg.msg_control = &msgpi6; + mesg.msg_controllen = sizeof msgpi6; mesg.msg_flags = 0; cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (opi6); + 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); From 5d6dbb03776de4d38f45e429ef674313a2bda8cc Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sun, 6 Feb 2011 09:52:46 +0100 Subject: [PATCH 33/37] * fix --multihome for ipv6: IPV6_RECVPKTINFO - setsockopt IPV6_RECVPKTINFO (not IPV6_PKTINFO!) - do check for setsockopt() failures - append % in INFO msg --- socket.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/socket.c b/socket.c index 577ef93b..cfec7578 100644 --- a/socket.c +++ b/socket.c @@ -843,7 +843,9 @@ create_socket_udp (const unsigned int flags) else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; - setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad)); + if (setsockopt (sd, SOL_IP, IP_PKTINFO, + (void*)&pad, sizeof(pad)) < 0) + msg(M_SOCKERR, "UDP: failed setsockopt for IP_PKTINFO"); } #endif return sd; @@ -861,7 +863,9 @@ create_socket_udp6 (const unsigned int flags) else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; - setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, (void*)&pad, sizeof(pad)); + if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void*)&pad, sizeof(pad)) < 0) + msg(M_SOCKERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); } #endif return sd; @@ -2453,6 +2457,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, { 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 @@ -2468,7 +2473,10 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, CLEAR (sa); sa.addr.in4.sin_family = AF_INET; sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; - buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc)); + if_indextoname(act->pi.in4.ipi_ifindex, ifname); + buf_printf (&out, " (via %s%%%s)", + print_sockaddr_ex (&sa, separator, 0, gc), + ifname); } #ifdef USE_PF_INET6 break; @@ -2479,13 +2487,12 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, CLEAR(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])"); - } + 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; } From c47fd4b35cc99130c4177fd6b19ed2e0b4776756 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Mon, 21 Mar 2011 09:21:39 +0100 Subject: [PATCH 34/37] * ipv6-0.4.14: fix xinetd usage: - closes http://bugs.debian.org/574164 - also needed for --disable-ipv6 builds - supports IPv6 from xinetd --- socket.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/socket.c b/socket.c index cfec7578..7de56ab6 100644 --- a/socket.c +++ b/socket.c @@ -1710,7 +1710,11 @@ link_socket_init_phase1 (struct link_socket *sock, /* 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; } @@ -1759,7 +1763,34 @@ link_socket_init_phase2 (struct link_socket *sock, /* 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, @@ -1769,6 +1800,7 @@ link_socket_init_phase2 (struct link_socket *sock, false, sock->inetd == INETD_NOWAIT, signal_received); + } ASSERT (!remote_changed); if (*signal_received) goto done; From d3774cdf1e3c2f4e86fac52a723a3869b75b5b4e Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Tue, 22 Mar 2011 21:59:23 +0100 Subject: [PATCH 35/37] * ipv6-0.4.15: add --multihome support to xBSD - _both_ for IPv4 (which was missing) and for IPv6 - tested on OpenBSD 4.7, FreeBSD 8.1 --- socket.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- socket.h | 10 ++++++++++ syshead.h | 5 +++-- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/socket.c b/socket.c index 7de56ab6..7efdf3a9 100644 --- a/socket.c +++ b/socket.c @@ -843,9 +843,17 @@ create_socket_udp (const unsigned int flags) else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; +#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; @@ -2504,8 +2512,15 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, 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); @@ -2847,7 +2862,12 @@ link_socket_read_tcp (struct link_socket *sock, 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 @@ -2892,13 +2912,26 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, 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 +#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.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 @@ -2983,7 +3016,6 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, case AF_INET: { struct openvpn_in4_pktinfo msgpi4; - struct in_pktinfo *pkti; mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in); mesg.msg_control = &msgpi4; @@ -2991,12 +3023,23 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, 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 diff --git a/socket.h b/socket.h index 5f1e800a..f9730b30 100644 --- a/socket.h +++ b/socket.h @@ -86,7 +86,12 @@ struct link_socket_actual struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO 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 @@ -594,7 +599,12 @@ 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 diff --git a/syshead.h b/syshead.h index d5895310..9dbb5015 100644 --- a/syshead.h +++ b/syshead.h @@ -390,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 From 86093c1cb434f448253cc8c7da4481dca320cafc Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Fri, 25 Mar 2011 14:51:33 +0100 Subject: [PATCH 36/37] * ipv6-0.4.15b: rebase over openvpn-testing-master --- README.ipv6 | 4 ++-- options.c | 1 + socket.c | 26 ++++++++++++++------------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/README.ipv6 b/README.ipv6 index 5d17b918..4295f854 100644 --- a/README.ipv6 +++ b/README.ipv6 @@ -1,4 +1,4 @@ -[ Last updated: 16-Nov-2009. ] +[ Last updated: 25-Mar-2011. ] OpenVPN-2.1 over UDP6/TCP6 README for ipv6-0.4.x patch releases: ( --udp6 and --tcp6-{client,server} ) @@ -18,7 +18,7 @@ OpenVPN-2.1 over UDP6/TCP6 README for ipv6-0.4.x patch releases: * Status: o OK: - - upd6,tcp6: GNU/Linux, win32, openbsd-4.6 + - 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: diff --git a/options.c b/options.c index 83017b81..ff65ca29 100644 --- a/options.c +++ b/options.c @@ -79,6 +79,7 @@ const char title_string[] = #endif #ifdef ENABLE_EUREPHIA " [eurephia]" +#endif #ifdef ENABLE_IP_PKTINFO " [MH]" #endif diff --git a/socket.c b/socket.c index 7efdf3a9..7cd62769 100644 --- a/socket.c +++ b/socket.c @@ -52,12 +52,13 @@ const int proto_overhead[] = { /* indexed by PROTO_x */ * Convert sockflags/getaddr_flags into getaddr_flags */ static unsigned int -sf2gaf(unsigned int getaddr_flags, +sf2gaf(const unsigned int getaddr_flags, const unsigned int sockflags) { - getaddr_flags |= (sockflags & SF_GETADDRINFO_DGRAM) ? GETADDR_DGRAM : 0; - getaddr_flags |= (sockflags & SF_HOST_RANDOMIZE) ? GETADDR_RANDOMIZE : 0; - return getaddr_flags; + if (sockflags & SF_HOST_RANDOMIZE) + return getaddr_flags | GETADDR_RANDOMIZE; + else + return getaddr_flags; } /* @@ -2440,11 +2441,11 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr, { const int port= ntohs (addr->addr.in4.sin_port); 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_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) + 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 (separator) @@ -2590,9 +2591,7 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv 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->addr.in4.sin_addr)); - mutex_unlock_static (L_INET_NTOA); if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port) { @@ -2607,8 +2606,11 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); setenv_str (es, name_buf, buf); - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); - setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); + 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 From 6dbf82a96253add5ed5f6c923080f4de4366c874 Mon Sep 17 00:00:00 2001 From: JuanJo Ciarlante Date: Sun, 27 Mar 2011 23:41:22 +0200 Subject: [PATCH 37/37] * ipv6-0.4.16: fix mingw32 build --- acinclude.m4 | 6 +++- install-win32/makeopenvpn | 60 +++++++++++++++++++++++---------------- options.c | 2 +- socket.c | 4 +++ 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 185907f9..acfc01d9 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -123,5 +123,9 @@ AC_DEFUN([TYPE_SOCKLEN_T], AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv, [type to use in place of socklen_t if not defined])], [#include -#include ]) +#ifdef WIN32 +#include +#else +#include +#endif]) ]) diff --git a/install-win32/makeopenvpn b/install-win32/makeopenvpn index 0f06a016..ced2a546 100755 --- a/install-win32/makeopenvpn +++ b/install-win32/makeopenvpn @@ -2,27 +2,34 @@ H=`pwd` -# get version.nsi definitions -. autodefs/defs.sh - -[ -z "$CC" ] && CC=gcc -LZO_INC_DIR=$H/$LZO_DIR/include -LZO_LIB_DIR=$H/$LZO_DIR -PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/usr/local/include -PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/usr/local/lib -XAUTOCONF="" - case "`uname -o 2>/dev/null`" in - *inux) + *inux) + # cross-compiling, make dude's life easier - XAUTOCONF="--host=i586-mingw32msvc --build=i386-linux" + XAUTOCONF="--host=i586-mingw32msvc --build=i386-linux $XAUTOCONF" export CC=i586-mingw32msvc-gcc export CXXCPP=i586-mingw32msvc-cpp export CXX=i586-mingw32msvc-g++ - # when cross-compiling from src, you'll typically get: - LZO_LIB_DIR=$H/$LZO_DIR/src/.libs - PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/include/pkcs11-helper-1.0/ - PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/lib/.libs/ + # this requires the human to setup these environ vars: + # OPENSSL_DIR LZO_DIR PKCS11_HELPER_DIR + OPENSSL_INC_DIR=$OPENSSL_DIR/include + OPENSSL_LIB_DIR=$OPENSSL_DIR/out + LZO_INC_DIR=$LZO_DIR/include + LZO_LIB_DIR=$LZO_DIR/src/.libs + PKCS11_INC_DIR=$PKCS11_HELPER_DIR/include/pkcs11-helper-1.0/ + PKCS11_LIB_DIR=$PKCS11_HELPER_DIR/lib/.libs/ + ;; + *) + # get version.nsi definitions + . autodefs/defs.sh + XAUTOCONF="" + # default configuration creates relative-path environ vars: + OPENSSL_INC_DIR=$H/$OPENSSL_DIR/include + OPENSSL_LIB_DIR=$H/$OPENSSL_DIR/out + LZO_INC_DIR=$H/$LZO_DIR/include + LZO_LIB_DIR=$H/$LZO_DIR + PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/usr/local/include + PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/usr/local/lib ;; esac if $CC --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ -d "$PKCS11_HELPER_DIR" ]; then @@ -34,23 +41,26 @@ if $CC --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ --enable-strict \ --prefix=$H/windest \ MAN2HTML=true \ - --with-ssl-headers=$H/$OPENSSL_DIR/include \ - --with-ssl-lib=$H/$OPENSSL_DIR/out \ + --with-ssl-headers=$OPENSSL_INC_DIR \ + --with-ssl-lib=$OPENSSL_LIB_DIR \ --with-lzo-headers=$LZO_INC_DIR \ --with-lzo-lib=$LZO_LIB_DIR \ --with-pkcs11-helper-headers=$PKCS11_INC_DIR \ - --with-pkcs11-helper-lib=$PKCS11_LIB_DIR + --with-pkcs11-helper-lib=$PKCS11_LIB_DIR \ + || exit 1 fi make -j $MAKE_JOBS && make install + if [ -n "$GENOOUT" ];then # copy OpenVPN and service executables to GENOUT/bin - mkdir -p $GENOUT/bin &>/dev/null - cp windest/sbin/openvpn.exe $GENOUT/bin - cp windest/sbin/openvpnserv.exe $GENOUT/bin - if [ -z "$NO_STRIP" ]; then - strip $GENOUT/bin/openvpn.exe - strip $GENOUT/bin/openvpnserv.exe + mkdir -p $GENOUT/bin &>/dev/null + cp windest/sbin/openvpn.exe $GENOUT/bin + cp windest/sbin/openvpnserv.exe $GENOUT/bin + if [ -z "$NO_STRIP" ]; then + strip $GENOUT/bin/openvpn.exe + strip $GENOUT/bin/openvpnserv.exe + fi fi else echo DID NOT BUILD openvpn.exe and openvpnserv.exe because one or more of gcc, OPENSSL_DIR, LZO_DIR, or PKCS11_HELPER_DIR directories were missing diff --git a/options.c b/options.c index ff65ca29..174ea896 100644 --- a/options.c +++ b/options.c @@ -80,7 +80,7 @@ const char title_string[] = #ifdef ENABLE_EUREPHIA " [eurephia]" #endif -#ifdef ENABLE_IP_PKTINFO +#if ENABLE_IP_PKTINFO " [MH]" #endif #ifdef USE_PF_INET6 diff --git a/socket.c b/socket.c index 7cd62769..1059d3ad 100644 --- a/socket.c +++ b/socket.c @@ -2490,6 +2490,10 @@ print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena 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,