[LAC-TF] VPN leaks y parche para OpenBSD (Fwd: Re: VPN traffic leaks in IPv6/IPv4 dual-stack networks/hosts)

Fernando Gont fernando at gont.com.ar
Tue Nov 27 12:46:04 BRST 2012


Esto es simplemente un data-point de que estas cosas ayudan.

Personalmente, siempre intento "socializar" los documentos con
developers, quienes son los que al fin y al cabo terminan plasmando las
ideas en implementaciones reales.


-------- Original Message --------
From: - Fri Nov 23 14:59:57 2012
Date: Fri, 23 Nov 2012 18:57:47 +0100
From: Reyk Floeter <reyk at openbsd.org>
To: Fernando Gont <fernando at gont.com.ar>
Cc: tech at openbsd.org
Subject: Re: VPN traffic leaks in IPv6/IPv4 dual-stack networks/hosts
Message-ID: <20121123175747.GG18302 at x61.fritz.box>
References: <50AF5899.7000402 at gont.com.ar>
<20121123114432.GF23359 at quigon.bsws.de>
<20121123141216.GA18302 at x61.fritz.box> <50AF8FB3.8090007 at gont.com.ar>
<20121123160116.GE18302 at x61.fritz.box>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20121123160116.GE18302 at x61.fritz.box>
User-Agent: Mutt/1.5.21 (2010-09-15)

On Fri, Nov 23, 2012 at 05:01:16PM +0100, Reyk Floeter wrote:
> Actually, in the iked(8)/IPsec case we could even block all v6 traffic
> without using PF by simply inserting a single "deny" flow.
> For example:
> 
> # ping6 -w ff02::1%em0
> # ipsecctl -vf /etc/ipsec-block.conf 
> flow esp out from ::/0 to ::/0 type deny
> # ping6 -w ff02::1%em0
> 
> Most IPsec VPN clients could use their existing PFKEYv2 interface to
> dynamically add a similar rule to their Security Policy Database.  But
> unfortunately, the SPD is the least portable part of PFKEYv2.
> 

Putting it into practice, it could look like this.

iked(8) would block any IPv6 traffic by default unless an IPv6 flow is
loaded or the -6 command line flag is specified.  This diff is a PoC
and definitely needs more thoughts.

Anyone?

Reyk

Index: iked.8
===================================================================
RCS file: /cvs/src/sbin/iked/iked.8,v
retrieving revision 1.10
diff -u -p -r1.10 iked.8
--- iked.8	22 Oct 2012 13:27:23 -0000	1.10
+++ iked.8	23 Nov 2012 17:53:15 -0000
@@ -23,7 +23,7 @@
 .Nd Internet Key Exchange version 2 (IKEv2) daemon
 .Sh SYNOPSIS
 .Nm iked
-.Op Fl dnSTtv
+.Op Fl 6dnSTtv
 .Oo
 .Fl D Ar macro Ns = Ns Ar value
 .Oc
@@ -59,6 +59,13 @@ infrastructure.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
+.It Fl 6
+Disable automatic blocking of IPv6 traffic.
+By default,
+.Xr iked 8
+blocks any IPv6 traffic unless a flow for this address family has been
+negotiated.
+This option is used to prevent VPN traffic leakages on dual stack hosts.
 .It Fl D Ar macro Ns = Ns Ar value
 Define
 .Ar macro
