diff options
author | Matthew Smith <mgsmith@netgate.com> | 2019-04-22 17:30:13 -0500 |
---|---|---|
committer | Ole Trøan <otroan@employees.org> | 2019-04-26 11:19:21 +0000 |
commit | aaed170828dfdb3d62295b76fd617f794dc76b3f (patch) | |
tree | d23842dbe40026a9ea26c994eb24ef8316c9135f | |
parent | 6825bc11287fd48b9ff2a4236446db5426b78c93 (diff) |
nat: fix ED mode unknown proto session management
In endpoint dependent mode, when a session at the head of a user
LRU is reused, if the IP protocol for that session was unknown (any
other than tcp, udp, or icmp), the attempt to delete the session
mapping from the in2out bihash was not using the same key that was
used when the mapping was added. This would cause the deletion of
the mapping to fail. If packets arrive later which match the original
session, the search for the session key would succeed when it should
have failed and the session, which is now associated with a different
pair of endpoints, may end up being updated when it should not be.
Update the key generation when reallocating an existing session to
do the right thing if the session is for an unknown protocol.
Also update format_nat_session() for unknown protocols so that
'vppctl show nat44 session detail' will display the protocol
correctly. In endpoint dependent mode, the IP protocol is stored in
the port field on a session if the protocol is unknown. The value
is stored in host byte order, but the format function was swapping
the bytes before writing the protocol.
Change-Id: I9e8daadd4569cb2610532dab4e4f41d1567cf3d1
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
-rwxr-xr-x | src/plugins/nat/nat.c | 15 | ||||
-rw-r--r-- | src/plugins/nat/nat_format.c | 6 | ||||
-rw-r--r-- | src/plugins/nat/out2in_ed.c | 11 |
3 files changed, 24 insertions, 8 deletions
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 97e2df1568e..249df38a3b5 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -188,11 +188,20 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, if (is_fwd_bypass_session (s)) { + if (snat_is_unk_proto_session (s)) + { + ed_key.proto = s->in2out.port; + ed_key.r_port = 0; + ed_key.l_port = 0; + } + else + { + ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); + ed_key.l_port = s->in2out.port; + ed_key.r_port = s->ext_host_port; + } ed_key.l_addr = s->in2out.addr; ed_key.r_addr = s->ext_host_addr; - ed_key.l_port = s->in2out.port; - ed_key.r_port = s->ext_host_port; - ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); ed_key.fib_index = 0; ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c index 8452940898d..7dcdff6c769 100644 --- a/src/plugins/nat/nat_format.c +++ b/src/plugins/nat/nat_format.c @@ -124,12 +124,10 @@ format_snat_session (u8 * s, va_list * args) { s = format (s, " i2o %U proto %u fib %u\n", format_ip4_address, &sess->in2out.addr, - clib_net_to_host_u16 (sess->in2out.port), - sess->in2out.fib_index); + sess->in2out.port, sess->in2out.fib_index); s = format (s, " o2i %U proto %u fib %u\n", format_ip4_address, &sess->out2in.addr, - clib_net_to_host_u16 (sess->out2in.port), - sess->out2in.fib_index); + sess->out2in.port, sess->out2in.fib_index); } else { diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c index 41f9bfe262e..06e72f31a1b 100644 --- a/src/plugins/nat/out2in_ed.c +++ b/src/plugins/nat/out2in_ed.c @@ -452,6 +452,8 @@ create_bypass_for_fwd (snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, } else { + u32 proto; + if (PREDICT_FALSE (maximum_sessions_exceeded (sm, thread_index))) return; @@ -471,12 +473,19 @@ create_bypass_for_fwd (snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, return; } + proto = ip_proto_to_snat_proto (key.proto); + s->ext_host_addr = key.r_addr; s->ext_host_port = key.r_port; s->flags |= SNAT_SESSION_FLAG_FWD_BYPASS; s->out2in.addr = key.l_addr; s->out2in.port = key.l_port; - s->out2in.protocol = ip_proto_to_snat_proto (key.proto); + s->out2in.protocol = proto; + if (proto == ~0) + { + s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; + s->out2in.port = ip->protocol; + } s->out2in.fib_index = 0; s->in2out = s->out2in; user_session_increment (sm, u, 0); |