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 Jan 28 15:12:00 2016 +0100
Revision:
155:a70f34550c34
Parent:
152:a3d286bf94e5
Adding TCP flag for FIN.

Who changed what in which revision?

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