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 Belgium NV
Date:
Mon Dec 16 11:25:54 2013 +0100
Revision:
131:4758606c9316
Parent:
128:ae39e6e81531
Child:
149:5f4cb161cec3
Syncronized with master branch

Who changed what in which revision?

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