Index: iked.c
===================================================================
RCS file: /cvs/src/sbin/iked/iked.c,v
retrieving revision 1.13
diff -u -p -r1.13 iked.c
--- iked.c	22 Oct 2012 10:25:17 -0000	1.13
+++ iked.c	23 Nov 2012 17:53:15 -0000
@@ -65,7 +65,7 @@ usage(void)
 {
 	extern char	*__progname;

-	fprintf(stderr, "usage: %s [-dnSTtv] [-D macro=value] "
+	fprintf(stderr, "usage: %s [-6dnSTtv] [-D macro=value] "
 	    "[-f file]\n", __progname);
 	exit(1);
 }
@@ -82,8 +82,11 @@ main(int argc, char *argv[])

 	log_init(1);

-	while ((c = getopt(argc, argv, "dD:nf:vSTt")) != -1) {
+	while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) {
 		switch (c) {
+		case '6':
+			opts |= IKED_OPT_NOIPV6BLOCKING;
+			break;
 		case 'd':
 			debug++;
 			break;
Index: iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.54
diff -u -p -r1.54 iked.h
--- iked.h	22 Oct 2012 10:25:17 -0000	1.54
+++ iked.h	23 Nov 2012 17:53:16 -0000
@@ -141,6 +141,7 @@ struct iked_flow {

 	u_int8_t			 flow_saproto;
 	u_int8_t			 flow_ipproto;
+	u_int8_t			 flow_type;

 	struct iked_id			*flow_srcid;
 	struct iked_id			*flow_dstid;
@@ -762,6 +763,7 @@ int	 eap_parse(struct iked *, struct ike
 int	 pfkey_couple(int, struct iked_sas *, int);
 int	 pfkey_flow_add(int fd, struct iked_flow *);
 int	 pfkey_flow_delete(int fd, struct iked_flow *);
+int	 pfkey_block(int, int, u_int);
 int	 pfkey_sa_init(int, struct iked_childsa *, u_int32_t *);
 int	 pfkey_sa_add(int, struct iked_childsa *, struct iked_childsa *);
 int	 pfkey_sa_delete(int, struct iked_childsa *);
Index: pfkey.c
===================================================================
RCS file: /cvs/src/sbin/iked/pfkey.c,v
retrieving revision 1.20
diff -u -p -r1.20 pfkey.c
--- pfkey.c	23 Oct 2012 14:40:14 -0000	1.20
+++ pfkey.c	23 Nov 2012 17:53:18 -0000
@@ -48,7 +48,9 @@

 static u_int32_t sadb_msg_seq = 0;
 static u_int sadb_decoupled = 0;
+static u_int sadb_ipv6refcnt = 0;

+static int pfkey_blockipv6 = 0;
 static struct event pfkey_timer_ev;
 static struct timeval pfkey_timer_tv;

@@ -247,7 +249,7 @@ pfkey_flow(int sd, u_int8_t satype, u_in

 	bzero(&slocal, sizeof(slocal));
 	bzero(&speer, sizeof(speer));
-	if (action != SADB_X_DELFLOW) {
+	if (action != SADB_X_DELFLOW && flow->flow_local != NULL) {
 		memcpy(&slocal, &flow->flow_local->addr, sizeof(slocal));
 		socket_af((struct sockaddr *)&slocal, 0);

@@ -268,8 +270,9 @@ pfkey_flow(int sd, u_int8_t satype, u_in
 	sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8;
 	sa_flowtype.sadb_protocol_direction = flow->flow_dir;
 	sa_flowtype.sadb_protocol_proto =
-	    flow->flow_dir == IPSP_DIRECTION_IN ?
-	    SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE;
+	    flow->flow_type ? flow->flow_type :
+	    (flow->flow_dir == IPSP_DIRECTION_IN ?
+	    SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE);

 	bzero(&sa_protocol, sizeof(sa_protocol));
 	sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
@@ -295,7 +298,7 @@ pfkey_flow(int sd, u_int8_t satype, u_in
 	sa_dmask.sadb_address_len =
 	    (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8;

-	if (action != SADB_X_DELFLOW) {
+	if (action != SADB_X_DELFLOW && flow->flow_local != NULL) {
 		/* local address */
 		bzero(&sa_local, sizeof(sa_local));
 		sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
@@ -330,7 +333,7 @@ pfkey_flow(int sd, u_int8_t satype, u_in
 	smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len;
 	iov_cnt++;

-	if (action != SADB_X_DELFLOW) {
+	if (action != SADB_X_DELFLOW && flow->flow_local != NULL) {
 #if 0
 		/* local ip */
 		iov[iov_cnt].iov_base = &sa_local;
@@ -1039,6 +1042,13 @@ pfkey_flow_add(int fd, struct iked_flow
 		return (-1);

 	flow->flow_loaded = 1;
+
+	if (flow->flow_dst.addr_af == AF_INET6) {
+		sadb_ipv6refcnt++;
+		if (sadb_ipv6refcnt == 1)
+			return (pfkey_block(fd, AF_INET6, SADB_X_DELFLOW));
+	}
+
 	return (0);
 }

@@ -1057,6 +1067,43 @@ pfkey_flow_delete(int fd, struct iked_fl
 		return (-1);

 	flow->flow_loaded = 0;
+
+	if (flow->flow_dst.addr_af == AF_INET6) {
+		sadb_ipv6refcnt--;
+		if (sadb_ipv6refcnt == 0)
+			return (pfkey_block(fd, AF_INET6, SADB_X_ADDFLOW));
+	}
+
+	return (0);
+}
+
+int
+pfkey_block(int fd, int af, u_int action)
+{
+	struct iked_flow	 flow;
+
+	if (!pfkey_blockipv6)
+		return (0);
+
+	/*
+	 * Prevent VPN traffic leakages in dual-stack hosts/networks.
+	 * http://tools.ietf.org/html/draft-gont-opsec-vpn-leakages.
+	 * We forcibly block IPv6 traffic unless it is used in any of
+	 * the flows by tracking a sadb_ipv6refcnt reference counter.
+	 */
+	bzero(&flow, sizeof(flow));
+	flow.flow_src.addr_af = flow.flow_src.addr.ss_family = af;
+	flow.flow_src.addr_net = 1;
+	socket_af((struct sockaddr *)&flow.flow_src.addr, 0);
+	flow.flow_dst.addr_af = flow.flow_dst.addr.ss_family = af;
+	flow.flow_dst.addr_net = 1;
+	socket_af((struct sockaddr *)&flow.flow_dst.addr, 0);
+	flow.flow_type = SADB_X_FLOW_TYPE_DENY;
+	flow.flow_dir = IPSP_DIRECTION_OUT;
+
+	if (pfkey_flow(fd, SADB_SATYPE_ESP, action, &flow) == -1)
+		return (-1);
+
 	return (0);
 }

@@ -1259,6 +1306,14 @@ pfkey_init(struct iked *env, int fd)
 	pfkey_timer_tv.tv_sec = 1;
 	pfkey_timer_tv.tv_usec = 0;
 	evtimer_set(&pfkey_timer_ev, pfkey_timer_cb, env);
+
+	if (env->sc_opts & IKED_OPT_NOIPV6BLOCKING)
+		return;
+
+	/* Block all IPv6 traffic by default */
+	pfkey_blockipv6 = 1;
+	if (pfkey_block(fd, AF_INET6, SADB_X_ADDFLOW))
+		fatal("pfkey_init: failed to block IPv6 traffic");
 }

 void *
Index: types.h
===================================================================
RCS file: /cvs/src/sbin/iked/types.h,v
retrieving revision 1.15
diff -u -p -r1.15 types.h
--- types.h	23 Oct 2012 14:36:18 -0000	1.15
+++ types.h	23 Nov 2012 17:53:18 -0000
@@ -44,6 +44,7 @@
 #define IKED_OPT_NONATT		0x00000004
 #define IKED_OPT_NATT		0x00000008
 #define IKED_OPT_PASSIVE	0x00000010
+#define IKED_OPT_NOIPV6BLOCKING	0x00000020

 #define IKED_IKE_PORT		500
 #define IKED_NATT_PORT		4500


-- 
Fernando Gont
e-mail: fernando at gont.com.ar || fgont at si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1








More information about the LACTF mailing list