From 1e5c07d379a092f4829e7081aa962d013b31fdfc Mon Sep 17 00:00:00 2001 From: Juraj Sloboda Date: Tue, 10 Apr 2018 13:51:54 +0200 Subject: Add special Twice-NAT feature (VPP-1221) When enabled then Twice-NAT is applied only when source IP equals destination IP after DNAT Change-Id: I58a9d1d222b2a10c83eafffb2107f32c1b4aa3a8 Signed-off-by: Juraj Sloboda --- src/plugins/nat/in2out.c | 2 ++ src/plugins/nat/nat.api | 16 ++++++++++++++++ src/plugins/nat/nat.c | 25 ++++++++++++++++++------- src/plugins/nat/nat.h | 29 +++++++++++++++++++---------- src/plugins/nat/nat44_cli.c | 19 ++++++++++++------- src/plugins/nat/nat_api.c | 24 ++++++++++++++++++++---- src/plugins/nat/out2in.c | 9 +++++++-- 7 files changed, 94 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index 7d9d6c3e6c1..786b6c6887b 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -1273,6 +1273,7 @@ create_ses: s->ext_host_addr.as_u32 = ip->dst_address.as_u32; s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = address_index; s->out2in.addr.as_u32 = new_addr; s->out2in.fib_index = sm->outside_fib_index; @@ -1402,6 +1403,7 @@ snat_in2out_lb (snat_main_t *sm, s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; if (lb) s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = ~0; s->in2out = l_key; s->out2in = e_key; diff --git a/src/plugins/nat/nat.api b/src/plugins/nat/nat.api index 69b6045c4cb..23c89adef7a 100644 --- a/src/plugins/nat/nat.api +++ b/src/plugins/nat/nat.api @@ -352,6 +352,9 @@ define nat44_interface_output_feature_details { @param vfr_id - VRF ID @param twice_nat - if 1 translate external host address and port, only for 1:1 NAPT (addr_only must be 0) + @param self_twice_nat - if 1 translate external host address and port + whenever external host address equals + local address of internal host @param out2in_only - if 1 rule match only out2in direction @param tag - opaque string tag */ @@ -368,6 +371,7 @@ autoreply define nat44_add_del_static_mapping { u32 external_sw_if_index; u32 vrf_id; u8 twice_nat; + u8 self_twice_nat; u8 out2in_only; u8 tag[64]; }; @@ -392,6 +396,9 @@ define nat44_static_mapping_dump { @param external_sw_if_index - external interface @param vfr_id - VRF ID @param twice_nat - if 1 translate external host address and port + @param self_twice_nat - if 1 translate external host address and port + whenever external host address equals + local address of internal host @param out2in_only - if 1 rule match only out2in direction @param tag - opaque string tag */ @@ -406,6 +413,7 @@ define nat44_static_mapping_details { u32 external_sw_if_index; u32 vrf_id; u8 twice_nat; + u8 self_twice_nat; u8 out2in_only; u8 tag[64]; }; @@ -584,6 +592,9 @@ typeonly manual_endian define nat44_lb_addr_port { @param protocol - IP protocol number of the service @param vrf_id - internal network VRF ID @param twice_nat - if 1 translate external host address and port + @param self_twice_nat - if 1 translate external host address and port + whenever external host address equals + local address of internal host @param out2in_only - if 1 rule match only out2in direction @param tag - opaque string tag @param local_num - number of local network nodes @@ -598,6 +609,7 @@ autoreply manual_endian define nat44_add_del_lb_static_mapping { u8 protocol; u32 vrf_id; u8 twice_nat; + u8 self_twice_nat; u8 out2in_only; u8 tag[64]; u8 local_num; @@ -621,6 +633,9 @@ define nat44_lb_static_mapping_dump { @param protocol - IP protocol number of the service @param vrf_id - internal network VRF ID @param twice_nat - if 1 translate external host address and port + @param self_twice_nat - if 1 translate external host address and port + whenever external host address equals + local address of internal host @param out2in_only - if 1 rule match only out2in direction @param tag - opaque string tag @param local_num - number of local network nodes @@ -633,6 +648,7 @@ manual_endian define nat44_lb_static_mapping_details { u8 protocol; u32 vrf_id; u8 twice_nat; + u8 self_twice_nat; u8 out2in_only; u8 tag[64]; u8 local_num; diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 51fbb1336e1..499f3a242cb 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -669,7 +669,11 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, * @param addr_only If 0 address port and pair mapping, otherwise address only. * @param sw_if_index External port instead of specific IP address. * @param is_add If 0 delete static mapping, otherwise add. - * @param twice_nat If 1 translate external host address and port. + * @param twice_nat If value is TWICE_NAT then translate external host address + * and port. + * If value is TWICE_NAT_SELF then translate external host + * address and port whenever external host address equals + * local address of internal host. * @param out2in_only If 1 rule match only out2in direction * @param tag - opaque string tag * @@ -678,7 +682,8 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, - u8 twice_nat, u8 out2in_only, u8 * tag) + twice_nat_type_t twice_nat, u8 out2in_only, + u8 * tag) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; @@ -1159,7 +1164,8 @@ static int lb_local_exists (nat44_lb_addr_port_t * local, int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add, - u8 twice_nat, u8 out2in_only, u8 *tag) + twice_nat_type_t twice_nat, u8 out2in_only, + u8 *tag) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; @@ -1993,7 +1999,7 @@ int snat_static_mapping_match (snat_main_t * sm, snat_session_key_t * mapping, u8 by_external, u8 *is_addr_only, - u8 *twice_nat, + twice_nat_type_t *twice_nat, u8 *lb) { clib_bihash_kv_8_8_t kv, value; @@ -2741,7 +2747,9 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) s = format (s, "local %U external %U vrf %d %s", format_ip4_address, &m->local_addr, format_ip4_address, &m->external_addr, - m->vrf_id, m->twice_nat ? "twice-nat" : ""); + m->vrf_id, + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : ""); else { if (vec_len (m->locals)) @@ -2750,7 +2758,8 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) format_snat_protocol, m->proto, m->vrf_id, format_ip4_address, &m->external_addr, m->external_port, - m->twice_nat ? "twice-nat" : "", + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", m->out2in_only ? "out2in-only" : ""); vec_foreach (local, m->locals) s = format (s, "\n local %U:%d probability %d\%", @@ -2762,7 +2771,9 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) format_snat_protocol, m->proto, format_ip4_address, &m->local_addr, m->local_port, format_ip4_address, &m->external_addr, m->external_port, - m->vrf_id, m->twice_nat ? "twice-nat" : "", + m->vrf_id, + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", m->out2in_only ? "out2in-only" : ""); } return s; diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 8d7d1738fb3..775376fcbab 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -125,11 +125,12 @@ typedef enum { } snat_session_state_t; -#define SNAT_SESSION_FLAG_STATIC_MAPPING 1 -#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2 -#define SNAT_SESSION_FLAG_LOAD_BALANCING 4 -#define SNAT_SESSION_FLAG_TWICE_NAT 8 -#define SNAT_SESSION_FLAG_FWD_BYPASS 16 +#define SNAT_SESSION_FLAG_STATIC_MAPPING 1 +#define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2 +#define SNAT_SESSION_FLAG_LOAD_BALANCING 4 +#define SNAT_SESSION_FLAG_TWICE_NAT 8 +#define SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT 16 +#define SNAT_SESSION_FLAG_FWD_BYPASS 32 #define NAT_INTERFACE_FLAG_IS_INSIDE 1 #define NAT_INTERFACE_FLAG_IS_OUTSIDE 2 @@ -211,13 +212,19 @@ typedef struct { u8 prefix; } nat44_lb_addr_port_t; +typedef enum { + TWICE_NAT_DISABLED, + TWICE_NAT, + TWICE_NAT_SELF, +} twice_nat_type_t; + typedef struct { ip4_address_t local_addr; ip4_address_t external_addr; u16 local_port; u16 external_port; u8 addr_only; - u8 twice_nat; + twice_nat_type_t twice_nat; u8 out2in_only; u32 vrf_id; u32 fib_index; @@ -422,7 +429,7 @@ int snat_static_mapping_match (snat_main_t * sm, snat_session_key_t * mapping, u8 by_external, u8 *is_addr_only, - u8 *twice_nat, + twice_nat_type_t *twice_nat, u8 *lb); void snat_add_del_addr_to_fib (ip4_address_t * addr, @@ -474,7 +481,7 @@ typedef struct { @param s NAT session @return 1 if NAT session is endpoint dependent */ -#define is_ed_session(s) (snat_is_unk_proto_session (s) || is_twice_nat_session (s) || is_lb_session (s)) +#define is_ed_session(s) (s->flags & SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT) #define nat_interface_is_inside(i) i->flags & NAT_INTERFACE_FLAG_IS_INSIDE #define nat_interface_is_outside(i) i->flags & NAT_INTERFACE_FLAG_IS_OUTSIDE @@ -558,7 +565,8 @@ void nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add); int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, - u8 twice_nat, u8 out2in_only, u8 *tag); + twice_nat_type_t twice_nat, u8 out2in_only, + u8 *tag); clib_error_t * snat_api_init(vlib_main_t * vm, snat_main_t * sm); int snat_set_workers (uword * bitmap); int snat_interface_add_del(u32 sw_if_index, u8 is_inside, int is_del); @@ -571,7 +579,8 @@ u8 * format_snat_protocol(u8 * s, va_list * args); int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add, - u8 twice_nat, u8 out2in_only, u8 *tag); + twice_nat_type_t twice_nat, u8 out2in_only, + u8 *tag); int nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, snat_protocol_t proto, u32 vrf_id, int is_in); void nat_free_session_data (snat_main_t * sm, snat_session_t * s, diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index da97a801b7f..2f1e9a019ac 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -501,7 +501,7 @@ add_static_mapping_command_fn (vlib_main_t * vm, int rv; snat_protocol_t proto = ~0; u8 proto_set = 0; - u8 twice_nat = 0; + twice_nat_type_t twice_nat = TWICE_NAT_DISABLED; u8 out2in_only = 0; if (sm->deterministic) @@ -538,7 +538,9 @@ add_static_mapping_command_fn (vlib_main_t * vm, else if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) proto_set = 1; else if (unformat (line_input, "twice-nat")) - twice_nat = 1; + twice_nat = TWICE_NAT; + else if (unformat (line_input, "self-twice-nat")) + twice_nat = TWICE_NAT_SELF; else if (unformat (line_input, "out2in-only")) out2in_only = 1; else if (unformat (line_input, "del")) @@ -688,7 +690,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, snat_protocol_t proto; u8 proto_set = 0; nat44_lb_addr_port_t *locals = 0, local; - u8 twice_nat = 0; + twice_nat_type_t twice_nat = TWICE_NAT_DISABLED; u8 out2in_only = 0; if (sm->deterministic) @@ -718,7 +720,9 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, &proto)) proto_set = 1; else if (unformat (line_input, "twice-nat")) - twice_nat = 1; + twice_nat = TWICE_NAT; + else if (unformat (line_input, "self-twice-nat")) + twice_nat = TWICE_NAT_SELF; else if (unformat (line_input, "out2in-only")) out2in_only = 1; else if (unformat (line_input, "del")) @@ -1584,7 +1588,8 @@ VLIB_CLI_COMMAND (add_static_mapping_command, static) = { .function = add_static_mapping_command_fn, .short_help = "nat44 add static mapping tcp|udp|icmp local [] " - "external [] [vrf ] [twice-nat] [out2in-only] [del]", + "external [] [vrf ] [twice-nat|self-twice-nat] " + "[out2in-only] [del]", }; /*? @@ -1622,8 +1627,8 @@ VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = { .function = add_lb_static_mapping_command_fn, .short_help = "nat44 add load-balancing static mapping protocol tcp|udp " - "external : local : probability [twice-nat] " - "[vrf ] [out2in-only] [del]", + "external : local : probability " + "[twice-nat|self-twice-nat] [vrf ] [out2in-only] [del]", }; /*? diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 56b261d1bb9..417d2984011 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -724,6 +724,7 @@ static void ip4_address_t local_addr, external_addr; u16 local_port = 0, external_port = 0; u32 vrf_id, external_sw_if_index; + twice_nat_type_t twice_nat = TWICE_NAT_DISABLED; int rv = 0; snat_protocol_t proto; u8 *tag = 0; @@ -744,6 +745,10 @@ static void vrf_id = clib_net_to_host_u32 (mp->vrf_id); external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); proto = ip_proto_to_snat_proto (mp->protocol); + if (mp->twice_nat) + twice_nat = TWICE_NAT; + else if (mp->self_twice_nat) + twice_nat = TWICE_NAT_SELF; mp->tag[sizeof (mp->tag) - 1] = 0; tag = format (0, "%s", mp->tag); vec_terminate_c_string (tag); @@ -751,7 +756,7 @@ static void rv = snat_add_static_mapping (local_addr, external_addr, local_port, external_port, vrf_id, mp->addr_only, external_sw_if_index, proto, mp->is_add, - mp->twice_nat, mp->out2in_only, tag); + twice_nat, mp->out2in_only, tag); vec_free (tag); @@ -804,7 +809,10 @@ send_nat44_static_mapping_details (snat_static_mapping_t * m, rmp->external_sw_if_index = ~0; rmp->vrf_id = htonl (m->vrf_id); rmp->context = context; - rmp->twice_nat = m->twice_nat; + if (m->twice_nat == TWICE_NAT) + rmp->twice_nat = 1; + else if (m->twice_nat == TWICE_NAT_SELF) + rmp->self_twice_nat = 1; rmp->out2in_only = m->out2in_only; if (m->addr_only == 0) { @@ -1324,6 +1332,7 @@ static void { snat_main_t *sm = &snat_main; vl_api_nat44_add_del_lb_static_mapping_reply_t *rmp; + twice_nat_type_t twice_nat = TWICE_NAT_DISABLED; int rv = 0; nat44_lb_addr_port_t *locals = 0; ip4_address_t e_addr; @@ -1339,6 +1348,10 @@ static void locals = unformat_nat44_lb_addr_port (mp->locals, mp->local_num); clib_memcpy (&e_addr, mp->external_addr, 4); proto = ip_proto_to_snat_proto (mp->protocol); + if (mp->twice_nat) + twice_nat = TWICE_NAT; + else if (mp->self_twice_nat) + twice_nat = TWICE_NAT_SELF; mp->tag[sizeof (mp->tag) - 1] = 0; tag = format (0, "%s", mp->tag); vec_terminate_c_string (tag); @@ -1347,7 +1360,7 @@ static void nat44_add_del_lb_static_mapping (e_addr, clib_net_to_host_u16 (mp->external_port), proto, clib_net_to_host_u32 (mp->vrf_id), - locals, mp->is_add, mp->twice_nat, + locals, mp->is_add, twice_nat, mp->out2in_only, tag); vec_free (locals); @@ -1391,7 +1404,10 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m, rmp->protocol = snat_proto_to_ip_proto (m->proto); rmp->vrf_id = ntohl (m->vrf_id); rmp->context = context; - rmp->twice_nat = m->twice_nat; + if (m->twice_nat == TWICE_NAT) + rmp->twice_nat = 1; + else if (m->twice_nat == TWICE_NAT_SELF) + rmp->self_twice_nat = 1; rmp->out2in_only = m->out2in_only; if (m->tag) strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag)); diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index 637a07341e0..a0128b8d61d 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -871,6 +871,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, s->ext_host_addr.as_u32 = ip->src_address.as_u32; s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = ~0; s->out2in.addr.as_u32 = old_addr; s->out2in.fib_index = rx_fib_index; @@ -935,7 +936,8 @@ snat_out2in_lb (snat_main_t *sm, snat_user_t *u; u32 address_index; snat_session_key_t eh_key; - u8 twice_nat, lb; + twice_nat_type_t twice_nat; + u8 lb; old_addr = ip->dst_address.as_u32; @@ -987,6 +989,7 @@ snat_out2in_lb (snat_main_t *sm, s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; if (lb) s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; + s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT; s->outside_address_index = ~0; s->out2in = e_key; s->in2out = l_key; @@ -997,7 +1000,9 @@ snat_out2in_lb (snat_main_t *sm, if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) clib_warning ("out2in-ed key add failed"); - if (twice_nat) + if (twice_nat == TWICE_NAT || + (twice_nat == TWICE_NAT_SELF && + ip->src_address.as_u32 == l_key.addr.as_u32)) { eh_key.protocol = proto; if (snat_alloc_outside_address_and_port (sm->twice_nat_addresses, 0, -- cgit 1.2.3-korg