aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/snat/nat64_out2in.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/snat/nat64_out2in.c')
-rw-r--r--src/plugins/snat/nat64_out2in.c84
1 files changed, 78 insertions, 6 deletions
diff --git a/src/plugins/snat/nat64_out2in.c b/src/plugins/snat/nat64_out2in.c
index 3eed9974af2..c11bbb5a7b1 100644
--- a/src/plugins/snat/nat64_out2in.c
+++ b/src/plugins/snat/nat64_out2in.c
@@ -208,9 +208,12 @@ nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg)
}
else
{
- //TODO: ICMP error
- clib_warning ("not ICMP echo request/reply, %u", icmp->type);
- return -1;
+ ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
+
+ ip6->src_address.as_u64[0] = ip6_saddr.as_u64[0];
+ ip6->src_address.as_u64[1] = ip6_saddr.as_u64[1];
+ ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
+ ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
}
return 0;
@@ -218,10 +221,79 @@ nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg)
static int
nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
- void *ctx)
+ void *arg)
{
- //TODO:
- return -1;
+ nat64_main_t *nm = &nat64_main;
+ nat64_out2in_set_ctx_t *ctx = arg;
+ nat64_db_bib_entry_t *bibe;
+ nat64_db_st_entry_t *ste;
+ ip46_address_t saddr, daddr;
+ ip6_address_t ip6_daddr;
+ u32 sw_if_index, fib_index;
+ snat_protocol_t proto = ip_proto_to_snat_proto (ip4->protocol);
+
+ sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
+ fib_index =
+ fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
+
+ memset (&saddr, 0, sizeof (saddr));
+ saddr.ip4.as_u32 = ip4->src_address.as_u32;
+ memset (&daddr, 0, sizeof (daddr));
+ daddr.ip4.as_u32 = ip4->dst_address.as_u32;
+
+ memcpy (&ip6_daddr, well_known_prefix, sizeof (ip6_daddr));
+ ip6_daddr.as_u32[3] = ip4->dst_address.as_u32;
+
+ if (proto == SNAT_PROTOCOL_ICMP)
+ {
+ icmp46_header_t *icmp = ip4_next_header (ip4);
+ u16 out_id = ((u16 *) (icmp))[2];
+
+ if (!
+ (icmp->type == ICMP6_echo_request
+ || icmp->type == ICMP6_echo_reply))
+ return -1;
+
+ ste =
+ nat64_db_st_entry_find (&nm->db, &saddr, &daddr, out_id, 0, proto,
+ fib_index, 0);
+ if (!ste)
+ return -1;
+
+ bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
+ if (!bibe)
+ return -1;
+
+ ip6->dst_address.as_u64[0] = ip6_daddr.as_u64[0];
+ ip6->dst_address.as_u64[1] = ip6_daddr.as_u64[1];
+ ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
+ ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
+ ((u16 *) (icmp))[2] = bibe->in_port;
+ }
+ else
+ {
+ udp_header_t *udp = ip4_next_header (ip4);
+ u16 dport = udp->dst_port;
+ u16 sport = udp->src_port;
+
+ ste =
+ nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
+ fib_index, 0);
+ if (!ste)
+ return -1;
+
+ bibe = nat64_db_bib_entry_by_index (&nm->db, proto, ste->bibe_index);
+ if (!bibe)
+ return -1;
+
+ ip6->dst_address.as_u64[0] = ip6_daddr.as_u64[0];
+ ip6->dst_address.as_u64[1] = ip6_daddr.as_u64[1];
+ ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
+ ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
+ udp->src_port = bibe->in_port;
+ }
+
+ return 0;
}
static uword