1/*********************************************************************
2   PicoTCP. Copyright (c) 2012-2017 Altran Intelligent Systems. Some rights reserved.
3   See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
4
5   .
6
7   Authors: Kristof Roelants, Brecht Van Cauwenberghe,
8         Simon Maes, Philippe Mariman
9 *********************************************************************/
10
11#include "pico_stack.h"
12#include "pico_frame.h"
13#include "pico_tcp.h"
14#include "pico_udp.h"
15#include "pico_ipv4.h"
16#include "pico_addressing.h"
17#include "pico_nat.h"
18
19#ifdef PICO_SUPPORT_IPV4
20#ifdef PICO_SUPPORT_NAT
21
22#ifdef DEBUG_NAT
23#define nat_dbg dbg
24#else
25#define nat_dbg(...) do {} while(0)
26#endif
27
28#define PICO_NAT_TIMEWAIT  240000 /* msec (4 mins) */
29
30#define PICO_NAT_INBOUND   0
31#define PICO_NAT_OUTBOUND  1
32
33struct pico_nat_tuple {
34    uint8_t proto;
35    uint16_t conn_active : 11;
36    uint16_t portforward : 1;
37    uint16_t rst : 1;
38    uint16_t syn : 1;
39    uint16_t fin_in : 1;
40    uint16_t fin_out : 1;
41    uint16_t src_port;
42    uint16_t dst_port;
43    uint16_t nat_port;
44    struct pico_ip4 src_addr;
45    struct pico_ip4 dst_addr;
46    struct pico_ip4 nat_addr;
47};
48
49static struct pico_ipv4_link *nat_link = NULL;
50
51static int nat_cmp_natport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
52{
53
54    if (a->nat_port < b->nat_port)
55        return -1;
56
57    if (a->nat_port > b->nat_port)
58
59        return 1;
60
61    return 0;
62
63}
64
65static int nat_cmp_srcport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
66{
67
68    if (a->src_port < b->src_port)
69        return -1;
70
71    if (a->src_port > b->src_port)
72
73        return 1;
74
75    return 0;
76
77}
78
79static int nat_cmp_proto(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
80{
81    if (a->proto < b->proto)
82        return -1;
83
84    if (a->proto > b->proto)
85        return 1;
86
87    return 0;
88}
89
90static int nat_cmp_address(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
91{
92    return pico_ipv4_compare(&a->src_addr, &b->src_addr);
93}
94
95static int nat_cmp_inbound(void *ka, void *kb)
96{
97    struct pico_nat_tuple *a = ka, *b = kb;
98    int cport = nat_cmp_natport(a, b);
99    if (cport)
100        return cport;
101
102    return nat_cmp_proto(a, b);
103}
104
105
106static int nat_cmp_outbound(void *ka, void *kb)
107{
108    struct pico_nat_tuple *a = ka, *b = kb;
109    int caddr, cport;
110
111    caddr = nat_cmp_address(a, b);
112    if (caddr)
113        return caddr;
114
115    cport = nat_cmp_srcport(a, b);
116
117    if (cport)
118        return cport;
119
120    return nat_cmp_proto(a, b);
121}
122
123static PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound);
124static PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound);
125
126void pico_ipv4_nat_print_table(void)
127{
128    struct pico_nat_tuple *t = NULL;
129    struct pico_tree_node *index = NULL;
130    (void)t;
131
132    nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
133    nat_dbg("+                                                        NAT table                                                       +\n");
134    nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
135    nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n");
136    nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
137
138    pico_tree_foreach(index, &NATOutbound)
139    {
140        t = index->keyValue;
141        nat_dbg("+ %08X |  %05u   | %08X |  %05u   | %08X |  %05u   |  %03u  |     %03u     |   %u  |   %u  |  %u  |  %u  |   %u  +\n",
142                long_be(t->src_addr.addr), t->src_port, long_be(t->dst_addr.addr), t->dst_port, long_be(t->nat_addr.addr), t->nat_port,
143                t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward);
144    }
145    nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
146}
147
148/*
149   2 options:
150    find on nat_port and proto
151    find on src_addr, src_port and proto
152   zero the unused parameters
153 */
154static struct pico_nat_tuple *pico_ipv4_nat_find_tuple(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
155{
156    struct pico_nat_tuple *found = NULL, test = {
157        0
158    };
159
160    test.nat_port = nat_port;
161    test.src_port = src_port;
162    test.proto = proto;
163    if (src_addr)
164        test.src_addr = *src_addr;
165
166    if (nat_port)
167        found = pico_tree_findKey(&NATInbound, &test);
168    else
169        found = pico_tree_findKey(&NATOutbound, &test);
170
171    if (found)
172        return found;
173    else
174        return NULL;
175}
176
177int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
178{
179    struct pico_nat_tuple *t = NULL;
180
181    t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto);
182    if (t)
183        return 1;
184    else
185        return 0;
186}
187
188static struct pico_nat_tuple *pico_ipv4_nat_add(struct pico_ip4 dst_addr, uint16_t dst_port, struct pico_ip4 src_addr, uint16_t src_port,
189                                                struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto)
190{
191    struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple));
192    if (!t) {
193        pico_err = PICO_ERR_ENOMEM;
194        return NULL;
195    }
196
197    t->dst_addr = dst_addr;
198    t->dst_port = dst_port;
199    t->src_addr = src_addr;
200    t->src_port = src_port;
201    t->nat_addr = nat_addr;
202    t->nat_port = nat_port;
203    t->proto = proto;
204    t->conn_active = 1;
205    t->portforward = 0;
206    t->rst = 0;
207    t->syn = 0;
208    t->fin_in = 0;
209    t->fin_out = 0;
210
211    if (pico_tree_insert(&NATOutbound, t)) {
212        PICO_FREE(t);
213        return NULL;
214    }
215
216    if (pico_tree_insert(&NATInbound, t)) {
217        pico_tree_delete(&NATOutbound, t);
218        PICO_FREE(t);
219        return NULL;
220    }
221
222    return t;
223}
224
225static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto)
226{
227    struct pico_nat_tuple *t = NULL;
228    t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto);
229    if (t) {
230        pico_tree_delete(&NATOutbound, t);
231        pico_tree_delete(&NATInbound, t);
232        PICO_FREE(t);
233    }
234
235    return 0;
236}
237
238static struct pico_trans *pico_nat_generate_tuple_trans(struct pico_ipv4_hdr *net, struct pico_frame *f)
239{
240    struct pico_trans *trans = NULL;
241    switch (net->proto) {
242    case PICO_PROTO_TCP:
243    {
244        struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
245        trans = (struct pico_trans *)&tcp->trans;
246        break;
247    }
248    case PICO_PROTO_UDP:
249    {
250        struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
251        trans = (struct pico_trans *)&udp->trans;
252        break;
253    }
254    case PICO_PROTO_ICMP4:
255        /* XXX: implement */
256        break;
257    }
258    return trans;
259}
260
261static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f)
262{
263    struct pico_trans *trans = NULL;
264    struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
265    uint16_t nport = 0;
266    uint8_t retry = 32;
267
268    /* generate NAT port */
269    do {
270        uint32_t rand = pico_rand();
271        nport = (uint16_t) (rand & 0xFFFFU);
272        nport = (uint16_t)((nport % (65535 - 1024)) + 1024U);
273        nport = short_be(nport);
274
275        if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4))
276            break;
277    } while (--retry);
278
279    if (!retry)
280        return NULL;
281
282    trans = pico_nat_generate_tuple_trans(net, f);
283    if(!trans)
284        return NULL;
285
286    return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto);
287    /* XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto); */
288}
289
290static inline void pico_ipv4_nat_set_tcp_flags(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
291{
292    struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
293    if (tcp->flags & PICO_TCP_SYN)
294        t->syn = 1;
295
296    if (tcp->flags & PICO_TCP_RST)
297        t->rst = 1;
298
299    if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND))
300        t->fin_in = 1;
301
302    if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND))
303        t->fin_out = 1;
304}
305
306static int pico_ipv4_nat_sniff_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
307{
308    struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
309
310    switch (net->proto) {
311    case PICO_PROTO_TCP:
312    {
313        pico_ipv4_nat_set_tcp_flags(t, f, direction);
314        break;
315    }
316
317    case PICO_PROTO_UDP:
318        t->conn_active = 1;
319        break;
320
321    case PICO_PROTO_ICMP4:
322        /* XXX: implement */
323        break;
324
325    default:
326        return -1;
327    }
328
329    return 0;
330}
331
332static void pico_ipv4_nat_table_cleanup(pico_time now, void *_unused)
333{
334    struct pico_tree_node *index = NULL, *_tmp = NULL;
335    struct pico_nat_tuple *t = NULL;
336    IGNORE_PARAMETER(now);
337    IGNORE_PARAMETER(_unused);
338    nat_dbg("NAT: before table cleanup:\n");
339    pico_ipv4_nat_print_table();
340
341    pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp)
342    {
343        t = index->keyValue;
344        switch (t->proto)
345        {
346        case PICO_PROTO_TCP:
347            if (t->portforward)
348                break;
349            else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */
350                pico_ipv4_nat_del(t->nat_port, t->proto);
351            else if (t->rst || (t->fin_in && t->fin_out))
352                t->conn_active = 0;
353            else
354                t->conn_active++;
355
356            break;
357
358        case PICO_PROTO_UDP:
359            if (t->portforward)
360                break;
361            else if (t->conn_active > 1)
362                pico_ipv4_nat_del(t->nat_port, t->proto);
363            else
364                t->conn_active++;
365
366            break;
367
368        case PICO_PROTO_ICMP4:
369            if (t->conn_active > 1)
370                pico_ipv4_nat_del(t->nat_port, t->proto);
371            else
372                t->conn_active++;
373            break;
374
375        default:
376            /* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */
377            if (t->conn_active > 1)
378                pico_ipv4_nat_del(t->nat_port, t->proto);
379            else
380                t->conn_active++;
381        }
382    }
383
384    nat_dbg("NAT: after table cleanup:\n");
385    pico_ipv4_nat_print_table();
386    if (!pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL)) {
387        nat_dbg("NAT: Failed to start cleanup timer\n");
388        /* TODO no more NAT table cleanup now */
389    }
390}
391
392int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
393{
394    struct pico_nat_tuple *t = NULL;
395    struct pico_ip4 any_addr = {
396        0
397    };
398    uint16_t any_port = 0;
399
400    switch (flag)
401    {
402    case PICO_NAT_PORT_FORWARD_ADD:
403        t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto);
404        if (!t) {
405            pico_err = PICO_ERR_EAGAIN;
406            return -1;
407        }
408
409        t->portforward = 1;
410        break;
411
412    case PICO_NAT_PORT_FORWARD_DEL:
413        return pico_ipv4_nat_del(nat_port, proto);
414
415    default:
416        pico_err = PICO_ERR_EINVAL;
417        return -1;
418    }
419
420    pico_ipv4_nat_print_table();
421    return 0;
422}
423
424int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
425{
426    struct pico_nat_tuple *tuple = NULL;
427    struct pico_trans *trans = NULL;
428    struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
429
430    if (!pico_ipv4_nat_is_enabled(link_addr))
431        return -1;
432
433    switch (net->proto) {
434#ifdef PICO_SUPPORT_TCP
435    case PICO_PROTO_TCP:
436    {
437        struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
438        trans = (struct pico_trans *)&tcp->trans;
439        tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
440        if (!tuple)
441            return -1;
442
443        /* replace dst IP and dst PORT */
444        net->dst = tuple->src_addr;
445        trans->dport = tuple->src_port;
446        /* recalculate CRC */
447        tcp->crc = 0;
448        tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
449        break;
450    }
451#endif
452#ifdef PICO_SUPPORT_UDP
453    case PICO_PROTO_UDP:
454    {
455        struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
456        trans = (struct pico_trans *)&udp->trans;
457        tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
458        if (!tuple)
459            return -1;
460
461        /* replace dst IP and dst PORT */
462        net->dst = tuple->src_addr;
463        trans->dport = tuple->src_port;
464        /* recalculate CRC */
465        udp->crc = 0;
466        udp->crc = short_be(pico_udp_checksum_ipv4(f));
467        break;
468    }
469#endif
470    case PICO_PROTO_ICMP4:
471        /* XXX reimplement */
472        break;
473
474    default:
475        nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n");
476        return -1;
477    }
478
479    pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_INBOUND);
480    net->crc = 0;
481    net->crc = short_be(pico_checksum(net, f->net_len));
482
483    nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n",
484            tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port));
485
486    return 0;
487}
488
489int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
490{
491    struct pico_nat_tuple *tuple = NULL;
492    struct pico_trans *trans = NULL;
493    struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
494
495    if (!pico_ipv4_nat_is_enabled(link_addr))
496        return -1;
497
498    switch (net->proto) {
499#ifdef PICO_SUPPORT_TCP
500    case PICO_PROTO_TCP:
501    {
502        struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
503        trans = (struct pico_trans *)&tcp->trans;
504        tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
505        if (!tuple)
506            tuple = pico_ipv4_nat_generate_tuple(f);
507
508        /* replace src IP and src PORT */
509        net->src = tuple->nat_addr;
510        trans->sport = tuple->nat_port;
511        /* recalculate CRC */
512        tcp->crc = 0;
513        tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
514        break;
515    }
516#endif
517#ifdef PICO_SUPPORT_UDP
518    case PICO_PROTO_UDP:
519    {
520        struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
521        trans = (struct pico_trans *)&udp->trans;
522        tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
523        if (!tuple)
524            tuple = pico_ipv4_nat_generate_tuple(f);
525
526        /* replace src IP and src PORT */
527        net->src = tuple->nat_addr;
528        trans->sport = tuple->nat_port;
529        /* recalculate CRC */
530        udp->crc = 0;
531        udp->crc = short_be(pico_udp_checksum_ipv4(f));
532        break;
533    }
534#endif
535    case PICO_PROTO_ICMP4:
536        /* XXX reimplement */
537        break;
538
539    default:
540        nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n");
541        return -1;
542    }
543
544    pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_OUTBOUND);
545    net->crc = 0;
546    net->crc = short_be(pico_checksum(net, f->net_len));
547
548    nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n",
549            tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port));
550
551    return 0;
552}
553
554int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
555{
556    if (link == NULL) {
557        pico_err = PICO_ERR_EINVAL;
558        return -1;
559    }
560
561    if (!pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL)) {
562        nat_dbg("NAT: Failed to start cleanup timer\n");
563        return -1;
564    }
565
566    nat_link = link;
567
568    return 0;
569}
570
571int pico_ipv4_nat_disable(void)
572{
573    nat_link = NULL;
574    return 0;
575}
576
577int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
578{
579    if (!nat_link)
580        return 0;
581
582    if (nat_link->address.addr != link_addr->addr)
583        return 0;
584
585    return 1;
586}
587
588#endif
589#endif
590