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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Mon Sep 02 08:02:21 2013 +0000
Revision:
51:ab4529a384a6
Parent:
3:b4047e8a0123
Child:
63:97f481e33cb2
Updated from masterbranch

Who changed what in which revision?

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