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
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
Generated on Tue Jul 12 2022 15:59:22 by 1.7.2