Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_nat.c Source File

pico_nat.c

00001 /*********************************************************************
00002    PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
00003    See LICENSE and COPYING for usage.
00004 
00005    .
00006 
00007    Authors: Kristof Roelants, Brecht Van Cauwenberghe,
00008          Simon Maes, Philippe Mariman
00009  *********************************************************************/
00010 
00011 #include "pico_stack.h"
00012 #include "pico_frame.h"
00013 #include "pico_tcp.h"
00014 #include "pico_udp.h"
00015 #include "pico_ipv4.h"
00016 #include "pico_addressing.h"
00017 #include "pico_nat.h"
00018 
00019 #ifdef PICO_SUPPORT_IPV4
00020 #ifdef PICO_SUPPORT_NAT
00021 
00022 #define nat_dbg(...) do {} while(0)
00023 /* #define nat_dbg dbg */
00024 #define PICO_NAT_TIMEWAIT  240000 /* msec (4 mins) */
00025 
00026 #define PICO_NAT_INBOUND   0
00027 #define PICO_NAT_OUTBOUND  1
00028 
00029 struct pico_nat_tuple {
00030     uint8_t proto;
00031     uint16_t conn_active : 11;
00032     uint16_t portforward : 1;
00033     uint16_t rst : 1;
00034     uint16_t syn : 1;
00035     uint16_t fin_in : 1;
00036     uint16_t fin_out : 1;
00037     uint16_t src_port;
00038     uint16_t dst_port;
00039     uint16_t nat_port;
00040     struct pico_ip4 src_addr;
00041     struct pico_ip4 dst_addr;
00042     struct pico_ip4 nat_addr;
00043 };
00044 
00045 static struct pico_ipv4_link *nat_link = NULL;
00046 
00047 static int nat_cmp_natport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
00048 {
00049 
00050     if (a->nat_port < b->nat_port)
00051         return -1;
00052 
00053     if (a->nat_port > b->nat_port)
00054 
00055         return 1;
00056 
00057     return 0;
00058 
00059 }
00060 
00061 static int nat_cmp_srcport(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
00062 {
00063 
00064     if (a->src_port < b->src_port)
00065         return -1;
00066 
00067     if (a->src_port > b->src_port)
00068 
00069         return 1;
00070 
00071     return 0;
00072 
00073 }
00074 
00075 static int nat_cmp_proto(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
00076 {
00077     if (a->proto < b->proto)
00078         return -1;
00079 
00080     if (a->proto > b->proto)
00081         return 1;
00082 
00083     return 0;
00084 }
00085 
00086 static int nat_cmp_address(struct pico_nat_tuple *a, struct pico_nat_tuple *b)
00087 {
00088     return pico_ipv4_compare(&a->src_addr, &b->src_addr);
00089 }
00090 
00091 static int nat_cmp_inbound(void *ka, void *kb)
00092 {
00093     struct pico_nat_tuple *a = ka, *b = kb;
00094     int cport = nat_cmp_natport(a, b);
00095     if (cport)
00096         return cport;
00097 
00098     return nat_cmp_proto(a, b);
00099 }
00100 
00101 
00102 static int nat_cmp_outbound(void *ka, void *kb)
00103 {
00104     struct pico_nat_tuple *a = ka, *b = kb;
00105     int caddr, cport;
00106 
00107     caddr = nat_cmp_address(a, b);
00108     if (caddr)
00109         return caddr;
00110 
00111     cport = nat_cmp_srcport(a, b);
00112 
00113     if (cport)
00114         return cport;
00115 
00116     return nat_cmp_proto(a, b);
00117 }
00118 
00119 PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound);
00120 PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound);
00121 
00122 void pico_ipv4_nat_print_table(void)
00123 {
00124     struct pico_nat_tuple *t = NULL;
00125     struct pico_tree_node *index = NULL;
00126     (void)t;
00127 
00128     nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00129     nat_dbg("+                                                        NAT table                                                       +\n");
00130     nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
00131     nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n");
00132     nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
00133 
00134     pico_tree_foreach(index, &NATOutbound)
00135     {
00136         t = index->keyValue;
00137         nat_dbg("+ %08X |  %05u   | %08X |  %05u   | %08X |  %05u   |  %03u  |     %03u     |   %u  |   %u  |  %u  |  %u  |   %u  +\n",
00138                 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,
00139                 t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward);
00140     }
00141     nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00142 }
00143 
00144 /*
00145    2 options:
00146     find on nat_port and proto
00147     find on src_addr, src_port and proto
00148    zero the unused parameters
00149  */
00150 static 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)
00151 {
00152     struct pico_nat_tuple *found = NULL, test = {
00153         0
00154     };
00155 
00156     test.nat_port = nat_port;
00157     test.src_port = src_port;
00158     test.proto = proto;
00159     if (src_addr)
00160         test.src_addr = *src_addr;
00161 
00162     if (nat_port)
00163         found = pico_tree_findKey(&NATInbound, &test);
00164     else
00165         found = pico_tree_findKey(&NATOutbound, &test);
00166 
00167     if (found)
00168         return found;
00169     else
00170         return NULL;
00171 }
00172 
00173 int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
00174 {
00175     struct pico_nat_tuple *t = NULL;
00176 
00177     t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto);
00178     if (t)
00179         return 1;
00180     else
00181         return 0;
00182 }
00183 
00184 static 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,
00185                                                 struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto)
00186 {
00187     struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple));
00188     if (!t) {
00189         pico_err = PICO_ERR_ENOMEM;
00190         return NULL;
00191     }
00192 
00193     t->dst_addr = dst_addr;
00194     t->dst_port = dst_port;
00195     t->src_addr = src_addr;
00196     t->src_port = src_port;
00197     t->nat_addr = nat_addr;
00198     t->nat_port = nat_port;
00199     t->proto = proto;
00200     t->conn_active = 1;
00201     t->portforward = 0;
00202     t->rst = 0;
00203     t->syn = 0;
00204     t->fin_in = 0;
00205     t->fin_out = 0;
00206 
00207     if (pico_tree_insert(&NATOutbound, t)) {
00208         PICO_FREE(t);
00209         return NULL;
00210     }
00211 
00212     if (pico_tree_insert(&NATInbound, t)) {
00213         pico_tree_delete(&NATOutbound, t);
00214         PICO_FREE(t);
00215         return NULL;
00216     }
00217 
00218     return t;
00219 }
00220 
00221 static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto)
00222 {
00223     struct pico_nat_tuple *t = NULL;
00224     t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto);
00225     if (t) {
00226         pico_tree_delete(&NATOutbound, t);
00227         pico_tree_delete(&NATInbound, t);
00228         PICO_FREE(t);
00229     }
00230 
00231     return 0;
00232 }
00233 
00234 static struct pico_trans *pico_nat_generate_tuple_trans(struct pico_ipv4_hdr *net, struct pico_frame *f)
00235 {
00236     struct pico_trans *trans = NULL;
00237     switch (net->proto) {
00238     case PICO_PROTO_TCP:
00239     {
00240         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
00241         trans = (struct pico_trans *)&tcp->trans;
00242         break;
00243     }
00244     case PICO_PROTO_UDP:
00245     {
00246         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
00247         trans = (struct pico_trans *)&udp->trans;
00248         break;
00249     }
00250     case PICO_PROTO_ICMP4:
00251         /* XXX: implement */
00252         break;
00253     }
00254     return trans;
00255 }
00256 
00257 static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f)
00258 {
00259     struct pico_trans *trans = NULL;
00260     struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
00261     uint16_t nport = 0;
00262     uint8_t retry = 32;
00263 
00264     /* generate NAT port */
00265     do {
00266         uint32_t rand = pico_rand();
00267         nport = (uint16_t) (rand & 0xFFFFU);
00268         nport = (uint16_t)((nport % (65535 - 1024)) + 1024U);
00269         nport = short_be(nport);
00270 
00271         if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4))
00272             break;
00273     } while (--retry);
00274 
00275     if (!retry)
00276         return NULL;
00277 
00278     trans = pico_nat_generate_tuple_trans(net, f);
00279     if(!trans)
00280         return NULL;
00281 
00282     return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto);
00283     /* XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto); */
00284 }
00285 
00286 static inline void pico_ipv4_nat_set_tcp_flags(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
00287 {
00288     struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
00289     if (tcp->flags & PICO_TCP_SYN)
00290         t->syn = 1;
00291 
00292     if (tcp->flags & PICO_TCP_RST)
00293         t->rst = 1;
00294 
00295     if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND))
00296         t->fin_in = 1;
00297 
00298     if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND))
00299         t->fin_out = 1;
00300 }
00301 
00302 static int pico_ipv4_nat_sniff_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
00303 {
00304     struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
00305 
00306     switch (net->proto) {
00307     case PICO_PROTO_TCP:
00308     {
00309         pico_ipv4_nat_set_tcp_flags(t, f, direction);
00310         break;
00311     }
00312 
00313     case PICO_PROTO_UDP:
00314         t->conn_active = 1;
00315         break;
00316 
00317     case PICO_PROTO_ICMP4:
00318         /* XXX: implement */
00319         break;
00320 
00321     default:
00322         return -1;
00323     }
00324 
00325     return 0;
00326 }
00327 
00328 static void pico_ipv4_nat_table_cleanup(pico_time now, void *_unused)
00329 {
00330     struct pico_tree_node *index = NULL, *_tmp = NULL;
00331     struct pico_nat_tuple *t = NULL;
00332     IGNORE_PARAMETER(now);
00333     IGNORE_PARAMETER(_unused);
00334     nat_dbg("NAT: before table cleanup:\n");
00335     pico_ipv4_nat_print_table();
00336 
00337     pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp)
00338     {
00339         t = index->keyValue;
00340         switch (t->proto)
00341         {
00342         case PICO_PROTO_TCP:
00343             if (t->portforward)
00344                 break;
00345             else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */
00346                 pico_ipv4_nat_del(t->nat_port, t->proto);
00347             else if (t->rst || (t->fin_in && t->fin_out))
00348                 t->conn_active = 0;
00349             else
00350                 t->conn_active++;
00351 
00352             break;
00353 
00354         case PICO_PROTO_UDP:
00355             if (t->portforward)
00356                 break;
00357             else if (t->conn_active > 1)
00358                 pico_ipv4_nat_del(t->nat_port, t->proto);
00359             else
00360                 t->conn_active++;
00361 
00362             break;
00363 
00364         case PICO_PROTO_ICMP4:
00365             if (t->conn_active > 1)
00366                 pico_ipv4_nat_del(t->nat_port, t->proto);
00367             else
00368                 t->conn_active++;
00369 
00370         default:
00371             /* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */
00372             if (t->conn_active > 1)
00373                 pico_ipv4_nat_del(t->nat_port, t->proto);
00374             else
00375                 t->conn_active++;
00376         }
00377     }
00378 
00379     nat_dbg("NAT: after table cleanup:\n");
00380     pico_ipv4_nat_print_table();
00381     pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
00382 }
00383 
00384 int 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)
00385 {
00386     struct pico_nat_tuple *t = NULL;
00387     struct pico_ip4 any_addr = {
00388         0
00389     };
00390     uint16_t any_port = 0;
00391 
00392     switch (flag)
00393     {
00394     case PICO_NAT_PORT_FORWARD_ADD:
00395         t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto);
00396         if (!t) {
00397             pico_err = PICO_ERR_EAGAIN;
00398             return -1;
00399         }
00400 
00401         t->portforward = 1;
00402         break;
00403 
00404     case PICO_NAT_PORT_FORWARD_DEL:
00405         return pico_ipv4_nat_del(nat_port, proto);
00406 
00407     default:
00408         pico_err = PICO_ERR_EINVAL;
00409         return -1;
00410     }
00411 
00412     pico_ipv4_nat_print_table();
00413     return 0;
00414 }
00415 
00416 int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
00417 {
00418     struct pico_nat_tuple *tuple = NULL;
00419     struct pico_trans *trans = NULL;
00420     struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
00421 
00422     if (!pico_ipv4_nat_is_enabled(link_addr))
00423         return -1;
00424 
00425     switch (net->proto) {
00426 #ifdef PICO_SUPPORT_TCP
00427     case PICO_PROTO_TCP:
00428     {
00429         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
00430         trans = (struct pico_trans *)&tcp->trans;
00431         tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
00432         if (!tuple)
00433             return -1;
00434 
00435         /* replace dst IP and dst PORT */
00436         net->dst = tuple->src_addr;
00437         trans->dport = tuple->src_port;
00438         /* recalculate CRC */
00439         tcp->crc = 0;
00440         tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
00441         break;
00442     }
00443 #endif
00444 #ifdef PICO_SUPPORT_UDP
00445     case PICO_PROTO_UDP:
00446     {
00447         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
00448         trans = (struct pico_trans *)&udp->trans;
00449         tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
00450         if (!tuple)
00451             return -1;
00452 
00453         /* replace dst IP and dst PORT */
00454         net->dst = tuple->src_addr;
00455         trans->dport = tuple->src_port;
00456         /* recalculate CRC */
00457         udp->crc = 0;
00458         udp->crc = short_be(pico_udp_checksum_ipv4(f));
00459         break;
00460     }
00461 #endif
00462     case PICO_PROTO_ICMP4:
00463         /* XXX reimplement */
00464         break;
00465 
00466     default:
00467         nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n");
00468         return -1;
00469     }
00470 
00471     pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_INBOUND);
00472     net->crc = 0;
00473     net->crc = short_be(pico_checksum(net, f->net_len));
00474 
00475     nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n",
00476             tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port));
00477 
00478     return 0;
00479 }
00480 
00481 int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
00482 {
00483     struct pico_nat_tuple *tuple = NULL;
00484     struct pico_trans *trans = NULL;
00485     struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
00486 
00487     if (!pico_ipv4_nat_is_enabled(link_addr))
00488         return -1;
00489 
00490     switch (net->proto) {
00491 #ifdef PICO_SUPPORT_TCP
00492     case PICO_PROTO_TCP:
00493     {
00494         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
00495         trans = (struct pico_trans *)&tcp->trans;
00496         tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
00497         if (!tuple)
00498             tuple = pico_ipv4_nat_generate_tuple(f);
00499 
00500         /* replace src IP and src PORT */
00501         net->src = tuple->nat_addr;
00502         trans->sport = tuple->nat_port;
00503         /* recalculate CRC */
00504         tcp->crc = 0;
00505         tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
00506         break;
00507     }
00508 #endif
00509 #ifdef PICO_SUPPORT_UDP
00510     case PICO_PROTO_UDP:
00511     {
00512         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
00513         trans = (struct pico_trans *)&udp->trans;
00514         tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
00515         if (!tuple)
00516             tuple = pico_ipv4_nat_generate_tuple(f);
00517 
00518         /* replace src IP and src PORT */
00519         net->src = tuple->nat_addr;
00520         trans->sport = tuple->nat_port;
00521         /* recalculate CRC */
00522         udp->crc = 0;
00523         udp->crc = short_be(pico_udp_checksum_ipv4(f));
00524         break;
00525     }
00526 #endif
00527     case PICO_PROTO_ICMP4:
00528         /* XXX reimplement */
00529         break;
00530 
00531     default:
00532         nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n");
00533         return -1;
00534     }
00535 
00536     pico_ipv4_nat_sniff_session(tuple, f, PICO_NAT_OUTBOUND);
00537     net->crc = 0;
00538     net->crc = short_be(pico_checksum(net, f->net_len));
00539 
00540     nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n",
00541             tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port));
00542 
00543     return 0;
00544 }
00545 
00546 int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
00547 {
00548     if (link == NULL) {
00549         pico_err = PICO_ERR_EINVAL;
00550         return -1;
00551     }
00552 
00553     nat_link = link;
00554     pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
00555     return 0;
00556 }
00557 
00558 int pico_ipv4_nat_disable(void)
00559 {
00560     nat_link = NULL;
00561     return 0;
00562 }
00563 
00564 int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
00565 {
00566     if (!nat_link)
00567         return 0;
00568 
00569     if (nat_link->address.addr != link_addr->addr)
00570         return 0;
00571 
00572     return 1;
00573 }
00574 
00575 #endif
00576 #endif