summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2013-11-25 13:31:15 +0100
committerGert Doering <gert@greenie.muc.de>2013-11-27 20:18:36 +0100
commit6c5db192c30ff0c6b89e2e0aefec00329de39302 (patch)
tree9b364925444a5403c3652d7b4d2e33c9c42a0781
parentbb9026a60a8ebdf20fdf9a99e16c0d8afc658747 (diff)
downloadopenvpn-6c5db192c30ff0c6b89e2e0aefec00329de39302.tar.gz
openvpn-6c5db192c30ff0c6b89e2e0aefec00329de39302.tar.xz
openvpn-6c5db192c30ff0c6b89e2e0aefec00329de39302.zip
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 <connection> blocks, with appropriate retry and AF selection logic. Acked-by: Gert Doering <gert@greenie.muc.de> 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 <gert@greenie.muc.de>
-rw-r--r--src/openvpn/init.c5
-rw-r--r--src/openvpn/socket.c51
-rw-r--r--src/openvpn/socket.h76
-rw-r--r--src/openvpn/tun.c16
-rw-r--r--src/openvpn/tun.h2
5 files changed, 111 insertions, 39 deletions
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 2076aad..e7f733b 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 1117e30..6853d0e 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 a41a3d9..65def10 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 9f53b23..0f30e2f 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 2c97ffe..ea2290c 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);