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 RTOSgeneric mbed Ethernet driverhigh performance NXP LPC1768 specific Ethernet driverMulti-threading support for mbed RTOSBerkeley sockets and integration with the New Socket APIFork of the apps running on top of the New Socket APIScheduling 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.
modules/pico_nat.c@131:4758606c9316, 2013-12-16 (annotated)
- 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?
User | Revision | Line number | New 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 |