summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/pfkeyv2.c298
-rw-r--r--sys/net/pfkeyv2.h1
2 files changed, 127 insertions, 172 deletions
diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c
index 487f6961ec6..2c602be0d99 100644
--- a/sys/net/pfkeyv2.c
+++ b/sys/net/pfkeyv2.c
@@ -1062,6 +1062,7 @@ pfkeyv2_send(struct socket *socket, void *message, int len)
{
case SADB_SATYPE_UNSPEC:
case SADB_X_SATYPE_BYPASS:
+ /* XXX IPv4 dependency -- does it matter though ? */
dst.sin.sin_family = AF_INET;
dst.sin.sin_len = sizeof(struct sockaddr_in);
dst.sin.sin_addr.s_addr = INADDR_ANY;
@@ -1100,79 +1101,77 @@ pfkeyv2_send(struct socket *socket, void *message, int len)
struct sockaddr_encap encapdst, encapgw, encapnetmask;
struct flow *flow2 = NULL, *old_flow = NULL, *old_flow2 = NULL;
union sockaddr_union *src, *dst, *srcmask, *dstmask;
- union sockaddr_union alts, altm;
- u_int8_t sproto = 0, local = 0, replace;
+ u_int8_t sproto = 0, replace;
struct rtentry *rt;
-
+ int lp;
+
/*
* SADB_X_SAFLAGS_REPLACEFLOW set means we should remove any
* potentially conflicting flow while we are adding this new one.
*/
- replace = ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags &
+ replace = ((struct sadb_sa *) headers[SADB_EXT_SA])->sadb_sa_flags &
SADB_X_SAFLAGS_REPLACEFLOW;
- if (replace && delflag) {
+ if (replace && delflag)
+ {
rval = EINVAL;
goto ret;
}
- s = spltdb();
- if (!delflag)
- {
- sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address)), SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype));
+ src = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_FLOW] + sizeof(struct sadb_address));
+ dst = (union sockaddr_union *) (headers[SADB_X_EXT_DST_FLOW] + sizeof(struct sadb_address));
+ srcmask = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_MASK] + sizeof(struct sadb_address));
+ dstmask = (union sockaddr_union *) (headers[SADB_X_EXT_DST_MASK] + sizeof(struct sadb_address));
- if (sa2 == NULL) {
- rval = ESRCH;
- goto splxret;
- }
+ /*
+ * Check that all the address families match. We know they are
+ * valid and supported because pfkeyv2_parsemessage() checked that.
+ */
+ if ((src->sa.sa_family != dst->sa.sa_family) ||
+ (src->sa.sa_family != srcmask->sa.sa_family) ||
+ (src->sa.sa_family != dstmask->sa.sa_family))
+ {
+ rval = EINVAL;
+ goto splxret;
}
- local = ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags &
- SADB_X_SAFLAGS_LOCALFLOW;
bzero(&encapdst, sizeof(struct sockaddr_encap));
bzero(&encapnetmask, sizeof(struct sockaddr_encap));
bzero(&encapgw, sizeof(struct sockaddr_encap));
- bzero(&alts, sizeof(alts));
- bzero(&altm, sizeof(altm));
- src = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_FLOW] + sizeof(struct sadb_address));
- dst = (union sockaddr_union *) (headers[SADB_X_EXT_DST_FLOW] + sizeof(struct sadb_address));
- srcmask = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_MASK] + sizeof(struct sadb_address));
- dstmask = (union sockaddr_union *) (headers[SADB_X_EXT_DST_MASK] + sizeof(struct sadb_address));
-
if (headers[SADB_X_EXT_PROTOCOL])
sproto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL])->sadb_protocol_proto;
else
sproto = 0;
-
- src->sin.sin_addr.s_addr &= srcmask->sin.sin_addr.s_addr;
- dst->sin.sin_addr.s_addr &= dstmask->sin.sin_addr.s_addr;
- flow = find_global_flow(src, srcmask, dst, dstmask, sproto);
- if (!replace &&
- ((delflag && (flow == NULL)) || (!delflag && (flow != NULL))))
+ /* Generic netmask handling, works for IPv4 and IPv6 */
+ for (lp = 0; lp < src->sa.sa_len; lp++)
{
- rval = delflag ? ESRCH : EEXIST;
- goto splxret;
+ src->sa.sa_data[lp] &= srcmask->sa.sa_data[lp];
+ dst->sa.sa_data[lp] &= dstmask->sa.sa_data[lp];
}
- /* Check for 0.0.0.0/255.255.255.255 if the flow is local */
- if (local)
+ s = spltdb();
+
+ if (!delflag)
{
- alts.sin.sin_family = altm.sin.sin_family = AF_INET;
- alts.sin.sin_len = altm.sin.sin_len = sizeof(struct sockaddr_in);
- alts.sin.sin_addr.s_addr = INADDR_ANY;
- altm.sin.sin_addr.s_addr = INADDR_BROADCAST;
-
- flow2 = find_global_flow(&alts, &altm, dst, dstmask, sproto);
- if (!replace &&
- ((delflag && (flow2 == NULL)) ||
- (!delflag && (flow2 != NULL))))
- {
- rval = delflag ? ESRCH : EEXIST;
+ /* Find the relevant SA */
+ sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address)), SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype));
+
+ if (sa2 == NULL) {
+ rval = ESRCH;
goto splxret;
}
}
+
+ flow = find_global_flow(src, srcmask, dst, dstmask, sproto);
+ if (!replace &&
+ ((delflag && (flow == NULL)) || (!delflag && (flow != NULL))))
+ {
+ rval = delflag ? ESRCH : EEXIST;
+ goto splxret;
+ }
+
if (!delflag)
{
if (replace)
@@ -1184,57 +1183,100 @@ pfkeyv2_send(struct socket *socket, void *message, int len)
bcopy(dstmask, &flow->flow_dstmask, dstmask->sa.sa_len);
flow->flow_proto = sproto;
put_flow(flow, sa2);
-
- if (local)
- {
- if (replace)
- old_flow2 = flow2;
- flow2 = get_flow();
- bcopy(&alts, &flow2->flow_src, alts.sa.sa_len);
- bcopy(dst, &flow2->flow_dst, dst->sa.sa_len);
- bcopy(&altm, &flow2->flow_srcmask, altm.sa.sa_len);
- bcopy(dstmask, &flow2->flow_dstmask, dstmask->sa.sa_len);
- flow2->flow_proto = sproto;
- put_flow(flow2, sa2);
- }
}
/* Setup the encap fields */
- encapdst.sen_len = SENT_IP4_LEN;
encapdst.sen_family = PF_KEY;
- encapdst.sen_type = SENT_IP4;
- encapdst.sen_ip_src = flow->flow_src.sin.sin_addr;
- encapdst.sen_ip_dst = flow->flow_dst.sin.sin_addr;
- encapdst.sen_proto = flow->flow_proto;
- encapdst.sen_sport = flow->flow_src.sin.sin_port;
- encapdst.sen_dport = flow->flow_dst.sin.sin_port;
-
- if (!delflag)
+ switch (flow->flow_src.sa.sa_family)
{
- encapgw.sen_len = SENT_IPSP_LEN;
- encapgw.sen_family = PF_KEY;
- encapgw.sen_type = SENT_IPSP;
- encapgw.sen_ipsp_dst = sa2->tdb_dst.sin.sin_addr;
- encapgw.sen_ipsp_spi = sa2->tdb_spi;
- encapgw.sen_ipsp_sproto = sa2->tdb_sproto;
+ case AF_INET:
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src = flow->flow_src.sin.sin_addr;
+ encapdst.sen_ip_dst = flow->flow_dst.sin.sin_addr;
+ encapdst.sen_proto = flow->flow_proto;
+ encapdst.sen_sport = flow->flow_src.sin.sin_port;
+ encapdst.sen_dport = flow->flow_dst.sin.sin_port;
+
+ encapnetmask.sen_len = SENT_IP4_LEN;
+ encapnetmask.sen_family = PF_KEY;
+ encapnetmask.sen_type = SENT_IP4;
+ encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr;
+ encapnetmask.sen_ip_dst = flow->flow_dstmask.sin.sin_addr;
+ break;
+
+#if INET6
+ case AF_INET6:
+ encapdst.sen_len = SENT_IP6_LEN;
+ encapdst.sen_type = SENT_IP6;
+ encapdst.sen_ip6_src = flow->flow_src.sin6.sin6_addr;
+ encapdst.sen_ip6_dst = flow->flow_dst.sin6.sin6_addr;
+ encapdst.sen_ip6_proto = flow->flow_proto;
+ encapdst.sen_ip6_sport = flow->flow_src.sin6.sin6_port;
+ encapdst.sen_ip6_dport = flow->flow_dst.sin6.sin6_port;
+
+ encapnetmask.sen_len = SENT_IP6_LEN;
+ encapnetmask.sen_family = PF_KEY;
+ encapnetmask.sen_type = SENT_IP6;
+ encapnetmask.sen_ip6_src = flow->flow_srcmask.sin6.sin6_addr;
+ encapnetmask.sen_ip6_dst = flow->flow_dstmask.sin6.sin6_addr;
+ break;
+#endif /* INET6 */
}
-
- encapnetmask.sen_len = SENT_IP4_LEN;
- encapnetmask.sen_family = PF_KEY;
- encapnetmask.sen_type = SENT_IP4;
- encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr;
- encapnetmask.sen_ip_dst = flow->flow_dstmask.sin.sin_addr;
- if (flow->flow_proto)
+ if (!delflag)
{
- encapnetmask.sen_proto = 0xff;
-
- if (flow->flow_src.sin.sin_port)
- encapnetmask.sen_sport = 0xffff;
-
- if (flow->flow_dst.sin.sin_port)
- encapnetmask.sen_dport = 0xffff;
+ switch (sa2->tdb_dst.sa.sa_family)
+ {
+ case AF_INET:
+ encapgw.sen_len = SENT_IPSP_LEN;
+ encapgw.sen_family = PF_KEY;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp_dst = sa2->tdb_dst.sin.sin_addr;
+ encapgw.sen_ipsp_spi = sa2->tdb_spi;
+ encapgw.sen_ipsp_sproto = sa2->tdb_sproto;
+
+ if (flow->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+ if (flow->flow_src.sin.sin_port)
+ encapnetmask.sen_sport = 0xffff;
+ if (flow->flow_dst.sin.sin_port)
+ encapnetmask.sen_dport = 0xffff;
+ }
+ break;
+
+#if INET6
+ case AF_INET6:
+ encapgw.sen_len = SENT_IPSP6_LEN;
+ encapgw.sen_family = PF_KEY;
+ encapgw.sen_type = SENT_IPSP6;
+ encapgw.sen_ipsp6_dst = sa2->tdb_dst.sin6.sin6_addr;
+ encapgw.sen_ipsp6_spi = sa2->tdb_spi;
+ encapgw.sen_ipsp6_sproto = sa2->tdb_sproto;
+
+ if (flow->flow_proto)
+ {
+ encapnetmask.sen_ip6_proto = 0xff;
+ if (flow->flow_src.sin6.sin6_port)
+ encapnetmask.sen_ip6_sport = 0xffff;
+ if (flow->flow_dst.sin6.sin6_port)
+ encapnetmask.sen_ip6_dport = 0xffff;
+ }
+ break;
+#endif /* INET6 */
+
+ default:
+ /*
+ * This shouldn't ever happen really, as SAs
+ * should be checked at establishment time.
+ */
+ rval = EPFNOSUPPORT;
+ delete_flow(flow, flow->flow_sa);
+ goto splxret;
+ }
}
+
/* Add the entry in the routing table */
if (delflag)
{
@@ -1295,92 +1337,6 @@ pfkeyv2_send(struct socket *socket, void *message, int len)
sa2->tdb_cur_allocations++;
}
- /* If this is a "local" packet flow */
- if (local)
- {
- encapdst.sen_ip_src.s_addr = INADDR_ANY;
- encapnetmask.sen_ip_src.s_addr = INADDR_BROADCAST;
-
- if (delflag)
- {
- rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
- (struct sockaddr *) 0,
- (struct sockaddr *) &encapnetmask, 0,
- (struct rtentry **) 0);
-
- delete_flow(flow2, flow2->flow_sa);
- }
- else if (!replace)
- {
- rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
- (struct sockaddr *) &encapgw,
- (struct sockaddr *) &encapnetmask,
- RTF_UP | RTF_GATEWAY | RTF_STATIC,
- (struct rtentry **) 0);
-
- if (rval)
- {
- /* Delete the first entry inserted */
- encapdst.sen_ip_src = flow->flow_src.sin.sin_addr;
- encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr;
-
- rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
- (struct sockaddr *) 0,
- (struct sockaddr *) &encapnetmask, 0,
- (struct rtentry **) 0);
-
- delete_flow(flow, sa2);
- delete_flow(flow2, sa2);
- goto splxret;
- }
-
- sa2->tdb_cur_allocations++;
- }
- else
- {
- rt = (struct rtentry *) rn_lookup(&encapdst, &encapnetmask,
- rt_tables[PF_KEY]);
- if (rt == NULL)
- {
- rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
- (struct sockaddr *) &encapgw,
- (struct sockaddr *) &encapnetmask,
- RTF_UP | RTF_GATEWAY | RTF_STATIC,
- (struct rtentry **) 0);
-
- if (rval)
- {
- /*
- * XXX We really should try to restore the non-local
- * route if we need to abort here but that is getting
- * very hairy. Currently we do half the change and
- * return an error, which is not optimal.
- */
-
- if (old_flow)
- delete_flow(old_flow, old_flow->flow_sa);
- delete_flow(flow2, sa2);
- goto splxret;
- }
- }
- else if (rt_setgate(rt, rt_key(rt),
- (struct sockaddr *) &encapgw))
- {
- /*
- * XXX See above regarding the cleaning of the
- * non-local route.
- */
- rval = ENOMEM;
- if (old_flow)
- delete_flow(old_flow, old_flow->flow_sa);
- delete_flow(flow2, sa2);
- goto splxret;
- }
-
- sa2->tdb_cur_allocations++;
- }
- }
-
if (replace)
{
if (old_flow != NULL)
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 2a05711d7c3..a9ee9df9c7d 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -234,7 +234,6 @@ struct sadb_protocol {
#define SADB_X_SAFLAGS_HALFIV 0x02 /* Used for ESP-old */
#define SADB_X_SAFLAGS_TUNNEL 0x04 /* Force tunneling */
#define SADB_X_SAFLAGS_CHAINDEL 0x08 /* Delete whole SA chain */
-#define SADB_X_SAFLAGS_LOCALFLOW 0x10 /* Add flow with src=0.0.0.0 */
#define SADB_X_SAFLAGS_REPLACEFLOW 0x20 /* Replace existing flow */
#define SADB_IDENTTYPE_RESERVED 0