From ec112e5a9eb708c1ee85faf569fef6fa40178294 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Wed, 7 Oct 2020 23:52:37 +0000 Subject: ikev2: fix setting responder/initiator addresses Type: fix Change-Id: Ic406aa914d92e802a5fb0f27c2ffa1b98db012b0 Signed-off-by: Filip Tehlar --- src/plugins/ikev2/ikev2.c | 82 ++++++++++++------------------------ src/plugins/ikev2/ikev2_payload.c | 24 +++++++++++ src/plugins/ikev2/ikev2_priv.h | 1 + src/plugins/ikev2/test/test_ikev2.py | 55 ++++++++++++++++++------ 4 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 4b318605df3..3ce9114e358 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -640,7 +640,7 @@ ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port) clib_memcpy_fast (&buf[8], &rspi, sizeof (rspi)); clib_memcpy_fast (&buf[8 + 8], ip_addr_bytes (ia), ip_address_size (ia)); clib_memcpy_fast (&buf[8 + 8 + ip_address_size (ia)], &port, sizeof (port)); - SHA1 (buf, sizeof (buf), res); + SHA1 (buf, 2 * sizeof (ispi) + sizeof (port) + ip_address_size (ia), res); return res; } @@ -2734,11 +2734,9 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) } static_always_inline void -ikev2_set_ip_address (ikev2_sa_t * sa, const void *src, - const void *dst, const int af, const int is_initiator) +ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr, + const void *raddr, const int af) { - const void *raddr = is_initiator ? src : dst; - const void *iaddr = is_initiator ? dst : src; ip_address_set (&sa->raddr, raddr, af); ip_address_set (&sa->iaddr, iaddr, af); } @@ -2854,19 +2852,16 @@ ikev2_node_internal (vlib_main_t * vm, sa0 = &sa; clib_memset (sa0, 0, sizeof (*sa0)); - u8 is_initiator = ike0->flags & IKEV2_HDR_FLAG_INITIATOR; - if (is_initiator) + if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR) { if (ike0->rspi == 0) { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->dst_address, - &ip40->src_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->src_address, + &ip40->dst_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->dst_address, - &ip60->src_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->src_address, + &ip60->dst_address, AF_IP6); sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); @@ -2927,13 +2922,11 @@ ikev2_node_internal (vlib_main_t * vm, else //received sa_init without initiator flag { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->src_address, - &ip40->dst_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->dst_address, + &ip40->src_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->src_address, - &ip60->dst_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->dst_address, + &ip60->src_address, AF_IP6); ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); @@ -4757,33 +4750,12 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) } } -static ike_payload_header_t * -ikev2_find_ike_payload (ike_header_t * ike, u32 payload_type) -{ - int p = 0; - ike_payload_header_t *ikep; - u32 payload = ike->nextpayload; - - while (payload != IKEV2_PAYLOAD_NONE) - { - ikep = (ike_payload_header_t *) & ike->payload[p]; - if (payload == payload_type) - return ikep; - - u16 plen = clib_net_to_host_u16 (ikep->length); - payload = ikep->nextpayload; - p += plen; - } - return 0; -} - static void ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) { ikev2_profile_t *p; u32 bi0; - u8 *nat_sha; - ike_payload_header_t *ph; + u8 *nat_sha, *np; if (ip_address_is_zero (&sa->iaddr)) { @@ -4794,20 +4766,20 @@ ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) return; /* update NAT detection payload */ - ph = - ikev2_find_ike_payload ((ike_header_t *) - sa->last_sa_init_req_packet_data, - IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); - if (!ph) - return; - - nat_sha = - ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), - clib_host_to_net_u64 (sa->rspi), - &sa->iaddr, - clib_host_to_net_u16 (IKEV2_PORT)); - clib_memcpy_fast (ph->payload, nat_sha, vec_len (nat_sha)); - vec_free (nat_sha); + np = + ikev2_find_ike_notify_payload + ((ike_header_t *) sa->last_sa_init_req_packet_data, + IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); + if (np) + { + nat_sha = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), + clib_host_to_net_u64 (sa->rspi), + &sa->iaddr, + clib_host_to_net_u16 (IKEV2_PORT)); + clib_memcpy_fast (np, nat_sha, vec_len (nat_sha)); + vec_free (nat_sha); + } } if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1) diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index c03054aa9cd..294864d8c43 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -588,6 +588,30 @@ ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen) return r; } +u8 * +ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type) +{ + int p = 0; + ike_notify_payload_header_t *n; + ike_payload_header_t *ikep; + u32 payload = ike->nextpayload; + + while (payload != IKEV2_PAYLOAD_NONE) + { + ikep = (ike_payload_header_t *) & ike->payload[p]; + if (payload == IKEV2_PAYLOAD_NOTIFY) + { + n = (ike_notify_payload_header_t *)ikep; + if (n->msg_type == clib_net_to_host_u16 (msg_type)) + return n->payload; + } + u16 plen = clib_net_to_host_u16 (ikep->length); + payload = ikep->nextpayload; + p += plen; + } + return 0; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 68a546a0f48..115a5b2a6b3 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -568,6 +568,7 @@ ikev2_delete_t *ikev2_parse_delete_payload (ike_payload_header_t * ikep, ikev2_notify_t *ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen); int ikev2_set_log_level (ikev2_log_level_t log_level); +u8 *ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type); static_always_inline ikev2_main_per_thread_data_t * ikev2_get_per_thread_data () diff --git a/src/plugins/ikev2/test/test_ikev2.py b/src/plugins/ikev2/test/test_ikev2.py index 4f64b56d853..f75a517f824 100644 --- a/src/plugins/ikev2/test/test_ikev2.py +++ b/src/plugins/ikev2/test/test_ikev2.py @@ -1,4 +1,5 @@ import os +from socket import inet_pton from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, hmac @@ -510,8 +511,10 @@ class IKEv2SA(object): def esp_crypto_attr(self): return self.crypto_attr(self.esp_crypto_key_len) - def compute_nat_sha1(self, ip, port): - data = self.ispi + self.rspi + ip + (port).to_bytes(2, 'big') + def compute_nat_sha1(self, ip, port, rspi=None): + if rspi is None: + rspi = self.rspi + data = self.ispi + rspi + ip + (port).to_bytes(2, 'big') digest = hashes.Hash(hashes.SHA1(), backend=default_backend()) digest.update(data) return digest.finalize() @@ -775,6 +778,36 @@ class TemplateInitiator(IkePeer): def tearDown(self): super(TemplateInitiator, self).tearDown() + @staticmethod + def find_notify_payload(packet, notify_type): + n = packet[ikev2.IKEv2_payload_Notify] + while n is not None: + if n.type == notify_type: + return n + n = n.payload + return None + + def verify_nat_detection(self, packet): + if self.ip6: + iph = packet[IPv6] + else: + iph = packet[IP] + udp = packet[UDP] + + # NAT_DETECTION_SOURCE_IP + s = self.find_notify_payload(packet, 16388) + self.assertIsNotNone(s) + src_sha = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, iph.src), udp.sport, b'\x00' * 8) + self.assertEqual(s.load, src_sha) + + # NAT_DETECTION_DESTINATION_IP + s = self.find_notify_payload(packet, 16389) + self.assertIsNotNone(s) + dst_sha = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, iph.dst), udp.dport, b'\x00' * 8) + self.assertEqual(s.load, dst_sha) + def verify_sa_init_request(self, packet): ih = packet[ikev2.IKEv2] self.assertNotEqual(ih.init_SPI, 8 * b'\x00') @@ -798,6 +831,7 @@ class TemplateInitiator(IkePeer): self.assertEqual(prop.trans[2].transform_id, self.p.ike_transforms['dh_group']) + self.verify_nat_detection(packet) self.sa.complete_dh_data() self.sa.calc_keys() @@ -957,11 +991,6 @@ class TemplateResponder(IkePeer): props = (ikev2.IKEv2_payload_Proposal(proposal=1, proto='IKEv2', trans_nb=4, trans=trans)) - if behind_nat: - next_payload = 'Notify' - else: - next_payload = None - self.sa.init_req_packet = ( ikev2.IKEv2(init_SPI=self.sa.ispi, flags='Initiator', exch_type='IKE_SA_INIT') / @@ -969,19 +998,21 @@ class TemplateResponder(IkePeer): ikev2.IKEv2_payload_KE(next_payload='Nonce', group=self.sa.ike_dh, load=self.sa.my_dh_pub_key) / - ikev2.IKEv2_payload_Nonce(next_payload=next_payload, + ikev2.IKEv2_payload_Nonce(next_payload='Notify', load=self.sa.i_nonce)) if behind_nat: src_address = b'\x0a\x0a\x0a\x01' else: - src_address = bytes(self.pg0.local_ip4, 'ascii') + src_address = inet_pton(socket.AF_INET, self.pg0.remote_ip4) src_nat = self.sa.compute_nat_sha1(src_address, self.sa.sport) - dst_nat = self.sa.compute_nat_sha1(bytes(self.pg0.remote_ip4, 'ascii'), - self.sa.sport) + dst_nat = self.sa.compute_nat_sha1( + inet_pton(socket.AF_INET, self.pg0.local_ip4), + self.sa.dport) nat_src_detection = ikev2.IKEv2_payload_Notify( - type='NAT_DETECTION_SOURCE_IP', load=src_nat) + type='NAT_DETECTION_SOURCE_IP', load=src_nat, + next_payload='Notify') nat_dst_detection = ikev2.IKEv2_payload_Notify( type='NAT_DETECTION_DESTINATION_IP', load=dst_nat) self.sa.init_req_packet = (self.sa.init_req_packet / -- cgit 1.2.3-korg