51#include "ipv6/ip64-addr.h"
60#define LOG_MODULE "NAT64"
61#define LOG_LEVEL LOG_LEVEL_INFO
66#define DEFAULT_HOPLIM 64
75#ifndef NAT64_MAX_TCP_SESSIONS
76#define NAT64_MAX_TCP_SESSIONS 16
82#ifndef NAT64_TCP_SEGMENT_SIZE
83#define NAT64_TCP_SEGMENT_SIZE 76
90#ifndef NAT64_TCP_RXBUF_SIZE
91#define NAT64_TCP_RXBUF_SIZE 1500
94#if NAT64_TCP_RXBUF_SIZE < 1500
95#error "NAT64_TCP_RXBUF_SIZE must be at least 1500 bytes"
103#ifndef NAT64_TCP_RTX_TIMEOUT
104#define NAT64_TCP_RTX_TIMEOUT (3 * CLOCK_SECOND)
109#ifndef NAT64_TCP_MAX_RETRIES
110#define NAT64_TCP_MAX_RETRIES 5
117 uint8_t nexthdr, hoplim;
118 uip_ip6addr_t src, dst;
122 uint16_t sport, dport;
133static inline uint16_t
134get16(
const uint8_t *p)
136 return ((uint16_t)p[0] << 8) | p[1];
140put16(uint8_t *p, uint16_t v)
142 p[0] = (uint8_t)(v >> 8);
146static inline uint32_t
147get32(
const uint8_t *p)
149 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
150 ((uint32_t)p[2] << 8) | p[3];
154put32(uint8_t *p, uint32_t v)
156 p[0] = (uint8_t)(v >> 24);
157 p[1] = (uint8_t)(v >> 16);
158 p[2] = (uint8_t)(v >> 8);
163cksum_acc(uint32_t acc,
const void *buf, uint16_t nbytes)
165 const uint8_t *p = buf;
167 acc += ((uint16_t)p[0] << 8) | p[1];
172 acc += (uint16_t)p[0] << 8;
178cksum_fold(uint32_t acc)
181 acc = (acc & 0xffff) + (acc >> 16);
183 return ~((uint16_t)acc);
187tcp6_checksum(
const struct v6hdr *ip6,
const void *tcp, uint16_t tcp_len)
191 acc = cksum_acc(acc, &ip6->src,
sizeof(uip_ip6addr_t));
192 acc = cksum_acc(acc, &ip6->dst,
sizeof(uip_ip6addr_t));
195 acc = cksum_acc(acc, tcp, tcp_len);
197 uint16_t result = cksum_fold(acc);
198 return (result == 0) ? 0xffff : result;
218 bool peer_fin_received;
219 bool server_fin_pending;
220 struct nat64_session *session;
221 uint32_t initial_our_seq;
225 uint8_t rxbuf[NAT64_TCP_RXBUF_SIZE];
227 uint16_t rxbuf_offset;
235 struct timer rtx_timer;
238static struct tcp_seqstate tcp_seq[NAT64_MAX_TCP_SESSIONS];
239static uint8_t isn_key[16];
244static struct tcp_seqstate *
248 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
249 if(tcp_seq[i].in_use && tcp_seq[i].session == s) {
271 uip_ip6addr_t ip6_peer;
272 uint16_t ip6_peer_port;
274 uint16_t ip4_remote_port;
277 uint8_t digest[SHA_256_DIGEST_LENGTH];
280 memcpy(&tuple.ip6_peer, &s->ip6_peer,
sizeof(uip_ip6addr_t));
281 tuple.ip6_peer_port = s->ip6_peer_port;
282 memcpy(&tuple.ip4_remote, &s->ip4_remote,
sizeof(
uip_ip4addr_t));
283 tuple.ip4_remote_port = s->ip4_remote_port;
285 sha_256_hmac(isn_key,
sizeof(isn_key),
286 (
const uint8_t *)&tuple,
sizeof(tuple), digest);
287 memcpy(&f, digest,
sizeof(f));
289 gettimeofday(&tv, NULL);
290 uint32_t m = (uint32_t)((uint64_t)tv.tv_sec * 250000 + tv.tv_usec / 4);
295static struct tcp_seqstate *
299 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
300 if(!tcp_seq[i].in_use) {
301 tcp_seq[i].in_use =
true;
302 tcp_seq[i].pending_ack =
false;
303 tcp_seq[i].peer_fin_received =
false;
304 tcp_seq[i].server_fin_pending =
false;
305 tcp_seq[i].session = s;
306 tcp_seq[i].our_seq = generate_isn(s);
307 tcp_seq[i].initial_our_seq = tcp_seq[i].our_seq;
308 tcp_seq[i].peer_next = peer_isn + 1;
309 tcp_seq[i].rxbuf_len = 0;
310 tcp_seq[i].rxbuf_offset = 0;
311 tcp_seq[i].in_flight = 0;
312 tcp_seq[i].rtx_count = 0;
316 LOG_WARN(
"TCP sequence state table full\n");
320static struct tcp_seqstate *
321find_seqstate_by_addrs(
const uip_ip6addr_t *ip6_peer, uint16_t peer_port,
325 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
326 struct tcp_seqstate *ts = &tcp_seq[i];
327 if(!ts->in_use || ts->session == NULL) {
331 if(s->ip6_peer_port == peer_port &&
332 s->ip4_remote_port == remote_port &&
333 uip_ip6addr_cmp(&s->ip6_peer,
ip6_peer) &&
358 uint8_t
flags,
const uint8_t *payload, uint16_t payload_len)
364 tcp_total = TCP_HDRLEN + payload_len;
366 LOG_WARN(
"inject_tcp: packet too large\n");
374 put16(ip6->plen, tcp_total);
375 ip6->nexthdr = IP_PROTO_TCP;
376 ip6->hoplim = DEFAULT_HOPLIM;
378 ip64_addr_4to6(&s->ip4_remote, &ip6->src);
379 uip_ip6addr_copy(&ip6->dst, &s->ip6_peer);
381 tcp = (
struct tcphdr *)(
uip_buf + IPV6_HDRLEN);
382 tcp->sport =
uip_htons(s->ip4_remote_port);
383 tcp->dport =
uip_htons(s->ip6_peer_port);
384 put32(tcp->seqno, ts->our_seq);
385 put32(tcp->ackno, ts->peer_next);
386 tcp->offset = (TCP_HDRLEN / 4) << 4;
388 put16(tcp->wnd, 4096);
392 if(payload_len > 0) {
393 memcpy(
uip_buf + IPV6_HDRLEN + TCP_HDRLEN, payload, payload_len);
396 tcp->tchksum =
uip_htons(tcp6_checksum(ip6, tcp, tcp_total));
398 uip_len = IPV6_HDRLEN + tcp_total;
400 LOG_INFO(
"inject_tcp: %u bytes, flags=0x%02x seq=%lu ack=%lu\n",
402 (
unsigned long)ts->peer_next);
413 const struct v6hdr *ip6 = (
const struct v6hdr *)pkt;
414 uint16_t payload_len = get16(ip6->plen);
415 const struct tcphdr *tcp;
416 uint16_t data_offset, data_len;
420 if(payload_len < TCP_HDRLEN) {
421 LOG_WARN(
"tcp_output: payload too short (%u bytes)\n", payload_len);
425 if(!ip64_addr_6to4(&ip6->dst, &dst4)) {
426 LOG_WARN(
"tcp_output: destination is not a NAT64 address\n");
430 tcp = (
const struct tcphdr *)(pkt + IPV6_HDRLEN);
431 data_offset = ((tcp->offset >> 4) & 0x0f) * 4;
432 if(data_offset < TCP_HDRLEN || data_offset > payload_len) {
433 LOG_WARN(
"tcp_output: invalid data offset %u for payload %u\n",
434 data_offset, payload_len);
437 data_len = payload_len - data_offset;
438 seq = get32(tcp->seqno);
440 LOG_INFO(
"tcp_output: flags=0x%02x data=%u seq=%lu\n",
441 tcp->flags, data_len, (
unsigned long)seq);
443 if(tcp->flags & TCP_SYN) {
444 struct tcp_seqstate *ts = find_seqstate_by_addrs(
445 &ip6->src, uip_ntohs(tcp->sport),
446 &dst4, uip_ntohs(tcp->dport));
448 uint32_t saved_seq = ts->our_seq;
450 LOG_INFO(
"TCP duplicate SYN: retransmitting SYN-ACK\n");
451 ts->our_seq = ts->initial_our_seq;
452 inject_tcp(ts->session, ts, TCP_SYN | TCP_ACK, NULL, 0);
453 ts->our_seq = saved_seq;
457 LOG_INFO(
"TCP SYN: port %u -> %u.%u.%u.%u:%u\n",
458 uip_ntohs(tcp->sport),
459 dst4.u8[0], dst4.u8[1], dst4.u8[2], dst4.u8[3],
460 uip_ntohs(tcp->dport));
463 &dst4, uip_ntohs(tcp->dport),
464 &ip6->src, uip_ntohs(tcp->sport), seq);
465 return (s != NULL) ? 1 : 0;
468 struct tcp_seqstate *ts = find_seqstate_by_addrs(
469 &ip6->src, uip_ntohs(tcp->sport),
470 &dst4, uip_ntohs(tcp->dport));
473 LOG_WARN(
"TCP packet for unknown session (flags=0x%02x)\n", tcp->flags);
479 if(tcp->flags & TCP_RST) {
480 LOG_INFO(
"TCP RST from IoT, aborting session\n");
493 if(tcp->flags & TCP_ACK) {
494 if(ts->in_flight > 0) {
495 uint32_t ackno = get32(tcp->ackno);
496 uint32_t end_of_inflight = ts->our_seq + ts->in_flight;
497 if((int32_t)(ackno - end_of_inflight) >= 0) {
500 }
else if(ts->rxbuf_len > ts->rxbuf_offset) {
508 const uint8_t *data = pkt + IPV6_HDRLEN + data_offset;
509 uint32_t seq_end = seq + (uint32_t)data_len;
510 int32_t gap = (int32_t)(seq - ts->peer_next);
516 LOG_WARN(
"TCP out-of-order seq=%lu peer_next=%lu, dropping\n",
517 (
unsigned long)seq, (
unsigned long)ts->peer_next);
518 ts->pending_ack =
true;
522 if((int32_t)(seq_end - ts->peer_next) <= 0) {
527 LOG_DBG(
"TCP retransmit seq=%lu len=%u (already forwarded)\n",
528 (
unsigned long)seq, data_len);
529 ts->pending_ack =
true;
533 uint32_t skip = ts->peer_next - seq;
534 const uint8_t *new_data = data + skip;
535 uint16_t new_len = data_len - (uint16_t)skip;
537 LOG_INFO(
"TCP forwarding %u bytes to IPv4 server%s\n",
538 new_len, skip > 0 ?
" (skipped retransmitted prefix)" :
"");
541 LOG_ERR(
"TCP send failed, aborting session\n");
545 ts->peer_next += (uint32_t)sent;
546 ts->pending_ack =
true;
547 if((uint32_t)sent < new_len) {
555 if(tcp->flags & TCP_FIN) {
556 if(!ts->peer_fin_received) {
557 LOG_INFO(
"TCP FIN from IoT node (half-close)\n");
559 ts->peer_fin_received =
true;
566 ts->pending_ack =
true;
573 LOG_INFO(
"TCP both sides FIN'd, destroying session\n");
578 LOG_DBG(
"TCP duplicate FIN from IoT node (already half-closed)\n");
603 if(ts->in_flight > 0) {
608 remaining = ts->rxbuf_len - ts->rxbuf_offset;
613 chunk = remaining > NAT64_TCP_SEGMENT_SIZE
614 ? NAT64_TCP_SEGMENT_SIZE : remaining;
616 LOG_INFO(
"TCP paced: %u/%u bytes -> IoT node\n", chunk, remaining);
617 inject_tcp(ts->session, ts, TCP_PSH | TCP_ACK,
618 ts->rxbuf + ts->rxbuf_offset, chunk);
619 ts->in_flight = chunk;
621 timer_set(&ts->rtx_timer, NAT64_TCP_RTX_TIMEOUT);
635 ts->our_seq += ts->in_flight;
636 ts->rxbuf_offset += ts->in_flight;
640 if(ts->rxbuf_offset >= ts->rxbuf_len) {
642 ts->rxbuf_offset = 0;
643 if(ts->server_fin_pending) {
644 ts->server_fin_pending =
false;
645 LOG_INFO(
"TCP deferred FIN: sending now\n");
646 inject_tcp(ts->session, ts, TCP_FIN | TCP_ACK, NULL, 0);
663 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
664 struct tcp_seqstate *ts = &tcp_seq[i];
665 if(!ts->in_use || ts->session == NULL) {
673 if(++ts->rtx_count > NAT64_TCP_MAX_RETRIES) {
674 LOG_ERR(
"TCP retransmit limit reached, aborting session\n");
678 LOG_WARN(
"TCP retransmit %u/%u (%u bytes)\n",
679 ts->rtx_count, NAT64_TCP_MAX_RETRIES, ts->in_flight);
680 inject_tcp(ts->session, ts, TCP_PSH | TCP_ACK,
681 ts->rxbuf + ts->rxbuf_offset, ts->in_flight);
685 if(ts->pending_ack) {
686 ts->pending_ack =
false;
693 inject_tcp(ts->session, ts, TCP_ACK, NULL, 0);
705 struct tcp_seqstate *ts = alloc_seqstate(s, s->peer_isn);
707 LOG_ERR(
"TCP seqstate table full, aborting connection\n");
712 LOG_INFO(
"TCP established: sending SYN-ACK\n");
713 inject_tcp(s, ts, TCP_SYN | TCP_ACK, NULL, 0);
719 const uint8_t *data, uint16_t len)
721 struct tcp_seqstate *ts = find_seqstate(s);
723 LOG_WARN(
"tcp_data_in: no sequence state\n");
727 if(ts->rxbuf_len > 0) {
728 LOG_WARN(
"tcp_data_in: buffer busy, dropping %u bytes\n", len);
732 if(len > NAT64_TCP_RXBUF_SIZE) {
733 len = NAT64_TCP_RXBUF_SIZE;
736 memcpy(ts->rxbuf, data, len);
738 ts->rxbuf_offset = 0;
748 struct tcp_seqstate *ts = find_seqstate(s);
753 if(ts->rxbuf_len > ts->rxbuf_offset) {
755 LOG_INFO(
"TCP remote closed: deferring FIN (%u bytes pending)\n",
756 ts->rxbuf_len - ts->rxbuf_offset);
757 ts->server_fin_pending =
true;
761 LOG_INFO(
"TCP remote closed: sending FIN to IoT node\n");
762 inject_tcp(s, ts, TCP_FIN | TCP_ACK, NULL, 0);
773 memset(tcp_seq, 0,
sizeof(tcp_seq));
779 memcpy(isn_key, key, 16);
785 struct tcp_seqstate *ts = find_seqstate(s);
786 return ts != NULL && ts->rxbuf_len > ts->rxbuf_offset;
792 struct tcp_seqstate *ts = find_seqstate(s);
793 return ts != NULL && ts->peer_fin_received;
799 struct tcp_seqstate *ts = find_seqstate(s);
802 ts->rxbuf_offset = 0;
static volatile at86rf215_flags_t flags
The radio driver uses the following flags to keep track of the current state of the radio and IRQ eve...
void nat64_tcp_flush_acks(void)
Flush deferred TCP ACKs.
void nat64_platform_tcp_destroy(struct nat64_session *s)
Fully tear down a TCP session.
static void nat64_tcp_send_pending(struct tcp_seqstate *ts)
Inject the next paced chunk from a session's receive buffer.
struct nat64_session * nat64_platform_tcp_connect(const uip_ip4addr_t *dst, uint16_t dstport, const uip_ip6addr_t *ip6_src, uint16_t srcport, uint32_t peer_isn)
Initiate a TCP connection to an IPv4 server.
static void nat64_tcp_ack_confirmed(struct tcp_seqstate *ts)
Promote the in-flight segment to acknowledged and queue what's next.
bool nat64_tcp_has_pending_data(const struct nat64_session *s)
Check whether a session has buffered data awaiting delivery.
void nat64_tcp_free_seqstate(const struct nat64_session *s)
Free any TCP sequence state associated with a session.
bool nat64_tcp_peer_fin_received(const struct nat64_session *s)
Check whether the IoT node has already half-closed the session.
void nat64_platform_tcp_close(struct nat64_session *s)
Half-close a TCP session (send FIN).
void nat64_platform_tcp_abort(struct nat64_session *s)
Abort a TCP session by sending RST upstream.
void nat64_tcp_set_isn_secret(const uint8_t key[16])
Set the 128-bit secret key for TCP ISN generation.
void nat64_tcp_closed(struct nat64_session *s)
Notify that an IPv4 server closed a TCP connection.
void nat64_tcp_data_in(struct nat64_session *s, const uint8_t *data, uint16_t len)
Forward TCP data from an IPv4 server to the IoT node.
void nat64_tcp_established(struct nat64_session *s)
Notify that a TCP connection to an IPv4 server completed.
static void inject_tcp(const struct nat64_session *s, struct tcp_seqstate *ts, uint8_t flags, const uint8_t *payload, uint16_t payload_len)
Fabricate and inject an IPv6+TCP segment toward the IoT node.
int nat64_platform_tcp_send(struct nat64_session *s, const uint8_t *data, uint16_t len)
Send data on an established TCP session.
int nat64_tcp_output(const uint8_t *pkt, uint16_t len)
Process an outgoing IPv6+TCP packet from an IoT node.
void nat64_tcp_init(void)
Initialize the TCP splice proxy.
@ NAT64_TCP_CLOSING
Half-closed (SHUT_WR sent).
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
bool timer_expired(struct timer *t)
Check if a timer has expired.
void timer_reset(struct timer *t)
Reset the timer with the same interval.
union uip_ip4addr_t uip_ip4addr_t
Representation of an IP address.
#define uip_ip4addr_cmp(addr1, addr2)
Compare two IP addresses.
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.
Platform-independent SHA-256 API.
A NAT64 session binding an IoT node's IPv6 flow to an IPv4 socket.
uip_ip6addr_t ip6_peer
IoT node's IPv6 address.
uip_ip4addr_t ip4_remote
IPv4 server address.
Header for the Contiki/uIP interface.
Representation of an IP address.