diff options
Diffstat (limited to 'src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c')
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 112 |
1 files changed, 72 insertions, 40 deletions
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 00ab5ab5a..3b32ba553 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -1296,7 +1296,8 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, { pfkey_msg_t response; u_int8_t protocol; - u_int32_t spi, reqid; + u_int32_t spi; + host_t *dst; bool hard; DBG2(DBG_KNL, "received an SADB_EXPIRE"); @@ -1309,18 +1310,18 @@ static void process_expire(private_kernel_pfkey_ipsec_t *this, protocol = satype2proto(msg->sadb_msg_satype); spi = response.sa->sadb_sa_spi; - reqid = response.x_sa2->sadb_x_sa2_reqid; hard = response.lft_hard != NULL; - if (protocol != IPPROTO_ESP && protocol != IPPROTO_AH) + if (protocol == IPPROTO_ESP || protocol == IPPROTO_AH) { - DBG2(DBG_KNL, "ignoring SADB_EXPIRE for SA with SPI %.8x and " - "reqid {%u} which is not a CHILD_SA", ntohl(spi), reqid); - return; + dst = host_create_from_sockaddr((sockaddr_t*)(response.dst + 1)); + if (dst) + { + hydra->kernel_interface->expire(hydra->kernel_interface, protocol, + spi, dst, hard); + dst->destroy(dst); + } } - - hydra->kernel_interface->expire(hydra->kernel_interface, reqid, protocol, - spi, hard); } #ifdef SADB_X_MIGRATE @@ -1387,9 +1388,9 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, struct sadb_msg* msg) { pfkey_msg_t response; - u_int32_t spi, reqid; + u_int32_t spi; sockaddr_t *sa; - host_t *host; + host_t *dst, *new; DBG2(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING"); @@ -1407,7 +1408,6 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, } spi = response.sa->sadb_sa_spi; - reqid = response.x_sa2->sadb_x_sa2_reqid; if (satype2proto(msg->sadb_msg_satype) != IPPROTO_ESP) { @@ -1415,6 +1415,7 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, } sa = (sockaddr_t*)(response.dst + 1); + dst = host_create_from_sockaddr(sa); switch (sa->sa_family) { case AF_INET: @@ -1432,12 +1433,16 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, default: break; } - - host = host_create_from_sockaddr(sa); - if (host) + if (dst) { - hydra->kernel_interface->mapping(hydra->kernel_interface, reqid, - spi, host); + new = host_create_from_sockaddr(sa); + if (new) + { + hydra->kernel_interface->mapping(hydra->kernel_interface, + IPPROTO_ESP, spi, dst, new); + new->destroy(new); + } + dst->destroy(dst); } } #endif /*SADB_X_NAT_T_NEW_MAPPING*/ @@ -1518,11 +1523,10 @@ static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd, static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, u_int8_t proto, u_int32_t min, u_int32_t max, - u_int32_t reqid, u_int32_t *spi) + u_int32_t *spi) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; - struct sadb_x_sa2 *sa2; struct sadb_spirange *range; pfkey_msg_t response; u_int32_t received_spi = 0; @@ -1536,12 +1540,6 @@ static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this, msg->sadb_msg_satype = proto2satype(proto); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); - sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); - sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; - sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange)); - sa2->sadb_x_sa2_reqid = reqid; - PFKEY_EXT_ADD(msg, sa2); - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); @@ -1577,39 +1575,37 @@ static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this, METHOD(kernel_ipsec_t, get_spi, status_t, private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) + u_int8_t protocol, u_int32_t *spi) { - DBG2(DBG_KNL, "getting SPI for reqid {%u}", reqid); - if (get_spi_internal(this, src, dst, protocol, - 0xc0000000, 0xcFFFFFFF, reqid, spi) != SUCCESS) + 0xc0000000, 0xcFFFFFFF, spi) != SUCCESS) { - DBG1(DBG_KNL, "unable to get SPI for reqid {%u}", reqid); + DBG1(DBG_KNL, "unable to get SPI"); return FAILED; } - DBG2(DBG_KNL, "got SPI %.8x for reqid {%u}", ntohl(*spi), reqid); + DBG2(DBG_KNL, "got SPI %.8x", ntohl(*spi)); return SUCCESS; } METHOD(kernel_ipsec_t, get_cpi, status_t, private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, - u_int32_t reqid, u_int16_t *cpi) + u_int16_t *cpi) { u_int32_t received_spi = 0; - DBG2(DBG_KNL, "getting CPI for reqid {%u}", reqid); + DBG2(DBG_KNL, "getting CPI"); if (get_spi_internal(this, src, dst, IPPROTO_COMP, - 0x100, 0xEFFF, reqid, &received_spi) != SUCCESS) + 0x100, 0xEFFF, &received_spi) != SUCCESS) { - DBG1(DBG_KNL, "unable to get CPI for reqid {%u}", reqid); + DBG1(DBG_KNL, "unable to get CPI"); return FAILED; } *cpi = htons((u_int16_t)ntohl(received_spi)); - DBG2(DBG_KNL, "got CPI %.4x for reqid {%u}", ntohs(*cpi), reqid); + DBG2(DBG_KNL, "got CPI %.4x", ntohs(*cpi)); return SUCCESS; } @@ -1619,8 +1615,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window, - bool initiator, bool encap, bool esn, bool inbound, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts) + bool initiator, bool encap, bool esn, bool inbound, bool update, + linked_list_t *src_ts, linked_list_t *dst_ts) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -1638,12 +1634,29 @@ METHOD(kernel_ipsec_t, add_sa, status_t, add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark, tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty, mode, ipcomp, 0, 0, FALSE, FALSE, FALSE, inbound, - NULL, NULL); + update, NULL, NULL); ipcomp = IPCOMP_NONE; /* use transport mode ESP SA, IPComp uses tunnel mode */ mode = MODE_TRANSPORT; } + if (update) + { + /* As we didn't know the reqid during SPI allocation, we used reqid + * zero. Unfortunately we can't SADB_UPDATE to the new reqid, hence we + * have to delete the SPI allocation state manually. The reqid + * selector does not count for that, therefore we have to delete + * that state before installing the new SA to avoid deleting the + * the new state after installing it. */ + mark_t zeromark = {0, 0}; + + if (this->public.interface.del_sa(&this->public.interface, + src, dst, spi, protocol, 0, zeromark) != SUCCESS) + { + DBG1(DBG_KNL, "deleting SPI allocation SA failed"); + } + } + memset(&request, 0, sizeof(request)); DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", @@ -1651,7 +1664,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, msg = (struct sadb_msg*)request; msg->sadb_msg_version = PF_KEY_V2; - msg->sadb_msg_type = inbound ? SADB_UPDATE : SADB_ADD; + msg->sadb_msg_type = SADB_ADD; msg->sadb_msg_satype = proto2satype(protocol); msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg)); @@ -1680,7 +1693,13 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } else { + /* Linux interprets sadb_sa_replay as number of packets/bits in the + * replay window, whereas on BSD it's the size of the window in bytes */ +#ifdef __linux__ sa->sadb_sa_replay = min(replay_window, 32); +#else + sa->sadb_sa_replay = (replay_window + 7) / 8; +#endif sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); } @@ -2969,6 +2988,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() { private_kernel_pfkey_ipsec_t *this; bool register_for_events = TRUE; + int rcv_buffer; INIT(this, .public = { @@ -3025,6 +3045,18 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() return NULL; } + rcv_buffer = lib->settings->get_int(lib->settings, + "%s.plugins.kernel-pfkey.events_buffer_size", 0, lib->ns); + if (rcv_buffer > 0) + { + if (setsockopt(this->socket_events, SOL_SOCKET, SO_RCVBUF, + &rcv_buffer, sizeof(rcv_buffer)) == -1) + { + DBG1(DBG_KNL, "unable to set receive buffer size on PF_KEY " + "event socket: %s", strerror(errno)); + } + } + /* register the event socket */ if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS || register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS) |