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

Reply via email to