From 42ae29a2fe9b12bbbc0c6495b2077252545c9cb9 Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Mon, 30 Apr 2018 16:39:13 -0500 Subject: NAT44 segv on unknown proto on inside interface When a packet with an unknown proto arrives on an inside interface and there are no existing sessions for the source address, a segv occurs. snat_in2out_unknown_proto() finds the head of the sessions dlist, fetches the address of the next element using head->next, and then dereferences the next element. On the first packet received from a source address, head->next is ~0, so this results in a segv. Check that the session list is not empty before trying to traverse it. Also removed unnecessary lookup against tsm->user_hash. Prior call to nat_user_get_or_create() already performed that lookup and added a user if one didn't exist. Change-Id: If73e79aa2f8e3962ab7b876ecf55aea40d7a5472 Signed-off-by: Matthew Smith --- src/plugins/nat/in2out.c | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'src/plugins/nat') diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index 786b6c6887b..3ec65e80cba 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -1217,34 +1217,37 @@ snat_in2out_unknown_proto (snat_main_t *sm, else { /* Choose same out address as for TCP/UDP session to same destination */ - if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tsm->list_pool, head_index); + elt_index = head->next; + if (PREDICT_FALSE (elt_index == ~0)) + ses_index = ~0; + else + { + elt = pool_elt_at_index (tsm->list_pool, elt_index); + ses_index = elt->value; + } + + while (ses_index != ~0) { - head_index = u->sessions_per_user_list_head_index; - head = pool_elt_at_index (tsm->list_pool, head_index); - elt_index = head->next; + s = pool_elt_at_index (tsm->sessions, ses_index); + elt_index = elt->next; elt = pool_elt_at_index (tsm->list_pool, elt_index); ses_index = elt->value; - while (ses_index != ~0) - { - s = pool_elt_at_index (tsm->sessions, ses_index); - elt_index = elt->next; - elt = pool_elt_at_index (tsm->list_pool, elt_index); - ses_index = elt->value; - if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) - { - new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; - address_index = s->outside_address_index; + if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) + { + new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; + address_index = s->outside_address_index; - key.fib_index = sm->outside_fib_index; - key.l_addr.as_u32 = new_addr; - s_kv.key[0] = key.as_u64[0]; - s_kv.key[1] = key.as_u64[1]; - if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) - break; + key.fib_index = sm->outside_fib_index; + key.l_addr.as_u32 = new_addr; + s_kv.key[0] = key.as_u64[0]; + s_kv.key[1] = key.as_u64[1]; + if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) + break; - goto create_ses; - } + goto create_ses; } } key.fib_index = sm->outside_fib_index; -- cgit 1.2.3-korg