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