From: Arne Schwabe Date: Mon, 25 Nov 2013 12:31:15 +0000 (+0100) Subject: change the type of 'remote' to addrinfo*, and rename to 'remote_list'. X-Git-Tag: v2.4_alpha1~509 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c5db192c30ff0c6b89e2e0aefec00329de39302;p=thirdparty%2Fopenvpn.git change the type of 'remote' to addrinfo*, and rename to 'remote_list'. Warning: this is work in progress, preparing for the full dual-stack client patch. With this commit in place, connecting via "--proto udp" or "--proto tcp-client" to a host that has IPv4+IPv6 in place, on an OS that will prefer IPv6 to IPv4 will always fail. The remote_list will have IPv6 in it's first entry, while the socket will try to do AF_INET, and that will not work. This will be fixed by the upcoming change to handle multiple remote IP addresses (as returned by getaddrinfo()) as multiple blocks, with appropriate retry and AF selection logic. Acked-by: Gert Doering Message-Id: <1385382680-5912-4-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/8053 Signed-off-by: Gert Doering --- diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 2076aadb8..e7f733b13 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1356,7 +1356,7 @@ do_init_tun (struct context *c) c->options.ifconfig_ipv6_netbits, c->options.ifconfig_ipv6_remote, addr_host (&c->c1.link_socket_addr.local), - addr_host (&c->c1.link_socket_addr.remote), + c->c1.link_socket_addr.remote_list, !c->options.ifconfig_nowarn, c->c2.es); @@ -2867,7 +2867,8 @@ do_close_link_socket (struct context *c) if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) { - CLEAR (c->c1.link_socket_addr.remote); + if (c->c1.link_socket_addr.remote_list) + freeaddrinfo(c->c1.link_socket_addr.remote_list); CLEAR (c->c1.link_socket_addr.actual); } diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 1117e30dd..6853d0e63 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1207,22 +1207,8 @@ resolve_remote (struct link_socket *sock, if (!sock->did_resolve_remote) { /* resolve remote address if undefined */ - if (!addr_defined (&sock->info.lsa->remote)) + if (!sock->info.lsa->remote_list) { - af = addr_guess_family(sock->info.af, 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; - 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; - } - if (sock->remote_host) { unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); @@ -1269,8 +1255,7 @@ resolve_remote (struct link_socket *sock, status = openvpn_getaddrinfo(flags, sock->remote_host, sock->remote_port, retry, signal_received, af, &ai); if(status == 0) { - sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - freeaddrinfo(ai); + sock->info.lsa->remote_list = ai; dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", flags, @@ -1304,7 +1289,17 @@ resolve_remote (struct link_socket *sock, else { CLEAR (sock->info.lsa->actual); - sock->info.lsa->actual.dest = sock->info.lsa->remote; + /* TODO(schwabe) will only use first address als dest address */ + if(sock->info.lsa->remote_list) { + if (sock->info.lsa->remote_list->ai_family == AF_INET) + sock->info.lsa->actual.dest.addr.in4 = + *((struct sockaddr_in*) sock->info.lsa->remote_list->ai_addr); + else if (sock->info.lsa->remote_list->ai_family == AF_INET6) + sock->info.lsa->actual.dest.addr.in6 = + *((struct sockaddr_in6*) sock->info.lsa->remote_list->ai_addr); + else + ASSERT(0); + } } /* remember that we finished */ @@ -1718,7 +1713,8 @@ phase2_socks_client (struct link_socket *sock, bool *remote_changed, sock->did_resolve_remote = false; addr_zero_host(&sock->info.lsa->actual.dest); - addr_zero_host(&sock->info.lsa->remote); + if (sock->info.lsa->remote_list) + freeaddrinfo(sock->info.lsa->remote_list); resolve_remote (sock, 1, NULL, signal_received); } @@ -1792,7 +1788,9 @@ link_socket_init_phase2 (struct link_socket *sock, if (remote_changed) { msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); - addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest); + /* TODO(schwabe) handle multiple addresses */ + ASSERT(0); + addr_copy_host(&sock->info.lsa->remote_list->ai_addr, &sock->info.lsa->actual.dest); } } @@ -1936,6 +1934,10 @@ link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_actual *from_addr) { struct gc_arena gc = gc_new (); + struct openvpn_sockaddr firstremoteaddr; + + /* TODO(schwabe) Fix this and print all remote addresses */ + firstremoteaddr.addr.in6 = *(struct sockaddr_in6*)info->lsa->remote_list->ai_addr; switch(from_addr->dest.addr.sa.sa_family) { @@ -1945,7 +1947,7 @@ link_socket_bad_incoming_addr (struct buffer *buf, "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)); + print_sockaddr (&firstremoteaddr, &gc)); break; } buf->len = 0; @@ -1971,13 +1973,14 @@ link_socket_current_remote (const struct link_socket_info *info) * by now just ignore it * */ +/* TODO(schwabe) what to do for a remote with multiple IPs? */ if (lsa->actual.dest.addr.sa.sa_family != AF_INET) return IPV4_INVALID_ADDR; if (link_socket_actual_defined (&lsa->actual)) return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr); - else if (addr_defined (&lsa->remote)) - return ntohl (lsa->remote.addr.in4.sin_addr.s_addr); + else if (lsa->remote_list) + return ntohl (((struct sockaddr_in*)lsa->remote_list->ai_addr)->sin_addr.s_addr); else return 0; } @@ -2816,7 +2819,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, iov.iov_len = BLEN (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; - switch (sock->info.lsa->remote.addr.sa.sa_family) + switch (sock->info.lsa->remote_list->ai_family) { case AF_INET: { diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index a41a3d979..65def103a 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -98,7 +98,7 @@ struct link_socket_actual struct link_socket_addr { struct openvpn_sockaddr local; - struct openvpn_sockaddr remote; /* initial remote */ + struct addrinfo* remote_list; /* initial remote */ struct link_socket_actual actual; /* reply to this address */ }; @@ -620,6 +620,29 @@ addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2 return false; } +static inline bool +addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) +{ + const struct addrinfo *curele; + for (curele = addrlist; curele; curele=curele->ai_next) + { + switch(a1->addr.sa.sa_family) + { + case AF_INET: + if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr) + return true; + break; + case AF_INET6: + if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)) + return true; + break; + default: + ASSERT(0); + } + } + return false; +} + static inline in_addr_t addr_host (const struct openvpn_sockaddr *addr) { @@ -633,6 +656,36 @@ addr_host (const struct openvpn_sockaddr *addr) return ntohl (addr->addr.in4.sin_addr.s_addr); } + +static inline bool +addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2) +{ + const struct addrinfo *curele; + for(curele=a2;curele;curele = curele->ai_next) + { + switch(a1->addr.sa.sa_family) + { + case AF_INET: + if (curele->ai_family == AF_INET + && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr + && a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port) + return true; + break; + case AF_INET6: + if (curele->ai_family == AF_INET6 + && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr) + && a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port) + return true; + break; + default: + ASSERT(0); + } + } + return false; +} + + + static inline bool addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { @@ -641,7 +694,7 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd 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; case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) + 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; } ASSERT(0); @@ -658,6 +711,17 @@ addr_match_proto (const struct openvpn_sockaddr *a1, : addr_port_match (a1, a2); } + +static inline bool +addrlist_match_proto (const struct openvpn_sockaddr *a1, + struct addrinfo *addr_list, + const int proto) +{ + return link_socket_proto_connection_oriented (proto) + ? addrlist_match (a1, addr_list) + : addrlist_port_match (a1, addr_list); +} + static inline void addr_zero_host(struct openvpn_sockaddr *addr) { @@ -774,9 +838,9 @@ link_socket_verify_incoming_addr (struct buffer *buf, case AF_INET: if (!link_socket_actual_defined (from_addr)) return false; - if (info->remote_float || !addr_defined (&info->lsa->remote)) + if (info->remote_float || !info->lsa->remote_list) return true; - if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto)) + if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto)) return true; } } @@ -818,8 +882,8 @@ link_socket_set_outgoing_addr (const struct buffer *buf, || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)) /* address undef or address == remote or --float */ && (info->remote_float - || !addr_defined (&lsa->remote) - || addr_match_proto (&act->dest, &lsa->remote, info->proto)) + || !lsa->remote_list + || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto)) ) { link_socket_connection_initiated (buf, info, act, common_name, es); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 9f53b23bc..0f30e2fa6 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -412,7 +412,7 @@ init_tun (const char *dev, /* --dev option */ int ifconfig_ipv6_netbits_parm, const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ in_addr_t local_public, - in_addr_t remote_public, + struct addrinfo *remote_public, const bool strict_warn, struct env_set *es) { @@ -466,6 +466,7 @@ init_tun (const char *dev, /* --dev option */ */ if (strict_warn) { + struct addrinfo *curele; ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); /* @@ -479,11 +480,14 @@ init_tun (const char *dev, /* --dev option */ tt->local, tt->remote_netmask); - check_addr_clash ("remote", - tt->type, - remote_public, - tt->local, - tt->remote_netmask); + for (curele=remote_public;curele;curele=curele->ai_next) { + if (curele->ai_family == AF_INET) + check_addr_clash ("remote", + tt->type, + ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, + tt->local, + tt->remote_netmask); + } if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter"); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 2c97ffe45..ea2290c68 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -233,7 +233,7 @@ struct tuntap *init_tun (const char *dev, /* --dev option */ int ifconfig_ipv6_netbits_parm, /* --ifconfig parm 1 / bits */ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ in_addr_t local_public, - in_addr_t remote_public, + struct addrinfo *remote_public, const bool strict_warn, struct env_set *es);