Hi, the diff below adds a new feature that allows the use of separate rdomains for the encrypted and unencrypted side of ipsec(4) flows.
The idea is that an edge router that controls access to a private network via ipsec can have its uplink in one rdomain and the private network in another. The kernel automatically moves successfully encrypted/decrypted packets to the respective rdomain. The outer (uplink) rdomain only ever sees encrypted packets, which could add another layer of protection against side channel leak attacks that we have seen in the past. The feature can be configured in iked(8) with the new 'rdomain $NUMBER' option (see iked.conf(5)). Only the inner (unencrypted) rdomain has to be configured, the outer rdomain is always the one the iked instance is running in. For this to work, the inner rdomain must exist (have at least one interface assigned) and have an enc(4) interface assigned before starting iked. The resulting flows and the outgoing SA are visible from the inner rdomain only, so don't forget to 'route -T $ID exec' ipsecctl. The incoming SA is visible from the outer rdomain. tcpdump works as usual on the enc(4) interface of the inner rdomain. Thanks to markus@ who did a lot of the work on this. Comments and tests welcome ;) diff --git a/sbin/iked/iked.conf.5 b/sbin/iked/iked.conf.5 index b0128610c81..980fa66952c 100644 --- a/sbin/iked/iked.conf.5 +++ b/sbin/iked/iked.conf.5 @@ -311,6 +311,18 @@ For a list of all the protocol name to number mappings used by .Xr iked 8 , see the file .Pa /etc/protocols . +.It Ic rdomain Ar number +Specify a different routing domain for unencrypted traffic. +The resulting IPsec SAs will match outgoing packets in the specified +.Ic rdomain Ar number +and move the encrypted packets to the rdomain the +.Xr iked 8 +instance is running in. +Vice versa, incoming +.Xr ipsec 4 +traffic is moved to +.Ic rdomain Ar number +after decryption. .It Xo .Ic from Ar src .Op Ic port Ar sport diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index 598e82d0157..203f34d637c 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -151,6 +151,7 @@ struct iked_flow { struct iked_addr flow_src; struct iked_addr flow_dst; unsigned int flow_dir; /* in/out */ + int flow_rdomain; struct iked_addr flow_prenat; unsigned int flow_loaded; /* pfkey done */ @@ -261,6 +262,7 @@ struct iked_policy { uint8_t pol_certreqtype; int pol_af; + int pol_rdomain; uint8_t pol_saproto; unsigned int pol_ipproto; diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 4074ea549b8..4d960a60342 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -5371,6 +5371,7 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, flowa->flow_dir = IPSP_DIRECTION_OUT; flowa->flow_saproto = ic ? IKEV2_SAPROTO_IPCOMP : prop->prop_protoid; + flowa->flow_rdomain = sa->sa_policy->pol_rdomain; flowa->flow_local = &sa->sa_local; flowa->flow_peer = &sa->sa_peer; flowa->flow_ikesa = sa; @@ -6440,7 +6441,7 @@ ikev2_info_flow(struct iked *env, int dolog, const char *msg, struct iked_flow * int buflen; buflen = asprintf(&buf, - "%s: %p %s %s %s/%d -> %s/%d [%u] (%s) @%p\n", msg, flow, + "%s: %p %s %s %s/%d -> %s/%d [%u]@%d (%s) @%p\n", msg, flow, print_map(flow->flow_saproto, ikev2_saproto_map), flow->flow_dir == IPSP_DIRECTION_IN ? "in" : "out", print_host((struct sockaddr *)&flow->flow_src.addr, NULL, 0), @@ -6448,6 +6449,7 @@ ikev2_info_flow(struct iked *env, int dolog, const char *msg, struct iked_flow * print_host((struct sockaddr *)&flow->flow_dst.addr, NULL, 0), flow->flow_dst.addr_mask, flow->flow_ipproto, + flow->flow_rdomain, flow->flow_loaded ? "L" : "", flow->flow_ikesa); diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index 38c07b95de2..bb578d45399 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -351,7 +351,8 @@ void copy_transforms(unsigned int, const struct ipsec_xf **, unsigned int, struct iked_transform **, unsigned int *, struct iked_transform *, size_t); -int create_ike(char *, int, uint8_t, struct ipsec_hosts *, +int create_ike(char *, int, uint8_t, + int, struct ipsec_hosts *, struct ipsec_hosts *, struct ipsec_mode *, struct ipsec_mode *, uint8_t, uint8_t, char *, char *, @@ -408,7 +409,7 @@ typedef struct { %token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER %token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET %token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT -%token IPCOMP OCSP IKELIFETIME MOBIKE NOMOBIKE +%token IPCOMP OCSP IKELIFETIME MOBIKE NOMOBIKE RDOMAIN %token FRAGMENTATION NOFRAGMENTATION %token <v.string> STRING %token <v.number> NUMBER @@ -418,7 +419,7 @@ typedef struct { %type <v.number> protoval %type <v.hosts> hosts hosts_list %type <v.port> port -%type <v.number> portval af +%type <v.number> portval af rdomain %type <v.peers> peers %type <v.anyhost> anyhost %type <v.host> host host_spec @@ -491,12 +492,12 @@ user : USER STRING STRING { } ; -ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers +ikev2rule : IKEV2 name ikeflags satype af proto rdomain hosts_list peers ike_sas child_sas ids ikelifetime lifetime ikeauth ikecfg filters { - if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3, - $11.srcid, $11.dstid, $12, &$13, &$14, - $16, $15) == -1) { + if (create_ike($2, $5, $6, $7, $8, &$9, $10, $11, $4, + $3, $12.srcid, $12.dstid, $13, &$14, &$15, + $17, $16) == -1) { yyerror("create_ike failed"); YYERROR; } @@ -577,6 +578,15 @@ protoval : STRING { } ; +rdomain : /* empty */ { $$ = -1; } + | RDOMAIN NUMBER { + if ($2 > 255 || $2 < 0) { + yyerror("rdomain outside range"); + YYERROR; + } + $$ = $2; + } + hosts_list : hosts { $$ = $1; } | hosts_list comma hosts { if ($3 == NULL) @@ -1264,6 +1274,7 @@ lookup(char *s) { "proto", PROTO }, { "psk", PSK }, { "quick", QUICK }, + { "rdomain", RDOMAIN }, { "sa", SA }, { "set", SET }, { "skip", SKIP }, @@ -2497,6 +2508,9 @@ print_policy(struct iked_policy *pol) print_verbose(" inet6"); } + if (pol->pol_rdomain) + print_verbose(" rdomain %d", pol->pol_rdomain); + RB_FOREACH(flow, iked_flows, &pol->pol_flows) { print_verbose(" from %s", print_host((struct sockaddr *)&flow->flow_src.addr, NULL, @@ -2679,7 +2693,8 @@ copy_transforms(unsigned int type, } int -create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, +create_ike(char *name, int af, uint8_t ipproto, + int rdomain, struct ipsec_hosts *hosts, struct ipsec_hosts *peers, struct ipsec_mode *ike_sa, struct ipsec_mode *ipsec_sa, uint8_t saproto, uint8_t flags, char *srcid, char *dstid, @@ -2709,6 +2724,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, pol.pol_saproto = saproto; pol.pol_ipproto = ipproto; pol.pol_flags = flags; + pol.pol_rdomain = rdomain; memcpy(&pol.pol_auth, authtype, sizeof(struct iked_auth)); if (name != NULL) { @@ -2969,6 +2985,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, } flow->flow_ipproto = ipproto; + flow->flow_rdomain = rdomain; if (RB_INSERT(iked_flows, &pol.pol_flows, flow) == NULL) pol.pol_nflows++; diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c index b4d2ffff537..a225432d159 100644 --- a/sbin/iked/pfkey.c +++ b/sbin/iked/pfkey.c @@ -40,7 +40,7 @@ #include "ikev2.h" #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) -#define IOV_CNT 20 +#define IOV_CNT 21 #define PFKEYV2_CHUNK sizeof(uint64_t) #define PFKEY_REPLY_TIMEOUT 1000 @@ -51,6 +51,8 @@ static uint32_t sadb_msg_seq = 0; static unsigned int sadb_decoupled = 0; +static int iked_rdomain = 0; + static struct event pfkey_timer_ev; static struct timeval pfkey_timer_tv; @@ -184,6 +186,7 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, sa_dmask; struct sadb_protocol sa_flowtype, sa_protocol; + struct sadb_x_rdomain sa_rdomain; struct sadb_ident *sa_srcid, *sa_dstid; struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; struct iovec iov[IOV_CNT]; @@ -335,6 +338,14 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) SADB_EXT_IDENTITY_DST); } + if (flow->flow_rdomain >= 0) { + /* install flow in specific rdomain */ + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + sa_rdomain.sadb_x_rdomain_dom1 = flow->flow_rdomain; + } + iov_cnt = 0; /* header */ @@ -427,6 +438,13 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow) iov_cnt++; } + if (flow->flow_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); free(sa_srcid); @@ -447,6 +465,7 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) struct sadb_x_tag sa_tag; char *tag = NULL; struct sadb_x_tap sa_tap; + struct sadb_x_rdomain sa_rdomain; struct sockaddr_storage ssrc, sdst, spxy; struct sadb_ident *sa_srcid, *sa_dstid; struct iked_lifetime *lt; @@ -532,6 +551,24 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) bzero(&sa_ltime_hard, sizeof(sa_ltime_hard)); bzero(&sa_ltime_soft, sizeof(sa_ltime_soft)); + if (pol->pol_rdomain >= 0) { + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + if (satype == SADB_X_SATYPE_IPCOMP) { + /* IPCOMP SAs are always in the pol_rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } else if (sa->csa_dir == IPSP_DIRECTION_OUT) { + /* switch rdomain on encrypt/decrypt */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = iked_rdomain; + } else { + sa_rdomain.sadb_x_rdomain_dom1 = iked_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } + } + if (action == SADB_DELETE) goto send; @@ -775,6 +812,13 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) iov_cnt++; } + if (pol->pol_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + ret = pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL); free(sa_srcid); @@ -786,15 +830,17 @@ pfkey_sa(int sd, uint8_t satype, uint8_t action, struct iked_childsa *sa) int pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) { + struct iked_policy *pol = sa->csa_ikesa->sa_policy; struct sadb_msg *msg, smsg; struct sadb_address sa_src, sa_dst; struct sadb_sa sadb; + struct sadb_x_rdomain sa_rdomain; struct sadb_lifetime *sa_life; struct sockaddr_storage ssrc, sdst; struct iovec iov[IOV_CNT]; uint8_t *data; ssize_t n; - int iov_cnt, ret = -1; + int iov_cnt, ret = -1, rdomain; uint8_t satype; *last_used = 0; @@ -831,6 +877,15 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) sadb.sadb_sa_state = SADB_SASTATE_MATURE; sadb.sadb_sa_replay = 64; + if (pol->pol_rdomain >= 0) { + rdomain = (sa->csa_dir == IPSP_DIRECTION_IN) ? + iked_rdomain : pol->pol_rdomain; + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + sa_rdomain.sadb_x_rdomain_dom1 = rdomain; + } + bzero(&sa_src, sizeof(sa_src)); sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; @@ -870,6 +925,13 @@ pfkey_sa_last_used(int sd, struct iked_childsa *sa, uint64_t *last_used) smsg.sadb_msg_len += sa_dst.sadb_address_len; iov_cnt++; + if (pol->pol_rdomain >= 0) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + if ((ret = pfkey_write(sd, &smsg, iov, iov_cnt, &data, &n)) != 0) return (-1); @@ -1010,8 +1072,11 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, struct sadb_address sa_dst1, sa_dst2; struct sockaddr_storage sdst1, sdst2; struct sadb_protocol sa_proto; + struct sadb_x_rdomain sa_rdomain; + struct iked_policy *pol; struct iovec iov[IOV_CNT]; int iov_cnt; + int group_rdomain; uint8_t satype2; if (pfkey_map(pfkey_satype, sa2->csa_saproto, &satype2) == -1) @@ -1052,6 +1117,28 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, sadb2.sadb_sa_exttype = SADB_X_EXT_SA2; sadb2.sadb_sa_spi = htonl(sa2->csa_spi.spi); sadb2.sadb_sa_state = SADB_SASTATE_MATURE; + + /* Incoming SA1 (IPCOMP) and SA2 (ESP) are in different/other rdomain */ + group_rdomain = + (pol = sa1->csa_ikesa->sa_policy) != NULL && + pol->pol_rdomain >= 0 && + satype1 == SADB_X_SATYPE_IPCOMP && + satype2 == SADB_SATYPE_ESP; + if (group_rdomain) { + bzero(&sa_rdomain, sizeof(sa_rdomain)); + sa_rdomain.sadb_x_rdomain_exttype = SADB_X_EXT_RDOMAIN; + sa_rdomain.sadb_x_rdomain_len = sizeof(sa_rdomain) / 8; + if (sa1->csa_dir == IPSP_DIRECTION_IN) { + /* only ESP SA is iked's rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = iked_rdomain; + } else { + /* both SAs are in pol_rdomain */ + sa_rdomain.sadb_x_rdomain_dom1 = pol->pol_rdomain; + sa_rdomain.sadb_x_rdomain_dom2 = pol->pol_rdomain; + } + } + iov_cnt = 0; bzero(&sa_dst1, sizeof(sa_dst1)); @@ -1111,6 +1198,14 @@ pfkey_sagroup(int sd, uint8_t satype1, uint8_t action, smsg.sadb_msg_len += sa_proto.sadb_protocol_len; iov_cnt++; + /* SA1 and SA2 are from different rdomains */ + if (group_rdomain) { + iov[iov_cnt].iov_base = &sa_rdomain; + iov[iov_cnt].iov_len = sizeof(sa_rdomain); + smsg.sadb_msg_len += sa_rdomain.sadb_x_rdomain_len; + iov_cnt++; + } + return (pfkey_write(sd, &smsg, iov, iov_cnt, NULL, NULL)); } @@ -1467,6 +1562,8 @@ pfkey_init(struct iked *env, int fd) struct sadb_msg smsg; struct iovec iov; + iked_rdomain = getrtable(); + /* Set up a timer to process messages deferred by the pfkey_reply */ pfkey_timer_tv.tv_sec = 1; pfkey_timer_tv.tv_usec = 0; @@ -1787,6 +1884,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm) goto out; } flow.flow_dir = sa_proto->sadb_protocol_direction; + flow.flow_rdomain = -1; /* XXX get from kernel */ log_debug("%s: flow %s from %s/%s to %s/%s via %s", __func__, flow.flow_dir == IPSP_DIRECTION_IN ? "in" : "out", diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 3a05d947927..51fd1cfa55c 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -874,6 +874,8 @@ flow_cmp(struct iked_flow *a, struct iked_flow *b) { int diff = 0; + if (!diff) + diff = a->flow_rdomain - b->flow_rdomain; if (!diff) diff = (int)a->flow_ipproto - (int)b->flow_ipproto; if (!diff) diff --git a/sbin/ipsecctl/pfkdump.c b/sbin/ipsecctl/pfkdump.c index 3ab5ea17c4c..5dd99a49a19 100644 --- a/sbin/ipsecctl/pfkdump.c +++ b/sbin/ipsecctl/pfkdump.c @@ -56,6 +56,7 @@ static void print_life(struct sadb_ext *, struct sadb_msg *, int); static void print_ident(struct sadb_ext *, struct sadb_msg *, int); static void print_udpenc(struct sadb_ext *, struct sadb_msg *, int); static void print_tag(struct sadb_ext *, struct sadb_msg *, int); +static void print_rdomain(struct sadb_ext *, struct sadb_msg *, int); static void print_tap(struct sadb_ext *, struct sadb_msg *, int); static void print_satype(struct sadb_ext *, struct sadb_msg *, int); static void print_counter(struct sadb_ext *, struct sadb_msg *, int); @@ -106,6 +107,7 @@ struct idname ext_types[] = { { SADB_X_EXT_UDPENCAP, "udpencap", print_udpenc }, { SADB_X_EXT_LIFETIME_LASTUSE, "lifetime_lastuse", print_life }, { SADB_X_EXT_TAG, "tag", print_tag }, + { SADB_X_EXT_RDOMAIN, "rdomain", print_rdomain }, { SADB_X_EXT_TAP, "tap", print_tap }, { SADB_X_EXT_SATYPE2, "satype2", print_satype }, { SADB_X_EXT_COUNTER, "counter", print_counter }, @@ -582,6 +584,16 @@ print_udpenc(struct sadb_ext *ext, struct sadb_msg *msg, int opts) printf("udpencap port %u", ntohs(x_udpencap->sadb_x_udpencap_port)); } +/* ARGSUSED1 */ +static void +print_rdomain(struct sadb_ext *ext, struct sadb_msg *msg, int opts) +{ + struct sadb_x_rdomain *srdomain = (struct sadb_x_rdomain *)ext; + + printf("%d/%d", srdomain->sadb_x_rdomain_dom1, + srdomain->sadb_x_rdomain_dom2); +} + static void setup_extensions(struct sadb_msg *msg) { diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c index 0094555edba..d48993321bd 100644 --- a/sys/net/pfkeyv2.c +++ b/sys/net/pfkeyv2.c @@ -855,6 +855,9 @@ pfkeyv2_get(struct tdb *tdb, void **headers, void **buffer, int *lenp) if (tdb->tdb_udpencap_port) i += sizeof(struct sadb_x_udpencap); + if (tdb->tdb_rdomain != tdb->tdb_rdomain_post) + i += sizeof(struct sadb_x_rdomain); + #if NPF > 0 if (tdb->tdb_tag) i += sizeof(struct sadb_x_tag) + PADUP(PF_TAG_NAME_SIZE); @@ -945,6 +948,12 @@ pfkeyv2_get(struct tdb *tdb, void **headers, void **buffer, int *lenp) export_udpencap(&p, tdb); } + /* Export rdomain switch, if present */ + if (tdb->tdb_rdomain != tdb->tdb_rdomain_post) { + headers[SADB_X_EXT_RDOMAIN] = p; + export_rdomain(&p, tdb); + } + #if NPF > 0 /* Export tag information, if present */ if (tdb->tdb_tag) { @@ -1109,7 +1118,8 @@ pfkeyv2_send(struct socket *so, void *message, int len) struct sadb_supported *ssup; struct sadb_ident *sid, *did; struct srp_ref sr; - u_int rdomain; + struct sadb_x_rdomain *srdomain; + u_int rdomain = 0; int promisc, s; mtx_enter(&pfkeyv2_mtx); @@ -1155,7 +1165,7 @@ pfkeyv2_send(struct socket *so, void *message, int len) /* Send to all promiscuous listeners */ SRPL_FOREACH(bkp, &sr, &pkptable.pkp_list, kcb_list) { - if (bkp->kcb_rdomain != rdomain) + if (bkp->kcb_rdomain != kp->kcb_rdomain) continue; s = keylock(bkp); @@ -1177,6 +1187,17 @@ pfkeyv2_send(struct socket *so, void *message, int len) if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0) goto ret; + /* use specified rdomain */ + srdomain = (struct sadb_x_rdomain *) headers[SADB_X_EXT_RDOMAIN]; + if (srdomain) { + if (!rtable_exists(srdomain->sadb_x_rdomain_dom1) || + !rtable_exists(srdomain->sadb_x_rdomain_dom2)) { + rval = EINVAL; + goto ret; + } + rdomain = srdomain->sadb_x_rdomain_dom1; + } + smsg = (struct sadb_msg *) headers[0]; switch (smsg->sadb_msg_type) { case SADB_GETSPI: /* Reserve an SPI */ @@ -1316,6 +1337,7 @@ pfkeyv2_send(struct socket *so, void *message, int len) headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]); import_udpencap(newsa, headers[SADB_X_EXT_UDPENCAP]); + import_rdomain(newsa, headers[SADB_X_EXT_RDOMAIN]); #if NPF > 0 import_tag(newsa, headers[SADB_X_EXT_TAG]); import_tap(newsa, headers[SADB_X_EXT_TAP]); @@ -1486,6 +1508,7 @@ pfkeyv2_send(struct socket *so, void *message, int len) headers[SADB_X_EXT_PROTOCOL], headers[SADB_X_EXT_FLOW_TYPE]); import_udpencap(newsa, headers[SADB_X_EXT_UDPENCAP]); + import_rdomain(newsa, headers[SADB_X_EXT_RDOMAIN]); #if NPF > 0 import_tag(newsa, headers[SADB_X_EXT_TAG]); import_tap(newsa, headers[SADB_X_EXT_TAP]); @@ -1720,7 +1743,9 @@ pfkeyv2_send(struct socket *so, void *message, int len) sizeof(struct sadb_address)); sa_proto = (struct sadb_protocol *) headers[SADB_X_EXT_SATYPE2]; - tdb2 = gettdb(rdomain, ssa->sadb_sa_spi, sunionp, + /* optionally fetch tdb2 from rdomain2 */ + tdb2 = gettdb(srdomain ? srdomain->sadb_x_rdomain_dom2 : rdomain, + ssa->sadb_sa_spi, sunionp, SADB_X_GETSPROTO(sa_proto->sadb_protocol_proto)); if (tdb2 == NULL) { rval = ESRCH; @@ -1983,7 +2008,7 @@ pfkeyv2_send(struct socket *so, void *message, int len) goto ret; SRPL_FOREACH(bkp, &sr, &pkptable.pkp_list, kcb_list) { - if (bkp == kp || bkp->kcb_rdomain != rdomain) + if (bkp == kp || bkp->kcb_rdomain != kp->kcb_rdomain) continue; if (!smsg->sadb_msg_seq || @@ -2061,7 +2086,7 @@ ret: } } - rval = pfkeyv2_sendmessage(headers, mode, so, 0, 0, rdomain); + rval = pfkeyv2_sendmessage(headers, mode, so, 0, 0, kp->kcb_rdomain); realret: @@ -2360,6 +2385,12 @@ pfkeyv2_expire(struct tdb *tdb, u_int16_t type) if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_BROADCAST, NULL, 0, 0, tdb->tdb_rdomain)) != 0) goto ret; + /* XXX */ + if (tdb->tdb_rdomain != tdb->tdb_rdomain_post) + if ((rval = pfkeyv2_sendmessage(headers, + PFKEYV2_SENDMESSAGE_BROADCAST, NULL, 0, 0, + tdb->tdb_rdomain_post)) != 0) + goto ret; rval = 0; @@ -2620,6 +2651,7 @@ pfkeyv2_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, struct pfkeyv2_sysctl_walk w; int error = EINVAL; u_int rdomain; + u_int tableid; if (new) return (EPERM); @@ -2630,7 +2662,13 @@ pfkeyv2_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, w.w_where = oldp; w.w_len = oldp ? *oldlenp : 0; - rdomain = rtable_l2(curproc->p_p->ps_rtableid); + if (namelen == 3) { + tableid = name[2]; + if (!rtable_exists(tableid)) + return (ENOENT); + } else + tableid = curproc->p_p->ps_rtableid; + rdomain = rtable_l2(tableid); switch(w.w_op) { case NET_KEY_SADB_DUMP: diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h index 9c31163e95e..4e0f71e0dcd 100644 --- a/sys/net/pfkeyv2.h +++ b/sys/net/pfkeyv2.h @@ -212,6 +212,13 @@ struct sadb_x_tag { u_int32_t sadb_x_tag_taglen; }; +struct sadb_x_rdomain { + uint16_t sadb_x_rdomain_len; + uint16_t sadb_x_rdomain_exttype; + uint16_t sadb_x_rdomain_dom1; + uint16_t sadb_x_rdomain_dom2; +}; + struct sadb_x_tap { uint16_t sadb_x_tap_len; uint16_t sadb_x_tap_exttype; @@ -277,7 +284,8 @@ struct sadb_x_counter { #define SADB_X_EXT_TAP 34 #define SADB_X_EXT_SATYPE2 35 #define SADB_X_EXT_COUNTER 36 -#define SADB_EXT_MAX 36 +#define SADB_X_EXT_RDOMAIN 37 +#define SADB_EXT_MAX 37 /* Fix pfkeyv2.c struct pfkeyv2_socket if SATYPE_MAX > 31 */ #define SADB_SATYPE_UNSPEC 0 @@ -409,6 +417,7 @@ void export_flow(void **, u_int8_t, struct sockaddr_encap *, void export_key(void **, struct tdb *, int); void export_udpencap(void **, struct tdb *); void export_tag(void **, struct tdb *); +void export_rdomain(void **, struct tdb *); void export_tap(void **, struct tdb *); void export_satype(void **, struct tdb *); void export_counter(void **, struct tdb *); @@ -424,6 +433,7 @@ void import_flow(struct sockaddr_encap *, struct sockaddr_encap *, struct sadb_address *, struct sadb_protocol *, struct sadb_protocol *); void import_udpencap(struct tdb *, struct sadb_x_udpencap *); void import_tag(struct tdb *, struct sadb_x_tag *); +void import_rdomain(struct tdb *, struct sadb_x_rdomain *); void import_tap(struct tdb *, struct sadb_x_tap *); #endif /* _KERNEL */ diff --git a/sys/net/pfkeyv2_convert.c b/sys/net/pfkeyv2_convert.c index c72bc152fa8..c3a53b35c80 100644 --- a/sys/net/pfkeyv2_convert.c +++ b/sys/net/pfkeyv2_convert.c @@ -840,6 +840,27 @@ export_udpencap(void **p, struct tdb *tdb) *p += sizeof(struct sadb_x_udpencap); } +/* Import rdomain switch for SA */ +void +import_rdomain(struct tdb *tdb, struct sadb_x_rdomain *srdomain) +{ + if (srdomain) + tdb->tdb_rdomain_post = srdomain->sadb_x_rdomain_dom2; +} + +/* Export rdomain switch for SA */ +void +export_rdomain(void **p, struct tdb *tdb) +{ + struct sadb_x_rdomain *srdomain = (struct sadb_x_rdomain *)*p; + + srdomain->sadb_x_rdomain_dom1 = tdb->tdb_rdomain; + srdomain->sadb_x_rdomain_dom2 = tdb->tdb_rdomain_post; + srdomain->sadb_x_rdomain_len = + sizeof(struct sadb_x_rdomain) / sizeof(uint64_t); + *p += sizeof(struct sadb_x_rdomain); +} + #if NPF > 0 /* Import PF tag information for SA */ void diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c index 2d351addd6e..20bd8960714 100644 --- a/sys/net/pfkeyv2_parsemessage.c +++ b/sys/net/pfkeyv2_parsemessage.c @@ -126,6 +126,7 @@ #define BITMAP_X_TAG (1LL << SADB_X_EXT_TAG) #define BITMAP_X_TAP (1LL << SADB_X_EXT_TAP) #define BITMAP_X_SATYPE2 (1LL << SADB_X_EXT_SATYPE2) +#define BITMAP_X_RDOMAIN (1LL << SADB_X_EXT_RDOMAIN) #define BITMAP_X_COUNTER (1LL << SADB_X_EXT_COUNTER) uint64_t sadb_exts_allowed_in[SADB_MAX+1] = @@ -135,13 +136,13 @@ uint64_t sadb_exts_allowed_in[SADB_MAX+1] = /* GETSPI */ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE, /* UPDATE */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_ADDRESS_PROXY | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_ADDRESS_PROXY | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_RDOMAIN, /* ADD */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_TAG | BITMAP_X_TAP, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_RDOMAIN, /* DELETE */ - BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_RDOMAIN, /* GET */ - BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_RDOMAIN, /* ACQUIRE */ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL, /* REGISTER */ @@ -155,11 +156,11 @@ uint64_t sadb_exts_allowed_in[SADB_MAX+1] = /* X_PROMISC */ 0, /* X_ADDFLOW */ - BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST | BITMAP_X_FLOW, + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST | BITMAP_X_FLOW | BITMAP_X_RDOMAIN, /* X_DELFLOW */ - BITMAP_X_FLOW, + BITMAP_X_FLOW | BITMAP_X_RDOMAIN, /* X_GRPSPIS */ - BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_SATYPE2, + BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_SATYPE2 | BITMAP_X_RDOMAIN, /* X_ASKPOLICY */ BITMAP_X_POLICY, }; @@ -207,13 +208,13 @@ uint64_t sadb_exts_allowed_out[SADB_MAX+1] = /* GETSPI */ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, /* UPDATE */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_ADDRESS_PROXY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_ADDRESS_PROXY | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_RDOMAIN, /* ADD */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_RDOMAIN, /* DELETE */ - BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST, + BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_RDOMAIN, /* GET */ - BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_FLOW_TYPE | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_COUNTER, + BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_FLOW_TYPE | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_TAG | BITMAP_X_TAP | BITMAP_X_COUNTER | BITMAP_X_RDOMAIN, /* ACQUIRE */ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL, /* REGISTER */ @@ -227,11 +228,11 @@ uint64_t sadb_exts_allowed_out[SADB_MAX+1] = /* X_PROMISC */ 0, /* X_ADDFLOW */ - BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST, + BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST | BITMAP_X_RDOMAIN, /* X_DELFLOW */ - BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE, + BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE | BITMAP_X_RDOMAIN, /* X_GRPSPIS */ - BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_SATYPE2, + BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_SATYPE2 | BITMAP_X_RDOMAIN, /* X_ASKPOLICY */ BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_FLOW_TYPE | BITMAP_X_POLICY, }; @@ -879,6 +880,13 @@ pfkeyv2_parsemessage(void *p, int len, void **headers) return (EINVAL); } break; + case SADB_X_EXT_RDOMAIN: + if (i != sizeof(struct sadb_x_rdomain)) { + DPRINTF(("pfkeyv2_parsemessage: bad RDOMAIN " + "header length\n")); + return (EINVAL); + } + break; #if NPF > 0 case SADB_X_EXT_TAG: if (i < sizeof(struct sadb_x_tag)) { diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index c27cabc82d3..32da310545e 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -84,7 +84,7 @@ void tdb_timeout(void *); void tdb_firstuse(void *); void tdb_soft_timeout(void *); void tdb_soft_firstuse(void *); -int tdb_hash(u_int, u_int32_t, union sockaddr_union *, u_int8_t); +int tdb_hash(u_int32_t, union sockaddr_union *, u_int8_t); int ipsec_in_use = 0; u_int64_t ipsec_last_added = 0; @@ -185,7 +185,7 @@ static int tdb_count; * so we cannot be DoS-attacked via choosing of the data to hash. */ int -tdb_hash(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, +tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) { SIPHASH_CTX ctx; @@ -193,7 +193,6 @@ tdb_hash(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, NET_ASSERT_LOCKED(); SipHash24_Init(&ctx, &tdbkey); - SipHash24_Update(&ctx, &rdomain, sizeof(rdomain)); SipHash24_Update(&ctx, &spi, sizeof(spi)); SipHash24_Update(&ctx, &proto, sizeof(proto)); SipHash24_Update(&ctx, dst, dst->sa.sa_len); @@ -306,7 +305,8 @@ reserve_spi(u_int rdomain, u_int32_t sspi, u_int32_t tspi, * is really one of our addresses if we received the packet! */ struct tdb * -gettdb(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) +gettdb_dir(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto, + int reverse) { u_int32_t hashval; struct tdb *tdbp; @@ -316,11 +316,12 @@ gettdb(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) if (tdbh == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(rdomain, spi, dst, proto); + hashval = tdb_hash(spi, dst, proto); for (tdbp = tdbh[hashval]; tdbp != NULL; tdbp = tdbp->tdb_hnext) if ((tdbp->tdb_spi == spi) && (tdbp->tdb_sproto == proto) && - (tdbp->tdb_rdomain == rdomain) && + ((!reverse && tdbp->tdb_rdomain == rdomain) || + (reverse && tdbp->tdb_rdomain_post == rdomain)) && !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) break; @@ -333,8 +334,8 @@ gettdb(u_int rdomain, u_int32_t spi, union sockaddr_union *dst, u_int8_t proto) * matches all SPIs. */ struct tdb * -gettdbbysrcdst(u_int rdomain, u_int32_t spi, union sockaddr_union *src, - union sockaddr_union *dst, u_int8_t proto) +gettdbbysrcdst_dir(u_int rdomain, u_int32_t spi, union sockaddr_union *src, + union sockaddr_union *dst, u_int8_t proto, int reverse) { u_int32_t hashval; struct tdb *tdbp; @@ -345,12 +346,13 @@ gettdbbysrcdst(u_int rdomain, u_int32_t spi, union sockaddr_union *src, if (tdbsrc == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(rdomain, 0, src, proto); + hashval = tdb_hash(0, src, proto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if (tdbp->tdb_sproto == proto && (spi == 0 || tdbp->tdb_spi == spi) && - (tdbp->tdb_rdomain == rdomain) && + ((!reverse && tdbp->tdb_rdomain == rdomain) || + (reverse && tdbp->tdb_rdomain_post == rdomain)) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC || !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) && @@ -362,12 +364,13 @@ gettdbbysrcdst(u_int rdomain, u_int32_t spi, union sockaddr_union *src, memset(&su_null, 0, sizeof(su_null)); su_null.sa.sa_len = sizeof(struct sockaddr); - hashval = tdb_hash(rdomain, 0, &su_null, proto); + hashval = tdb_hash(0, &su_null, proto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if (tdbp->tdb_sproto == proto && (spi == 0 || tdbp->tdb_spi == spi) && - (tdbp->tdb_rdomain == rdomain) && + ((!reverse && tdbp->tdb_rdomain == rdomain) || + (reverse && tdbp->tdb_rdomain_post == rdomain)) && ((tdbp->tdb_flags & TDBF_INVALID) == 0) && (tdbp->tdb_dst.sa.sa_family == AF_UNSPEC || !memcmp(&tdbp->tdb_dst, dst, dst->sa.sa_len)) && @@ -431,7 +434,7 @@ gettdbbydst(u_int rdomain, union sockaddr_union *dst, u_int8_t sproto, if (tdbdst == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(rdomain, 0, dst, sproto); + hashval = tdb_hash(0, dst, sproto); for (tdbp = tdbdst[hashval]; tdbp != NULL; tdbp = tdbp->tdb_dnext) if ((tdbp->tdb_sproto == sproto) && @@ -464,7 +467,7 @@ gettdbbysrc(u_int rdomain, union sockaddr_union *src, u_int8_t sproto, if (tdbsrc == NULL) return (struct tdb *) NULL; - hashval = tdb_hash(rdomain, 0, src, sproto); + hashval = tdb_hash(0, src, sproto); for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext) if ((tdbp->tdb_sproto == sproto) && @@ -620,8 +623,7 @@ tdb_rehash(void) for (i = 0; i <= old_hashmask; i++) { for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp) { tdbnp = tdbp->tdb_hnext; - hashval = tdb_hash(tdbp->tdb_rdomain, - tdbp->tdb_spi, &tdbp->tdb_dst, + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); tdbp->tdb_hnext = new_tdbh[hashval]; new_tdbh[hashval] = tdbp; @@ -629,18 +631,14 @@ tdb_rehash(void) for (tdbp = tdbdst[i]; tdbp != NULL; tdbp = tdbnp) { tdbnp = tdbp->tdb_dnext; - hashval = tdb_hash(tdbp->tdb_rdomain, - 0, &tdbp->tdb_dst, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); tdbp->tdb_dnext = new_tdbdst[hashval]; new_tdbdst[hashval] = tdbp; } for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp) { tdbnp = tdbp->tdb_snext; - hashval = tdb_hash(tdbp->tdb_rdomain, - 0, &tdbp->tdb_src, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); tdbp->tdb_snext = new_srcaddr[hashval]; new_srcaddr[hashval] = tdbp; } @@ -676,8 +674,7 @@ puttdb(struct tdb *tdbp) M_TDB, M_WAITOK | M_ZERO); } - hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi, - &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); /* * Rehash if this tdb would cause a bucket to have more than @@ -690,20 +687,18 @@ puttdb(struct tdb *tdbp) if (tdbh[hashval] != NULL && tdbh[hashval]->tdb_hnext != NULL && tdb_count * 10 > tdb_hashmask + 1) { tdb_rehash(); - hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi, - &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, + tdbp->tdb_sproto); } tdbp->tdb_hnext = tdbh[hashval]; tdbh[hashval] = tdbp; - hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_dst, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); tdbp->tdb_dnext = tdbdst[hashval]; tdbdst[hashval] = tdbp; - hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); tdbp->tdb_snext = tdbsrc[hashval]; tdbsrc[hashval] = tdbp; @@ -727,8 +722,7 @@ tdb_unlink(struct tdb *tdbp) if (tdbh == NULL) return; - hashval = tdb_hash(tdbp->tdb_rdomain, tdbp->tdb_spi, - &tdbp->tdb_dst, tdbp->tdb_sproto); + hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto); if (tdbh[hashval] == tdbp) { tdbh[hashval] = tdbp->tdb_hnext; @@ -744,8 +738,7 @@ tdb_unlink(struct tdb *tdbp) tdbp->tdb_hnext = NULL; - hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_dst, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto); if (tdbdst[hashval] == tdbp) { tdbdst[hashval] = tdbp->tdb_dnext; @@ -761,8 +754,7 @@ tdb_unlink(struct tdb *tdbp) tdbp->tdb_dnext = NULL; - hashval = tdb_hash(tdbp->tdb_rdomain, 0, &tdbp->tdb_src, - tdbp->tdb_sproto); + hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto); if (tdbsrc[hashval] == tdbp) { tdbsrc[hashval] = tdbp->tdb_snext; @@ -816,6 +808,7 @@ tdb_alloc(u_int rdomain) /* Save routing domain */ tdbp->tdb_rdomain = rdomain; + tdbp->tdb_rdomain_post = rdomain; /* Initialize timeouts. */ timeout_set_proc(&tdbp->tdb_timer_tmo, tdb_timeout, tdbp); diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index 49c9d661d57..0917af9f35c 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -409,6 +409,7 @@ struct tdb { /* tunnel descriptor block */ u_int32_t tdb_tap; /* Alternate enc(4) interface */ u_int tdb_rdomain; /* Routing domain */ + u_int tdb_rdomain_post; /* Change domain */ struct sockaddr_encap tdb_filter; /* What traffic is acceptable */ struct sockaddr_encap tdb_filtermask; /* And the mask */ @@ -574,15 +575,19 @@ int spd_table_walk(unsigned int, /* TDB management routines */ uint32_t reserve_spi(u_int, u_int32_t, u_int32_t, union sockaddr_union *, union sockaddr_union *, u_int8_t, int *); -struct tdb *gettdb(u_int, u_int32_t, union sockaddr_union *, u_int8_t); +struct tdb *gettdb_dir(u_int, u_int32_t, union sockaddr_union *, u_int8_t, int); +#define gettdb(a,b,c,d) gettdb_dir((a),(b),(c),(d),0) +#define gettdb_rev(a,b,c,d) gettdb_dir((a),(b),(c),(d),1) struct tdb *gettdbbydst(u_int, union sockaddr_union *, u_int8_t, struct ipsec_ids *, struct sockaddr_encap *, struct sockaddr_encap *); struct tdb *gettdbbysrc(u_int, union sockaddr_union *, u_int8_t, struct ipsec_ids *, struct sockaddr_encap *, struct sockaddr_encap *); -struct tdb *gettdbbysrcdst(u_int, u_int32_t, union sockaddr_union *, - union sockaddr_union *, u_int8_t); +struct tdb *gettdbbysrcdst_dir(u_int, u_int32_t, union sockaddr_union *, + union sockaddr_union *, u_int8_t, int); +#define gettdbbysrcdst(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),0) +#define gettdbbysrcdst_rev(a,b,c,d,e) gettdbbysrcdst_dir((a),(b),(c),(d),(e),1) void puttdb(struct tdb *); void tdb_delete(struct tdb *); struct tdb *tdb_alloc(u_int); diff --git a/sys/netinet/ipsec_input.c b/sys/netinet/ipsec_input.c index b6d0083af40..fcf4ba3d309 100644 --- a/sys/netinet/ipsec_input.c +++ b/sys/netinet/ipsec_input.c @@ -299,7 +299,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto, } if (sproto != IPPROTO_IPCOMP) { - if ((encif = enc_getif(tdbp->tdb_rdomain, + if ((encif = enc_getif(tdbp->tdb_rdomain_post, tdbp->tdb_tap)) == NULL) { DPRINTF(("%s: no enc%u interface for SA %s/%08x/%u\n", __func__, @@ -657,6 +657,8 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff) pf_tag_packet(m, tdbp->tdb_tag, -1); pf_pkt_addr_changed(m); #endif + if (tdbp->tdb_rdomain != tdbp->tdb_rdomain_post) + m->m_pkthdr.ph_rtableid = tdbp->tdb_rdomain_post; if (tdbp->tdb_flags & TDBF_TUNNELING) m->m_flags |= M_TUNNEL; @@ -665,7 +667,7 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff) tdbp->tdb_idecompbytes += m->m_pkthdr.len; #if NBPFILTER > 0 - if ((encif = enc_getif(tdbp->tdb_rdomain, tdbp->tdb_tap)) != NULL) { + if ((encif = enc_getif(tdbp->tdb_rdomain_post, tdbp->tdb_tap)) != NULL) { encif->if_ipackets++; encif->if_ibytes += m->m_pkthdr.len; @@ -966,7 +968,7 @@ ipsec_common_ctlinput(u_int rdomain, int cmd, struct sockaddr *sa, memcpy(&spi, (caddr_t)ip + hlen, sizeof(u_int32_t)); - tdbp = gettdb(rdomain, spi, (union sockaddr_union *)&dst, + tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst, proto); if (tdbp == NULL || tdbp->tdb_flags & TDBF_INVALID) return; @@ -1025,7 +1027,8 @@ udpencap_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) src.sin_addr.s_addr = ip->ip_src.s_addr; su_src = (union sockaddr_union *)&src; - tdbp = gettdbbysrcdst(rdomain, 0, su_src, su_dst, IPPROTO_ESP); + tdbp = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst, + IPPROTO_ESP); for (; tdbp != NULL; tdbp = tdbp->tdb_snext) { if (tdbp->tdb_sproto == IPPROTO_ESP && diff --git a/sys/netinet/ipsec_output.c b/sys/netinet/ipsec_output.c index 28ff5b92781..436998f097d 100644 --- a/sys/netinet/ipsec_output.c +++ b/sys/netinet/ipsec_output.c @@ -592,6 +592,8 @@ ipsp_process_done(struct mbuf *m, struct tdb *tdb) pf_tag_packet(m, tdb->tdb_tag, -1); pf_pkt_addr_changed(m); #endif + if (tdb->tdb_rdomain != tdb->tdb_rdomain_post) + m->m_pkthdr.ph_rtableid = tdb->tdb_rdomain_post; /* * We're done with IPsec processing, transmit the packet using the