diff options
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c')
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c | 247 |
1 files changed, 72 insertions, 175 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index 47523160b..1c4b60317 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -95,12 +95,6 @@ #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + \ NLMSG_ALIGN(sizeof(x)))) /** - * Returns a pointer to the next rtattr following rta. - * !!! Do not use this to parse messages. Use RTA_NEXT and RTA_OK instead !!! - */ -#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + \ - RTA_ALIGN((rta)->rta_len))) -/** * Returns the total size of attached rta data * (after 'usual' netlink data x like 'struct xfrm_usersa_info') */ @@ -1223,8 +1217,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->lft.soft_use_expires_seconds = 0; sa->lft.hard_use_expires_seconds = 0; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info); - switch (enc_alg) { case ENCR_UNDEFINED: @@ -1257,24 +1249,17 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_type = XFRMA_ALG_AEAD; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + - enc_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD, + sizeof(*algo) + enc_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; algo->alg_icv_len = icv_size; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); - - rthdr = XFRM_RTA_NEXT(rthdr); break; } default: @@ -1291,22 +1276,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_type = XFRMA_ALG_CRYPT; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT, + sizeof(*algo) + enc_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); - - rthdr = XFRM_RTA_NEXT(rthdr); } } @@ -1344,17 +1323,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, /* the kernel uses SHA256 with 96 bit truncation by default, * use specified truncation size supported by newer kernels. * also use this for untruncated MD5 and SHA1. */ - rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) + - int_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC, + sizeof(*algo) + int_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; algo->alg_trunc_len = trunc_len; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); @@ -1365,27 +1339,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo* algo; - rthdr->rta_type = XFRMA_ALG_AUTH; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH, + sizeof(*algo) + int_key.len); + if (!algo) { goto failed; } - - algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, int_key.ptr, int_key.len); } - rthdr = XFRM_RTA_NEXT(rthdr); } if (ipcomp != IPCOMP_NONE) { - rthdr->rta_type = XFRMA_ALG_COMP; + struct xfrm_algo* algo; + alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); if (alg_name == NULL) { @@ -1396,34 +1366,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t, DBG2(DBG_KNL, " using compression algorithm %N", ipcomp_transform_names, ipcomp); - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_COMP, + sizeof(*algo)); + if (!algo) { goto failed; } - - struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = 0; strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; - - rthdr = XFRM_RTA_NEXT(rthdr); } if (encap) { struct xfrm_encap_tmpl *tmpl; - rthdr->rta_type = XFRMA_ENCAP; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); + if (!tmpl) { goto failed; } - - tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr); tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_sport = htons(src->get_port(src)); tmpl->encap_dport = htons(dst->get_port(dst)); @@ -1438,43 +1400,32 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * No. The reason the kernel ignores NAT-OA is that it recomputes * (or, rather, just ignores) the checksum. If packets pass the IPsec * checks it marks them "checksum ok" so OA isn't needed. */ - rthdr = XFRM_RTA_NEXT(rthdr); } if (mark.value) { struct xfrm_mark *mrk; - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { goto failed; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; - rthdr = XFRM_RTA_NEXT(rthdr); } if (tfc) { u_int32_t *tfcpad; - rthdr->rta_type = XFRMA_TFCPAD; - rthdr->rta_len = RTA_LENGTH(sizeof(u_int32_t)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD, + sizeof(*tfcpad)); + if (!tfcpad) { goto failed; } - - tfcpad = (u_int32_t*)RTA_DATA(rthdr); *tfcpad = tfc; - rthdr = XFRM_RTA_NEXT(rthdr); } if (protocol != IPPROTO_COMP) @@ -1485,24 +1436,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t, * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */ struct xfrm_replay_state_esn *replay; - rthdr->rta_type = XFRMA_REPLAY_ESN_VAL; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + - (this->replay_window + 7) / 8); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL, + sizeof(*replay) + (this->replay_window + 7) / 8); + if (!replay) { goto failed; } - - replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr); /* bmp_len contains number uf __u32's */ replay->bmp_len = this->replay_bmp; replay->replay_window = this->replay_window; DBG2(DBG_KNL, " using replay window of %u packets", this->replay_window); - rthdr = XFRM_RTA_NEXT(rthdr); if (esn) { DBG2(DBG_KNL, " using extended sequence numbers (ESN)"); @@ -1577,17 +1522,12 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1678,17 +1618,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1781,17 +1716,12 @@ METHOD(kernel_ipsec_t, del_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1863,17 +1793,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -1945,7 +1870,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = XFRM_RTA(out, struct xfrm_usersa_info); rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info); - while(RTA_OK(rta, rtasize)) + while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ if (rta->rta_type != XFRMA_ENCAP || new_encap) @@ -1964,53 +1889,42 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = RTA_NEXT(rta, rtasize); } - rta = (struct rtattr*)pos; if (tmpl == NULL && new_encap) { /* add tmpl if we are enabling it */ - rta->rta_type = XFRMA_ENCAP; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); + if (!tmpl) { goto failed; } - - tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta); tmpl->encap_type = UDP_ENCAP_ESPINUDP; tmpl->encap_sport = ntohs(new_src->get_port(new_src)); tmpl->encap_dport = ntohs(new_dst->get_port(new_dst)); memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); - - rta = XFRM_RTA_NEXT(rta); } if (replay_esn) { - rta->rta_type = XFRMA_REPLAY_ESN_VAL; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) + - this->replay_bmp); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + struct xfrm_replay_state_esn *state; + + state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL, + sizeof(*state) + this->replay_bmp); + if (!state) { goto failed; } - memcpy(RTA_DATA(rta), replay_esn, - sizeof(struct xfrm_replay_state_esn) + this->replay_bmp); - - rta = XFRM_RTA_NEXT(rta); + memcpy(state, replay_esn, sizeof(*state) + this->replay_bmp); } else if (replay) { - rta->rta_type = XFRMA_REPLAY_VAL; - rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rta->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + struct xfrm_replay_state *state; + + state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_VAL, + sizeof(*state)); + if (!state) { goto failed; } - memcpy(RTA_DATA(rta), replay, sizeof(struct xfrm_replay_state)); - - rta = XFRM_RTA_NEXT(rta); + memcpy(state, replay, sizeof(*state)); } else { @@ -2107,11 +2021,9 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_info->lft.soft_use_expires_seconds = 0; policy_info->lft.hard_use_expires_seconds = 0; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info); - if (mapping->type == POLICY_IPSEC) { - struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr); + struct xfrm_user_tmpl *tmpl; struct { u_int8_t proto; bool use; @@ -2121,26 +2033,29 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, { IPPROTO_AH, ipsec->cfg.ah.use }, }; ipsec_mode_t proto_mode = ipsec->cfg.mode; - - rthdr->rta_type = XFRMA_TMPL; - rthdr->rta_len = 0; /* actual length is set below */ + int count = 0; for (i = 0; i < countof(protos); i++) { - if (!protos[i].use) + if (protos[i].use) { - continue; + count++; } + } + tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_TMPL, + count * sizeof(*tmpl)); + if (!tmpl) + { + this->mutex->unlock(this->mutex); + return FAILED; + } - rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + - RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl))); - if (hdr->nlmsg_len > sizeof(request)) + for (i = 0; i < countof(protos); i++) + { + if (!protos[i].use) { - this->mutex->unlock(this->mutex); - return FAILED; + continue; } - tmpl->reqid = ipsec->cfg.reqid; tmpl->id.proto = protos[i].proto; tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0; @@ -2160,25 +2075,18 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, /* use transport mode for other SAs */ proto_mode = MODE_TRANSPORT; } - - rthdr = XFRM_RTA_NEXT(rthdr); } if (ipsec->mark.value) { struct xfrm_mark *mrk; - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { this->mutex->unlock(this->mutex); return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = ipsec->mark.value; mrk->m = ipsec->mark.mask; } @@ -2410,17 +2318,12 @@ METHOD(kernel_ipsec_t, query_policy, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } @@ -2581,18 +2484,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (mark.value) { struct xfrm_mark *mrk; - struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id); - rthdr->rta_type = XFRMA_MARK; - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark)); - hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(rthdr->rta_len); - if (hdr->nlmsg_len > sizeof(request)) + mrk = netlink_reserve(hdr, sizeof(request), XFRMA_MARK, sizeof(*mrk)); + if (!mrk) { - this->mutex->unlock(this->mutex); return FAILED; } - - mrk = (struct xfrm_mark*)RTA_DATA(rthdr); mrk->v = mark.value; mrk->m = mark.mask; } |