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
88#ifndef NAT64_TCP_RXBUF_SIZE
89#define NAT64_TCP_RXBUF_SIZE 1500
97#ifndef NAT64_TCP_RTX_TIMEOUT
98#define NAT64_TCP_RTX_TIMEOUT (3 * CLOCK_SECOND)
103#ifndef NAT64_TCP_MAX_RETRIES
104#define NAT64_TCP_MAX_RETRIES 5
111 uint8_t nexthdr, hoplim;
112 uip_ip6addr_t src, dst;
116 uint16_t sport, dport;
127static inline uint16_t
128get16(
const uint8_t *p)
130 return ((uint16_t)p[0] << 8) | p[1];
134put16(uint8_t *p, uint16_t v)
136 p[0] = (uint8_t)(v >> 8);
140static inline uint32_t
141get32(
const uint8_t *p)
143 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
144 ((uint32_t)p[2] << 8) | p[3];
148put32(uint8_t *p, uint32_t v)
150 p[0] = (uint8_t)(v >> 24);
151 p[1] = (uint8_t)(v >> 16);
152 p[2] = (uint8_t)(v >> 8);
157cksum_acc(uint32_t acc,
const void *buf, uint16_t nbytes)
159 const uint8_t *p = buf;
161 acc += ((uint16_t)p[0] << 8) | p[1];
166 acc += (uint16_t)p[0] << 8;
172cksum_fold(uint32_t acc)
175 acc = (acc & 0xffff) + (acc >> 16);
177 return ~((uint16_t)acc);
181tcp6_checksum(
const struct v6hdr *ip6,
const void *tcp, uint16_t tcp_len)
185 acc = cksum_acc(acc, &ip6->src,
sizeof(uip_ip6addr_t));
186 acc = cksum_acc(acc, &ip6->dst,
sizeof(uip_ip6addr_t));
189 acc = cksum_acc(acc, tcp, tcp_len);
191 uint16_t result = cksum_fold(acc);
192 return (result == 0) ? 0xffff : result;
202 bool peer_fin_received;
203 bool server_fin_pending;
208 uint8_t rxbuf[NAT64_TCP_RXBUF_SIZE];
210 uint16_t rxbuf_offset;
218 struct timer rtx_timer;
221static struct tcp_seqstate tcp_seq[NAT64_MAX_TCP_SESSIONS];
222static uint8_t isn_key[16];
227static struct tcp_seqstate *
231 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
232 if(tcp_seq[i].in_use && tcp_seq[i].session == s) {
254 uip_ip6addr_t ip6_peer;
255 uint16_t ip6_peer_port;
257 uint16_t ip4_remote_port;
260 uint8_t digest[SHA_256_DIGEST_LENGTH];
263 memcpy(&tuple.ip6_peer, &s->
ip6_peer,
sizeof(uip_ip6addr_t));
268 sha_256_hmac(isn_key,
sizeof(isn_key),
269 (
const uint8_t *)&tuple,
sizeof(tuple), digest);
270 memcpy(&f, digest,
sizeof(f));
272 gettimeofday(&tv, NULL);
273 uint32_t m = (uint32_t)((uint64_t)tv.tv_sec * 250000 + tv.tv_usec / 4);
278static struct tcp_seqstate *
282 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
283 if(!tcp_seq[i].in_use) {
284 tcp_seq[i].in_use =
true;
285 tcp_seq[i].pending_ack =
false;
286 tcp_seq[i].peer_fin_received =
false;
287 tcp_seq[i].server_fin_pending =
false;
288 tcp_seq[i].session = s;
289 tcp_seq[i].our_seq = generate_isn(s);
290 tcp_seq[i].peer_next = peer_isn + 1;
291 tcp_seq[i].rxbuf_len = 0;
292 tcp_seq[i].rxbuf_offset = 0;
293 tcp_seq[i].in_flight = 0;
294 tcp_seq[i].rtx_count = 0;
298 LOG_WARN(
"TCP sequence state table full\n");
302static struct tcp_seqstate *
303find_seqstate_by_addrs(
const uip_ip6addr_t *ip6_peer, uint16_t peer_port,
307 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
308 struct tcp_seqstate *ts = &tcp_seq[i];
309 if(!ts->in_use || ts->session == NULL) {
340 uint8_t
flags,
const uint8_t *payload, uint16_t payload_len)
346 tcp_total = TCP_HDRLEN + payload_len;
348 LOG_WARN(
"inject_tcp: packet too large\n");
356 put16(ip6->plen, tcp_total);
357 ip6->nexthdr = IP_PROTO_TCP;
358 ip6->hoplim = DEFAULT_HOPLIM;
361 uip_ip6addr_copy(&ip6->dst, &s->
ip6_peer);
363 tcp = (
struct tcphdr *)(
uip_buf + IPV6_HDRLEN);
366 put32(tcp->seqno, ts->our_seq);
367 put32(tcp->ackno, ts->peer_next);
368 tcp->offset = (TCP_HDRLEN / 4) << 4;
370 put16(tcp->wnd, 4096);
374 if(payload_len > 0) {
375 memcpy(
uip_buf + IPV6_HDRLEN + TCP_HDRLEN, payload, payload_len);
378 tcp->tchksum =
uip_htons(tcp6_checksum(ip6, tcp, tcp_total));
380 uip_len = IPV6_HDRLEN + tcp_total;
382 LOG_INFO(
"inject_tcp: %u bytes, flags=0x%02x seq=%lu ack=%lu\n",
384 (
unsigned long)ts->peer_next);
395 const struct v6hdr *ip6 = (
const struct v6hdr *)pkt;
396 uint16_t payload_len = get16(ip6->plen);
397 const struct tcphdr *tcp;
398 uint16_t data_offset, data_len;
402 if(payload_len < TCP_HDRLEN) {
403 LOG_WARN(
"tcp_output: payload too short (%u bytes)\n", payload_len);
407 if(!ip64_addr_6to4(&ip6->dst, &dst4)) {
408 LOG_WARN(
"tcp_output: destination is not a NAT64 address\n");
412 tcp = (
const struct tcphdr *)(pkt + IPV6_HDRLEN);
413 data_offset = ((tcp->offset >> 4) & 0x0f) * 4;
414 if(data_offset > payload_len) {
415 LOG_WARN(
"tcp_output: data offset %u exceeds payload %u\n",
416 data_offset, payload_len);
419 data_len = payload_len - data_offset;
420 seq = get32(tcp->seqno);
422 LOG_INFO(
"tcp_output: flags=0x%02x data=%u seq=%lu\n",
423 tcp->flags, data_len, (
unsigned long)seq);
425 if(tcp->flags & TCP_SYN) {
426 LOG_INFO(
"TCP SYN: port %u -> %u.%u.%u.%u:%u\n",
427 uip_ntohs(tcp->sport),
428 dst4.u8[0], dst4.u8[1], dst4.u8[2], dst4.u8[3],
429 uip_ntohs(tcp->dport));
432 &dst4, uip_ntohs(tcp->dport),
433 &ip6->src, uip_ntohs(tcp->sport), seq);
434 return (s != NULL) ? 1 : 0;
437 struct tcp_seqstate *ts = find_seqstate_by_addrs(
438 &ip6->src, uip_ntohs(tcp->sport),
439 &dst4, uip_ntohs(tcp->dport));
442 LOG_WARN(
"TCP packet for unknown session (flags=0x%02x)\n", tcp->flags);
448 if(tcp->flags & TCP_RST) {
449 LOG_INFO(
"TCP RST from IoT, aborting session\n");
462 if(tcp->flags & TCP_ACK) {
463 if(ts->in_flight > 0) {
464 uint32_t ackno = get32(tcp->ackno);
465 uint32_t end_of_inflight = ts->our_seq + ts->in_flight;
466 if((int32_t)(ackno - end_of_inflight) >= 0) {
469 }
else if(ts->rxbuf_len > ts->rxbuf_offset) {
477 const uint8_t *data = pkt + IPV6_HDRLEN + data_offset;
478 uint32_t seq_end = seq + (uint32_t)data_len;
479 int32_t gap = (int32_t)(seq - ts->peer_next);
485 LOG_WARN(
"TCP out-of-order seq=%lu peer_next=%lu, dropping\n",
486 (
unsigned long)seq, (
unsigned long)ts->peer_next);
487 ts->pending_ack =
true;
491 if((int32_t)(seq_end - ts->peer_next) <= 0) {
496 LOG_DBG(
"TCP retransmit seq=%lu len=%u (already forwarded)\n",
497 (
unsigned long)seq, data_len);
498 ts->pending_ack =
true;
502 uint32_t skip = ts->peer_next - seq;
503 const uint8_t *new_data = data + skip;
504 uint16_t new_len = data_len - (uint16_t)skip;
506 LOG_INFO(
"TCP forwarding %u bytes to IPv4 server%s\n",
507 new_len, skip > 0 ?
" (skipped retransmitted prefix)" :
"");
510 LOG_ERR(
"TCP send failed, aborting session\n");
514 ts->peer_next += (uint32_t)sent;
515 ts->pending_ack =
true;
516 if((uint32_t)sent < new_len) {
524 if(tcp->flags & TCP_FIN) {
525 if(!ts->peer_fin_received) {
526 LOG_INFO(
"TCP FIN from IoT node (half-close)\n");
528 ts->peer_fin_received =
true;
535 ts->pending_ack =
true;
542 LOG_INFO(
"TCP both sides FIN'd, destroying session\n");
547 LOG_DBG(
"TCP duplicate FIN from IoT node (already half-closed)\n");
572 if(ts->in_flight > 0) {
577 remaining = ts->rxbuf_len - ts->rxbuf_offset;
582 chunk = remaining > NAT64_TCP_SEGMENT_SIZE
583 ? NAT64_TCP_SEGMENT_SIZE : remaining;
585 LOG_INFO(
"TCP paced: %u/%u bytes -> IoT node\n", chunk, remaining);
586 inject_tcp(ts->session, ts, TCP_PSH | TCP_ACK,
587 ts->rxbuf + ts->rxbuf_offset, chunk);
588 ts->in_flight = chunk;
590 timer_set(&ts->rtx_timer, NAT64_TCP_RTX_TIMEOUT);
604 ts->our_seq += ts->in_flight;
605 ts->rxbuf_offset += ts->in_flight;
609 if(ts->rxbuf_offset >= ts->rxbuf_len) {
611 ts->rxbuf_offset = 0;
612 if(ts->server_fin_pending) {
613 ts->server_fin_pending =
false;
614 LOG_INFO(
"TCP deferred FIN: sending now\n");
615 inject_tcp(ts->session, ts, TCP_FIN | TCP_ACK, NULL, 0);
632 for(i = 0; i < NAT64_MAX_TCP_SESSIONS; i++) {
633 struct tcp_seqstate *ts = &tcp_seq[i];
634 if(!ts->in_use || ts->session == NULL) {
642 if(++ts->rtx_count > NAT64_TCP_MAX_RETRIES) {
643 LOG_ERR(
"TCP retransmit limit reached, aborting session\n");
647 LOG_WARN(
"TCP retransmit %u/%u (%u bytes)\n",
648 ts->rtx_count, NAT64_TCP_MAX_RETRIES, ts->in_flight);
649 inject_tcp(ts->session, ts, TCP_PSH | TCP_ACK,
650 ts->rxbuf + ts->rxbuf_offset, ts->in_flight);
654 if(ts->pending_ack) {
655 ts->pending_ack =
false;
662 inject_tcp(ts->session, ts, TCP_ACK, NULL, 0);
674 struct tcp_seqstate *ts = alloc_seqstate(s, s->
peer_isn);
676 LOG_ERR(
"TCP seqstate table full, closing connection\n");
681 LOG_INFO(
"TCP established: sending SYN-ACK\n");
682 inject_tcp(s, ts, TCP_SYN | TCP_ACK, NULL, 0);
688 const uint8_t *data, uint16_t len)
690 struct tcp_seqstate *ts = find_seqstate(s);
692 LOG_WARN(
"tcp_data_in: no sequence state\n");
696 if(ts->rxbuf_len > 0) {
697 LOG_WARN(
"tcp_data_in: buffer busy, dropping %u bytes\n", len);
701 if(len > NAT64_TCP_RXBUF_SIZE) {
702 len = NAT64_TCP_RXBUF_SIZE;
705 memcpy(ts->rxbuf, data, len);
707 ts->rxbuf_offset = 0;
717 struct tcp_seqstate *ts = find_seqstate(s);
722 if(ts->rxbuf_len > ts->rxbuf_offset) {
724 LOG_INFO(
"TCP remote closed: deferring FIN (%u bytes pending)\n",
725 ts->rxbuf_len - ts->rxbuf_offset);
726 ts->server_fin_pending =
true;
730 LOG_INFO(
"TCP remote closed: sending FIN to IoT node\n");
731 inject_tcp(s, ts, TCP_FIN | TCP_ACK, NULL, 0);
742 memset(tcp_seq, 0,
sizeof(tcp_seq));
748 memcpy(isn_key, key, 16);
754 struct tcp_seqstate *ts = find_seqstate(s);
755 return ts != NULL && ts->rxbuf_len > ts->rxbuf_offset;
761 struct tcp_seqstate *ts = find_seqstate(s);
762 return ts != NULL && ts->peer_fin_received;
768 struct tcp_seqstate *ts = find_seqstate(s);
771 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.
#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.
uint16_t ip4_remote_port
IPv4 server port.
uip_ip6addr_t ip6_peer
IoT node's IPv6 address.
enum nat64_tcp_state tcp_state
TCP connection state.
uint32_t peer_isn
IoT node's ISN (TCP only).
uip_ip4addr_t ip4_remote
IPv4 server address.
uint16_t ip6_peer_port
IoT node's transport port.
Header for the Contiki/uIP interface.
Representation of an IP address.