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