[lacnog] VPN leaks y parche para OpenBSD (Fwd: Re: VPN traffic leaks in IPv6/IPv4 dual-stack networks/hosts)
Fernando Gont
fernando en gont.com.ar
Mar 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 en openbsd.org>
To: Fernando Gont <fernando en gont.com.ar>
Cc: tech en openbsd.org
Subject: Re: VPN traffic leaks in IPv6/IPv4 dual-stack networks/hosts
Message-ID: <20121123175747.GG18302 en x61.fritz.box>
References: <50AF5899.7000402 en gont.com.ar>
<20121123114432.GF23359 en quigon.bsws.de>
<20121123141216.GA18302 en x61.fritz.box> <50AF8FB3.8090007 en gont.com.ar>
<20121123160116.GE18302 en x61.fritz.box>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <20121123160116.GE18302 en 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 en gont.com.ar || fgont en si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
Más información sobre la lista de distribución LACNOG