49#include "ipv6/ip64-addr.h"
56#define LOG_MODULE "NAT64"
57#define LOG_LEVEL LOG_LEVEL_INFO
61#define IP_PROTO_UDP 17
62#define IP_PROTO_ICMPV6 58
64#define DEFAULT_HOPLIM 64
66#define ICMP6_DST_UNREACH 1
67#define ICMP6_ECHO_REQUEST 128
68#define ICMP6_ECHO_REPLY 129
70#define ICMP4_ECHO_REQUEST 8
71#define ICMP4_ECHO_REPLY 0
75#ifndef NAT64_ICMP6_QUEUE_SIZE
76#define NAT64_ICMP6_QUEUE_SIZE 8
86#ifndef NAT64_DNS_BUF_SIZE
87#define NAT64_DNS_BUF_SIZE 1500
95#ifndef NAT64_CONF_ALLOW_LOOPBACK
96#define NAT64_CONF_ALLOW_LOOPBACK 0
102#define NAT64_ICMP6_BUF_SIZE 256
108 uint8_t nexthdr, hoplim;
109 uip_ip6addr_t src, dst;
113 uint16_t sport, dport, ulen, uchksum;
116struct icmp6_dst_unreach {
123struct icmp6_pending {
125 uint8_t buf[NAT64_ICMP6_BUF_SIZE];
128static struct icmp6_pending icmp6_queue[NAT64_ICMP6_QUEUE_SIZE];
129static unsigned icmp6_queue_count;
150 uint8_t a =
addr->u8[0];
151 uint8_t b =
addr->u8[1];
162 if(a == 100 && (b & 0xc0) == 64) {
167 return !NAT64_CONF_ALLOW_LOOPBACK;
170 if(a == 169 && b == 254) {
174 if(a == 172 && (b & 0xf0) == 16) {
178 if(a == 192 && b == 0 &&
addr->u8[2] == 0) {
182 if(a == 192 && b == 0 &&
addr->u8[2] == 2) {
186 if(a == 192 && b == 168) {
190 if(a == 198 && (b & 0xfe) == 18) {
194 if(a == 198 && b == 51 &&
addr->u8[2] == 100) {
198 if(a == 203 && b == 0 &&
addr->u8[2] == 113) {
202 if((a & 0xf0) == 224) {
206 if((a & 0xf0) == 240) {
212static inline uint16_t
213get16(
const uint8_t *p)
215 return ((uint16_t)p[0] << 8) | p[1];
219put16(uint8_t *p, uint16_t v)
221 p[0] = (uint8_t)(v >> 8);
226cksum_acc(uint32_t acc,
const void *buf, uint16_t nbytes)
228 const uint8_t *p = buf;
230 acc += ((uint16_t)p[0] << 8) | p[1];
235 acc += (uint16_t)p[0] << 8;
241cksum_fold(uint32_t acc)
244 acc = (acc & 0xffff) + (acc >> 16);
246 return ~((uint16_t)acc);
250udp6_checksum(
const struct v6hdr *ip6,
const struct udphdr *udp,
251 const uint8_t *payload, uint16_t payload_len)
253 uint16_t udp_total =
sizeof(
struct udphdr) + payload_len;
256 acc = cksum_acc(acc, &ip6->src,
sizeof(uip_ip6addr_t));
257 acc = cksum_acc(acc, &ip6->dst,
sizeof(uip_ip6addr_t));
260 acc = cksum_acc(acc, udp,
sizeof(
struct udphdr));
261 acc = cksum_acc(acc, payload, payload_len);
263 uint16_t result = cksum_fold(acc);
264 return (result == 0) ? 0xffff : result;
268icmp6_checksum(
const struct v6hdr *ip6,
const void *icmp, uint16_t icmp_len)
272 acc = cksum_acc(acc, &ip6->src,
sizeof(uip_ip6addr_t));
273 acc = cksum_acc(acc, &ip6->dst,
sizeof(uip_ip6addr_t));
275 acc += IP_PROTO_ICMPV6;
276 acc = cksum_acc(acc, icmp, icmp_len);
278 uint16_t result = cksum_fold(acc);
279 return (result == 0) ? 0xffff : result;
286 const struct v6hdr *orig;
287 struct icmp6_pending *slot;
289 struct icmp6_dst_unreach *icmp;
290 uint16_t embed_len, icmp_total, total;
292 if(invoking_len < IPV6_HDRLEN) {
296 orig = (
const struct v6hdr *)invoking_pkt;
300 if(orig->nexthdr == IP_PROTO_ICMPV6) {
304 if(icmp6_queue_count >= NAT64_ICMP6_QUEUE_SIZE) {
305 LOG_WARN(
"icmp6: queue full, dropping Dest Unreach code=%u\n", code);
312 embed_len = invoking_len;
313 if(embed_len > NAT64_ICMP6_BUF_SIZE - IPV6_HDRLEN -
sizeof(*icmp)) {
314 embed_len = NAT64_ICMP6_BUF_SIZE - IPV6_HDRLEN -
sizeof(*icmp);
317 icmp_total =
sizeof(*icmp) + embed_len;
318 total = IPV6_HDRLEN + icmp_total;
320 slot = &icmp6_queue[icmp6_queue_count];
322 ip6 = (
struct v6hdr *)slot->buf;
326 put16(ip6->plen, icmp_total);
327 ip6->nexthdr = IP_PROTO_ICMPV6;
328 ip6->hoplim = DEFAULT_HOPLIM;
331 uip_ip6addr_copy(&ip6->src, &orig->dst);
332 uip_ip6addr_copy(&ip6->dst, &orig->src);
334 icmp = (
struct icmp6_dst_unreach *)(slot->buf + IPV6_HDRLEN);
340 memcpy(slot->buf + IPV6_HDRLEN +
sizeof(*icmp), invoking_pkt, embed_len);
342 icmp->checksum =
uip_htons(icmp6_checksum(ip6, icmp, icmp_total));
347 LOG_DBG(
"icmp6: queued Dest Unreach code=%u (%u bytes)\n", code, total);
353 uint8_t ipproto, uint8_t code)
355 uint8_t fake[IPV6_HDRLEN + 8];
356 struct v6hdr *ip6 = (
struct v6hdr *)fake;
357 uint8_t *th = fake + IPV6_HDRLEN;
363 ip6->nexthdr = ipproto;
364 ip6->hoplim = DEFAULT_HOPLIM;
365 uip_ip6addr_copy(&ip6->src, ip6_src);
366 ip64_addr_4to6(ip4_dst, &ip6->dst);
372 put16(th + 2, dst_port);
373 th[4] = th[5] = th[6] = th[7] = 0;
383 for(i = 0; i < icmp6_queue_count; i++) {
384 struct icmp6_pending *slot = &icmp6_queue[i];
388 memcpy(
uip_buf, slot->buf, slot->len);
390 LOG_DBG(
"icmp6: injecting Dest Unreach (%u bytes)\n",
uip_len);
393 icmp6_queue_count = 0;
399 return active && ip64_addr_is_ip64(
addr);
419 const struct udphdr *udp;
422 static uint8_t dns_buf[NAT64_DNS_BUF_SIZE];
424 if(payload_len <
sizeof(
struct udphdr)) {
425 LOG_WARN(
"udp_output: payload too short (%u bytes)\n", payload_len);
429 udp = (
const struct udphdr *)(pkt + IPV6_HDRLEN);
430 data = pkt + IPV6_HDRLEN +
sizeof(
struct udphdr);
431 data_len = payload_len -
sizeof(
struct udphdr);
434 if(data_len <=
sizeof(dns_buf)) {
435 memcpy(dns_buf, data, data_len);
439 LOG_WARN(
"DNS64: query of %u bytes exceeds buffer (%u), forwarding "
440 "without AAAA->A rewrite\n",
441 data_len, (
unsigned)
sizeof(dns_buf));
446 &ip6->src, uip_ntohs(udp->sport),
447 data, data_len) >= 0 ? 1 : 0;
453icmp4_checksum(
const void *icmp, uint16_t icmp_len)
455 return cksum_fold(cksum_acc(0, icmp, icmp_len));
477 static uint8_t icmp_buf[256];
481 if(payload_len < ICMP6_HDRLEN) {
482 LOG_WARN(
"icmp6_output: payload too short (%u bytes)\n", payload_len);
486 icmp = pkt + IPV6_HDRLEN;
491 LOG_DBG(
"icmp6_output: ignoring ICMPv6 type %u\n", icmp[0]);
495 if(payload_len >
sizeof(icmp_buf)) {
496 LOG_WARN(
"icmp6_output: echo request too large (%u bytes)\n",
503 memcpy(icmp_buf, icmp, payload_len);
504 icmp_buf[0] = ICMP4_ECHO_REQUEST;
507 uint16_t cksum = icmp4_checksum(icmp_buf, payload_len);
508 icmp_buf[2] = (uint8_t)(cksum >> 8);
509 icmp_buf[3] = (uint8_t)cksum;
511 identifier = ((uint16_t)icmp[4] << 8) | icmp[5];
514 icmp_buf, payload_len) >= 0 ? 1 : 0;
520 const struct v6hdr *ip6 = (
const struct v6hdr *)pkt;
521 uint16_t payload_len;
524 if(len < IPV6_HDRLEN) {
525 LOG_WARN(
"output: packet too short (%u bytes)\n", len);
529 payload_len = get16(ip6->plen);
530 if(payload_len + IPV6_HDRLEN > len) {
531 LOG_WARN(
"output: payload %u exceeds packet %u\n", payload_len, len);
535 if(ip64_addr_is_ip64(&ip6->src)) {
536 LOG_WARN(
"output: dropping packet with NAT64 source address\n");
540 if(!ip64_addr_6to4(&ip6->dst, &dst4)) {
541 LOG_WARN(
"output: destination is not a NAT64 address\n");
546 LOG_WARN(
"output: dropping packet to forbidden IPv4 destination "
548 dst4.u8[0], dst4.u8[1], dst4.u8[2], dst4.u8[3]);
553 switch(ip6->nexthdr) {
558 case IP_PROTO_ICMPV6:
561 LOG_WARN(
"output: unsupported next-header %u\n", ip6->nexthdr);
568 const uint8_t *payload, uint16_t payload_len)
574 udp_total =
sizeof(
struct udphdr) + payload_len;
577 LOG_WARN(
"udp_input: response too large (%u bytes)\n",
578 IPV6_HDRLEN + udp_total);
586 ip6->nexthdr = IP_PROTO_UDP;
587 ip6->hoplim = DEFAULT_HOPLIM;
590 uip_ip6addr_copy(&ip6->dst, &s->
ip6_peer);
592 udp = (
struct udphdr *)(
uip_buf + IPV6_HDRLEN);
596 memcpy(
uip_buf + IPV6_HDRLEN +
sizeof(
struct udphdr),
597 payload, payload_len);
600 uint16_t max_payload =
UIP_BUFSIZE - IPV6_HDRLEN -
sizeof(
struct udphdr);
603 payload, payload_len,
604 uip_buf + IPV6_HDRLEN +
sizeof(
struct udphdr), payload_len,
606 if(new_len > max_payload) {
607 LOG_WARN(
"udp_input: DNS64 response too large (%u bytes)\n", new_len);
610 payload_len = new_len;
611 udp_total =
sizeof(
struct udphdr) + payload_len;
614 put16(ip6->plen, udp_total);
620 uip_buf + IPV6_HDRLEN +
sizeof(
struct udphdr),
623 uip_len = IPV6_HDRLEN + udp_total;
625 LOG_DBG(
"udp_input: injecting %u-byte packet\n",
uip_len);
635 if(len < ICMP6_HDRLEN) {
636 LOG_WARN(
"icmp_input: reply too short (%u bytes)\n", len);
640 LOG_WARN(
"icmp_input: reply too large (%u bytes)\n", IPV6_HDRLEN + len);
649 if(icmp_pkt[0] != ICMP4_ECHO_REPLY) {
650 LOG_DBG(
"icmp_input: ignoring ICMPv4 type %u\n", icmp_pkt[0]);
658 put16(ip6->plen, len);
659 ip6->nexthdr = IP_PROTO_ICMPV6;
660 ip6->hoplim = DEFAULT_HOPLIM;
662 uip_ip6addr_copy(&ip6->dst, &s->
ip6_peer);
664 icmp_out =
uip_buf + IPV6_HDRLEN;
665 memcpy(icmp_out, icmp_pkt, len);
676 uint16_t cksum = icmp6_checksum(ip6, icmp_out, len);
677 icmp_out[2] = (uint8_t)(cksum >> 8);
678 icmp_out[3] = (uint8_t)cksum;
682 LOG_DBG(
"icmp_input: injecting Echo Reply (%u bytes)\n",
uip_len);
int nat64_platform_udp_send(const uip_ip4addr_t *dst, uint16_t dstport, const uip_ip6addr_t *ip6_src, uint16_t srcport, const uint8_t *payload, uint16_t len)
Forward a UDP payload to an IPv4 server.
static int handle_udp_output(const uint8_t *pkt, const struct v6hdr *ip6, const uip_ip4addr_t *dst4, uint16_t payload_len)
Forward an outbound IPv6/UDP datagram to its IPv4 destination.
int nat64_platform_icmp_send(const uip_ip4addr_t *dst, const uip_ip6addr_t *ip6_src, uint16_t identifier, const uint8_t *icmp_pkt, uint16_t icmp_len)
Forward an ICMPv4 Echo Request to an IPv4 destination.
void nat64_queue_icmp6_unreach_tuple(const uip_ip6addr_t *ip6_src, uint16_t src_port, const uip_ip4addr_t *ip4_dst, uint16_t dst_port, uint8_t ipproto, uint8_t code)
Queue an ICMPv6 Destination Unreachable for a 5-tuple whose connection failed.
bool nat64_is_ip64_addr(const uip_ip6addr_t *addr)
Check whether an IPv6 address embeds an IPv4 address via the NAT64 prefix.
void nat64_udp_input(struct nat64_session *s, const uint8_t *payload, uint16_t payload_len)
Inject a UDP response from an IPv4 server.
void nat64_activate(void)
Initialize the NAT64 gateway.
static bool ipv4_dst_is_forbidden(const uip_ip4addr_t *addr)
Reject IPv4 destinations that must not be reached via NAT64.
int nat64_output(const uint8_t *pkt, uint16_t len)
Process an outgoing IPv6 packet destined for an IPv4 host.
void nat64_queue_icmp6_unreach(const uint8_t *invoking_pkt, uint16_t invoking_len, uint8_t code)
Queue an ICMPv6 Destination Unreachable for delivery to the IoT node.
static int handle_icmp6_output(const uint8_t *pkt, const struct v6hdr *ip6, const uip_ip4addr_t *dst4, uint16_t payload_len)
Translate an outbound ICMPv6 Echo Request to ICMPv4 and send it.
uint16_t nat64_dns64_4to6(const uint8_t *ipv4data, uint16_t ipv4len, uint8_t *ipv6data, uint16_t ipv6len, uint16_t ipv6bufsiz)
Rewrite an incoming DNS response from A to AAAA.
int nat64_tcp_output(const uint8_t *pkt, uint16_t len)
Process an outgoing IPv6+TCP packet from an IoT node.
void nat64_flush_icmp6(void)
Drain the queue of pending ICMPv6 errors into the uIP stack.
#define NAT64_ICMP6_ADMIN
Communication administratively prohibited.
void nat64_dns64_6to4(uint8_t *data, uint16_t len)
Rewrite an outgoing DNS query from AAAA to A.
void nat64_tcp_init(void)
Initialize the TCP splice proxy.
void nat64_icmp_input(struct nat64_session *s, const uint8_t *icmp_pkt, uint16_t len)
Inject an ICMPv4 Echo Reply received from an IPv4 host.
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
#define ICMP6_ECHO_REPLY
Echo reply.
#define ICMP6_DST_UNREACH
dest unreachable
#define ICMP6_ECHO_REQUEST
Echo request.
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
uint16_t uip_len
The length of the packet in the uip_buf buffer.
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Header file for the logging system.
NAT64 DNS64 translation (RFC 6147).
A NAT64 session binding an IoT node's IPv6 flow to an IPv4 socket.
uint16_t ip4_remote_port
IPv4 server port.
uip_ip6addr_t ip6_peer
IoT node's IPv6 address.
uip_ip4addr_t ip4_remote
IPv4 server address.
uint16_t ip6_peer_port
IoT node's transport port.
Header for the Contiki/uIP interface.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Representation of an IP address.