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:
Thu Sep 19 13:26:14 2013 +0000
Revision:
68:0847e35d08a6
Child:
70:cd218dd180e5
Imported from masterbranch, again

Who changed what in which revision?

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