From: Tobias Brunner Date: Fri, 1 Feb 2019 16:29:20 +0000 (+0100) Subject: kernel-netlink: Make interface ID configurable on SAs and policies X-Git-Tag: 5.8.0rc1~41^2~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b32c3ce8feac91a9ea5c447e03516f46c76c54b9;p=thirdparty%2Fstrongswan.git kernel-netlink: Make interface ID configurable on SAs and policies --- diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h index 4158eb45e8..70ff2eb12d 100644 --- a/src/libcharon/kernel/kernel_ipsec.h +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -55,6 +55,8 @@ struct kernel_ipsec_sa_id_t { uint8_t proto; /** Optional mark */ mark_t mark; + /** Optional interface ID */ + uint32_t if_id; }; /** @@ -154,6 +156,8 @@ struct kernel_ipsec_policy_id_t { traffic_selector_t *dst_ts; /** Optional mark */ mark_t mark; + /** Optional interface ID */ + uint32_t if_id; /** Network interface restricting policy */ char *interface; }; diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 2819cbe8b5..205e772ae2 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2018 Tobias Brunner + * Copyright (C) 2006-2019 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2008-2016 Andreas Steffen * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser @@ -430,6 +430,9 @@ struct ipsec_sa_t { /** Optional mark */ mark_t mark; + /** Optional mark */ + uint32_t if_id; + /** Description of this SA */ ipsec_sa_cfg_t cfg; @@ -445,7 +448,8 @@ static u_int ipsec_sa_hash(ipsec_sa_t *sa) return chunk_hash_inc(sa->src->get_address(sa->src), chunk_hash_inc(sa->dst->get_address(sa->dst), chunk_hash_inc(chunk_from_thing(sa->mark), - chunk_hash(chunk_from_thing(sa->cfg))))); + chunk_hash_inc(chunk_from_thing(sa->if_id), + chunk_hash(chunk_from_thing(sa->cfg)))))); } /** @@ -457,6 +461,7 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa) sa->dst->ip_equals(sa->dst, other_sa->dst) && sa->mark.value == other_sa->mark.value && sa->mark.mask == other_sa->mark.mask && + sa->if_id == other_sa->if_id && ipsec_sa_cfg_equals(&sa->cfg, &other_sa->cfg); } @@ -465,13 +470,14 @@ static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa) */ static ipsec_sa_t *ipsec_sa_create(private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, mark_t mark, - ipsec_sa_cfg_t *cfg) + uint32_t if_id, ipsec_sa_cfg_t *cfg) { ipsec_sa_t *sa, *found; INIT(sa, .src = src, .dst = dst, .mark = mark, + .if_id = if_id, .cfg = *cfg, ); found = this->sas->get(this->sas, sa); @@ -546,7 +552,7 @@ struct policy_sa_out_t { static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, mark_t mark, - ipsec_sa_cfg_t *cfg) + uint32_t if_id, ipsec_sa_cfg_t *cfg) { policy_sa_t *policy; @@ -564,7 +570,7 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, INIT(policy, .priority = 0); } policy->type = type; - policy->sa = ipsec_sa_create(this, src, dst, mark, cfg); + policy->sa = ipsec_sa_create(this, src, dst, mark, if_id, cfg); return policy; } @@ -610,6 +616,9 @@ struct policy_entry_t { /** Optional mark */ uint32_t mark; + /** Optional interface ID */ + uint32_t if_id; + /** Associated route installed for this policy */ route_entry_t *route; @@ -651,7 +660,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this, static u_int policy_hash(policy_entry_t *key) { chunk_t chunk = chunk_from_thing(key->sel); - return chunk_hash_inc(chunk, chunk_hash(chunk_from_thing(key->mark))); + return chunk_hash_inc(chunk, chunk_hash_inc(chunk_from_thing(key->mark), + chunk_hash(chunk_from_thing(key->if_id)))); } /** @@ -661,6 +671,7 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key) { return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) && key->mark == other_key->mark && + key->if_id == other_key->if_id && key->direction == other_key->direction; } @@ -1577,6 +1588,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, .spi = htonl(ntohs(data->cpi)), .proto = IPPROTO_COMP, .mark = id->mark, + .if_id = id->if_id, }; kernel_ipsec_add_sa_t ipcomp_sa = { .reqid = data->reqid, @@ -1902,6 +1914,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t, goto failed; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + goto failed; + } + if (ipcomp == IPCOMP_NONE && (data->mark.value | data->mark.mask)) { if (!add_uint32(hdr, sizeof(request), XFRMA_SET_MARK, @@ -2034,6 +2051,10 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, { return; } + if (sa->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, sa->if_id)) + { + return; + } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) { @@ -2132,6 +2153,10 @@ METHOD(kernel_ipsec_t, query_sa, status_t, { return FAILED; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + return FAILED; + } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) { @@ -2236,6 +2261,10 @@ METHOD(kernel_ipsec_t, del_sa, status_t, { return FAILED; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + return FAILED; + } switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr)) { @@ -2282,6 +2311,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, .spi = htonl(ntohs(data->cpi)), .proto = IPPROTO_COMP, .mark = id->mark, + .if_id = id->if_id, }; kernel_ipsec_update_sa_t ipcomp = { .new_src = data->new_src, @@ -2312,6 +2342,10 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { return FAILED; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + return FAILED; + } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) { @@ -2786,6 +2820,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_change_done(this, policy); return FAILED; } + if (ipsec->if_id && + !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, ipsec->if_id)) + { + policy_change_done(this, policy); + return FAILED; + } this->mutex->unlock(this->mutex); status = this->socket_xfrm->send_ack(this->socket_xfrm, hdr); @@ -2837,6 +2877,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, INIT(policy, .sel = ts2selector(id->src_ts, id->dst_ts, id->interface), .mark = id->mark.value & id->mark.mask, + .if_id = id->if_id, .direction = id->dir, .reqid = data->sa->reqid, ); @@ -2882,7 +2923,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* cache the assigned IPsec SA */ assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, - data->dst, id->src_ts, id->dst_ts, id->mark, data->sa); + data->dst, id->src_ts, id->dst_ts, id->mark, + id->if_id, data->sa); assigned_sa->auto_priority = get_priority(policy, data->prio, id->interface); assigned_sa->priority = this->get_priority ? this->get_priority(id, data) : data->manual_prio; @@ -2980,6 +3022,10 @@ METHOD(kernel_ipsec_t, query_policy, status_t, { return FAILED; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + return FAILED; + } if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) { @@ -3048,6 +3094,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, .src = data->src, .dst = data->dst, .mark = id->mark, + .if_id = id->if_id, .cfg = *data->sa, }; char markstr[32] = ""; @@ -3063,6 +3110,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, memset(&policy, 0, sizeof(policy_entry_t)); policy.sel = ts2selector(id->src_ts, id->dst_ts, id->interface); policy.mark = id->mark.value & id->mark.mask; + policy.if_id = id->if_id; policy.direction = id->dir; /* find the policy */ @@ -3153,6 +3201,11 @@ METHOD(kernel_ipsec_t, del_policy, status_t, policy_change_done(this, current); return FAILED; } + if (id->if_id && !add_uint32(hdr, sizeof(request), XFRMA_IF_ID, id->if_id)) + { + policy_change_done(this, current); + return FAILED; + } if (current->route) {