On Mon, Apr 13, 2020 at 11:56:36AM +0200, Tobias Heider wrote: > 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 ;)
I haven't heard of any problems with this so far but I think it would be nice to have a few more test results. Also, ok? 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