nat_misc.c
Go to the documentation of this file.
1 /**
2  * @file nat_misc.c
3  * @brief Helper functions for NAT
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NAT_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "ipv4/ipv4_misc.h"
37 #include "ipv4/icmp.h"
38 #include "nat/nat.h"
39 #include "nat/nat_misc.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (NAT_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief NAT timer handler
48  * @param[in] context Pointer to the NAT context
49  **/
50 
51 void natTick(NatContext *context)
52 {
53  uint_t i;
55  NatSession *session;
56 
57  //Make sure the NAT context has been properly instantiated
58  if(context == NULL)
59  return;
60 
61  //Get current time
63 
64  //Loop through the NAT sessions
65  for(i = 0; i < context->numSessions; i++)
66  {
67  //Point to the current session
68  session = &context->sessions[i];
69 
70  //Valid session?
71  if(session->protocol != 0)
72  {
73  //TCP, UDP or ICMP session?
74  if(session->protocol == IPV4_PROTOCOL_TCP)
75  {
76  //Check whether the TCP session timer has expired
77  if((time - session->timestamp) >= NAT_TCP_SESSION_TIMEOUT)
78  {
79  session->protocol = IPV4_PROTOCOL_NONE;
80  }
81  }
82  else if(session->protocol == IPV4_PROTOCOL_UDP)
83  {
84  //Check whether the UDP session timer has expired
85  if((time - session->timestamp) >= NAT_UDP_SESSION_TIMEOUT)
86  {
87  session->protocol = IPV4_PROTOCOL_NONE;
88  }
89  }
90  else
91  {
92  //Check whether the ICMP session timer has expired
93  if((time - session->timestamp) >= NAT_ICMP_SESSION_TIMEOUT)
94  {
95  session->protocol = IPV4_PROTOCOL_NONE;
96  }
97  }
98  }
99  }
100 }
101 
102 
103 /**
104  * @brief Check whether a network interface is the WAN interface
105  * @param[in] context Pointer to the NAT context
106  * @param[in] interface Pointer to a network interface
107  * @return TRUE if the specified interface is the WAN interface, else FALSE
108  **/
109 
111 {
112  bool_t res;
113 
114  //Initialize flag
115  res = FALSE;
116 
117  //Check the operational state of the NAT
118  if(context != NULL && context->running)
119  {
120  //Matching interface?
121  if(interface == context->publicInterface)
122  {
123  res = TRUE;
124  }
125  }
126 
127  //Return TRUE if the specified interface is the WAN interface
128  return res;
129 }
130 
131 
132 /**
133  * @brief Check whether a network interface is a LAN interface
134  * @param[in] context Pointer to the NAT context
135  * @param[in] interface Pointer to a network interface
136  * @return TRUE if the specified interface is a LAN interface, else FALSE
137  **/
138 
140 {
141  uint_t i;
142  bool_t res;
143 
144  //Initialize flag
145  res = FALSE;
146 
147  //Check the operational state of the NAT
148  if(context != NULL && context->running)
149  {
150  //Loop through private interfaces
151  for(i = 0; i < context->numPrivateInterfaces; i++)
152  {
153  //Matching interface?
154  if(context->privateInterfaces[i] == interface)
155  {
156  res = TRUE;
157  break;
158  }
159  }
160  }
161 
162  //Return TRUE if the specified interface is a LAN interface
163  return res;
164 }
165 
166 
167 /**
168  * @brief Process IP packet
169  * @param[in] context Pointer to the NAT context
170  * @param[in] inInterface Pointer to the interface where the packet was received
171  * @param[in] inPseudoHeader Pointer to the pseudo header
172  * @param[in] inBuffer Multi-part buffer that holds the incoming IP packet
173  * @param[in] inOffset Packet Offset to the payload of the IP packet
174  * @param[in] ancillary Additional options passed to the stack along with
175  * the packet
176  * @return Error code
177  **/
178 
180  const Ipv4PseudoHeader *inPseudoHeader, const NetBuffer *inBuffer,
181  size_t inOffset, NetRxAncillary *ancillary)
182 {
183  error_t error;
184  NatIpPacket packet;
185 
186  //Incoming IP packet
187  packet.interface = inInterface;
188  packet.buffer = inBuffer;
189  packet.offset = inOffset;
190  packet.protocol = (Ipv4Protocol) inPseudoHeader->protocol;
191  packet.srcIpAddr = inPseudoHeader->srcAddr;
192  packet.srcPort = 0;
193  packet.destIpAddr = inPseudoHeader->destAddr;
194  packet.destPort = 0;
195  packet.icmpQueryId = 0;
196  packet.ttl = ancillary->ttl;
197  packet.tos = ancillary->tos;
198 
199  //Make sure the NAT context has been properly instantiated
200  if(context == NULL)
201  return ERROR_FAILURE;
202 
203  //Broadcast and multicast packets are not forwarded by the NAT
204  if(ipv4IsBroadcastAddr(packet.interface, packet.destIpAddr) ||
206  {
207  return ERROR_INVALID_ADDRESS;
208  }
209 
210  //Packets with a link-local source or destination address are not routable
211  //off the link
212  if(ipv4IsLinkLocalAddr(packet.srcIpAddr) ||
214  {
215  return ERROR_INVALID_ADDRESS;
216  }
217 
218  //Inbound or outbound traffic?
219  if(natIsPublicInterface(context, packet.interface))
220  {
221  //Extract transport identifiers (TCP/UDP ports or ICMP query ID)
222  error = natParseTransportHeader(&packet);
223  //Unrecognized packet?
224  if(error)
225  return error;
226 
227  //Debug message
228  TRACE_DEBUG("NAT: Packet received on interface %s...\r\n",
229  packet.interface->name);
230  //Dump IP packet for debugging purpose
231  natDumpPacket(&packet);
232 
233  //Perform address translation
234  error = natTranslateInboundPacket(context, &packet);
235  //Any error to report?
236  if(error)
237  return error;
238  }
239  else if(natIsPrivateInterface(context, packet.interface))
240  {
241  //Check destination IP address
242  error = ipv4CheckDestAddr(packet.interface, packet.destIpAddr);
243  //Do not forward packets destined to the host
244  if(!error)
245  return ERROR_INVALID_ADDRESS;
246 
247  //Extract transport identifiers (TCP/UDP ports or ICMP query ID)
248  error = natParseTransportHeader(&packet);
249  //Unrecognized packet?
250  if(error)
251  return NO_ERROR;
252 
253  //Debug message
254  TRACE_DEBUG("NAT: Packet received on interface %s...\r\n",
255  packet.interface->name);
256  //Dump IP packet for debugging purpose
257  natDumpPacket(&packet);
258 
259  //Perform address translation
260  error = natTranslateOutboundPacket(context, &packet);
261  //Any error to report?
262  if(error)
263  return NO_ERROR;
264 
265  //Check destination IP address
266  error = ipv4CheckDestAddr(packet.interface, packet.destIpAddr);
267 
268  //NATs that forward packets originating from an internal address,
269  //destined for an external address that matches the active mapping for
270  //an internal address, back to that internal address are defined in
271  //as supporting "hairpinning"
272  if(!error)
273  {
274  //Perform address translation
275  natTranslateInboundPacket(context, &packet);
276  }
277  }
278  else
279  {
280  //Do not forward the received packet
281  return ERROR_FAILURE;
282  }
283 
284  //TTL exceeded in transit?
285  if(packet.ttl <= 1)
286  {
287  //A NAT device must generate a Time Exceeded ICMP Error message when
288  //it discards a packet due to an expired Time to Live field (refer to
289  //RFC 5508, section 7.2)
291  packet.buffer, 0);
292  }
293  else
294  {
295  //NAT devices decrement the TTL on packets that they forward
296  packet.ttl--;
297  //Forward the packet to the specified interface
298  natForwardPacket(context, &packet);
299  }
300 
301  //Successful processing
302  return NO_ERROR;
303 }
304 
305 
306 /**
307  * @brief Perform address translation (inbound packet)
308  * @param[in] context Pointer to the NAT context
309  * @param[in] packet IP packet
310  * @return Error code
311  **/
312 
314 {
315  error_t error;
316  NatPortFwdRule *rule;
317  NatSession *session;
318 
319  //Initialize status code
320  error = NO_ERROR;
321 
322  //Check whether the packet matches any port forwarding rule
323  rule = natMatchPortFwdRule(context, packet);
324 
325  //Matching port forwarding rule found?
326  if(rule != NULL)
327  {
328  //Translate destination IP address
329  packet->destIpAddr = rule->privateIpAddr;
330 
331  //Translate destination port
332  packet->destPort = rule->privatePortMin + packet->destPort -
333  rule->publicPortMin;
334 
335  //Interface where to forward the received packet
336  packet->interface = rule->privateInterface;
337  }
338  else
339  {
340  //Check whether the packet matches any existing session
341  session = natMatchSession(context, packet);
342 
343  //Matching session found?
344  if(session != NULL)
345  {
346  //Translate destination IP address and port
347  packet->destIpAddr = session->privateIpAddr;
348  packet->destPort = session->privatePort;
349 
350  //Translate ICMP query identifier
351  packet->icmpQueryId = session->privateIcmpQueryId;
352  //Interface where to forward the received packet
353  packet->interface = session->privateInterface;
354 
355  //Keep the mapping active when a packet goes from the external
356  //side of the NAT to the internal side of the NAT
357  session->timestamp = osGetSystemTime();
358  }
359  else
360  {
361  //Report an error
362  error = ERROR_INVALID_SESSION;
363  }
364  }
365 
366  //Return status code
367  return error;
368 }
369 
370 
371 /**
372  * @brief Perform address translation (outbound packet)
373  * @param[in] context Pointer to the NAT context
374  * @param[in] packet IP packet
375  * @return Error code
376  **/
377 
379 {
380  error_t error;
381  Ipv4Addr publicIpAddr;
382  Ipv4Context *ipv4Context;
383  NatPortFwdRule *rule;
384  NatSession *session;
385 
386  //Initialize status code
387  error = NO_ERROR;
388 
389  //Point to the IPv4 context
390  ipv4Context = &context->publicInterface->ipv4Context;
391  //Get the external address
392  publicIpAddr = ipv4Context->addrList[context->publicIpAddrIndex].addr;
393 
394  //Check whether the packet matches any port forwarding rule
395  rule = natMatchPortFwdRule(context, packet);
396 
397  //Matching port forwarding rule found?
398  if(rule != NULL)
399  {
400  //Translate source IP address
401  packet->srcIpAddr = publicIpAddr;
402 
403  //Translate source port
404  packet->srcPort = rule->publicPortMin + packet->srcPort -
405  rule->privatePortMin;
406 
407  //Interface where to forward the received packet
408  packet->interface = context->publicInterface;
409  }
410  else
411  {
412  //Check whether the packet matches any existing session
413  session = natMatchSession(context, packet);
414 
415  //Matching session found?
416  if(session == NULL)
417  {
418  //a NAT device must permit ICMP Queries and their associated
419  //responses, when the Query is initiated from a private host to
420  //the external hosts (refer to RFC 5508, section 3.1)
421  if(packet->protocol != IPV4_PROTOCOL_ICMP ||
422  packet->icmpType == ICMP_TYPE_ECHO_REQUEST ||
425  {
426  //Create a new session
427  session = natCreateSession(context);
428  }
429 
430  //Valid session?
431  if(session != NULL)
432  {
433  //A NAT session is an association between a session as seen in the
434  //private realm and a session as seen in the public realm
435  session->protocol = packet->protocol;
436  session->privateInterface = packet->interface;
437  session->privateIpAddr = packet->srcIpAddr;
438  session->privatePort = 0;
439  session->privateIcmpQueryId = 0;
440  session->publicPort = 0;
441  session->publicIcmpQueryId = 0;
442  session->remoteIpAddr = packet->destIpAddr;
443  session->remotePort = 0;
444 
445  //NAT sessions are restricted to sessions based on TCP, UDP, and
446  //ICMP
447  if(session->protocol == IPV4_PROTOCOL_TCP ||
448  session->protocol == IPV4_PROTOCOL_UDP)
449  {
450  //The NAPT assigns the session a public port number, so that
451  //subsequent response packets from the external endpoint can
452  //be received by the NAPT, translated, and forwarded to the
453  //internal host
454  session->privatePort = packet->srcPort;
455  session->publicPort = natAllocatePort(context);
456  session->remotePort = packet->destPort;
457  }
458  else
459  {
460  //The identifier field in ICMP message header is uniquely mapped
461  //to a query identifier of the registered IP address (refer to
462  //RFC 3022, section 2.2)
463  session->privateIcmpQueryId = packet->icmpQueryId;
464  session->publicIcmpQueryId = natAllocateIcmpQueryId(context);
465  }
466 
467  //A private address is bound to an external address, when the first
468  //outgoing session is initiated from the private host (refer to
469  //RFC 3022, section 3.1)
470  error = ipv4SelectSourceAddr(context->publicInterface->netContext,
471  &context->publicInterface, packet->destIpAddr, &session->publicIpAddr);
472 
473  //Check status code
474  if(error)
475  {
476  //Send an ICMP destination unreachable messages
478  ICMP_CODE_NET_UNREACHABLE, 0, packet->buffer, 0);
479 
480  //Terminate session
481  session->protocol = IPV4_PROTOCOL_NONE;
482  }
483  }
484  else
485  {
486  //Report an error
487  error = ERROR_INVALID_SESSION;
488  }
489  }
490 
491  //Check status code
492  if(!error)
493  {
494  //Translate source IP address and port
495  packet->srcIpAddr = publicIpAddr;
496  packet->srcPort = session->publicPort;
497 
498  //Translate ICMP query identifier
499  packet->icmpQueryId = session->publicIcmpQueryId;
500  //Interface where to forward the received packet
501  packet->interface = context->publicInterface;
502 
503  //Keep the mapping active when a packet goes from the internal side of
504  //the NAT to the external side of the NAT
505  session->timestamp = osGetSystemTime();
506  }
507  }
508 
509  //Return status code
510  return error;
511 }
512 
513 
514 /**
515  * @brief Forward an IP packet to the specified interface
516  * @param[in] context Pointer to the NAT context
517  * @param[in] packet IP packet
518  * @return Error code
519  **/
520 
522 {
523  error_t error;
524  size_t length;
525  NetBuffer *outBuffer;
526  size_t outOffset;
527  Ipv4PseudoHeader pseudoHeader;
528  NetTxAncillary ancillary;
529 
530  //Retrieve the length of the incoming IP packet
531  length = netBufferGetLength(packet->buffer) - packet->offset;
532 
533  //Allocate a buffer to hold the IP packet
534  outBuffer = ipAllocBuffer(length, &outOffset);
535 
536  //Successful memory allocation?
537  if(outBuffer != NULL)
538  {
539  //Copy the payload
540  error = netBufferCopy(outBuffer, outOffset, packet->buffer,
541  packet->offset, length);
542 
543  //Check status code
544  if(!error)
545  {
546  //Format pseudo header
547  pseudoHeader.srcAddr = packet->srcIpAddr;
548  pseudoHeader.destAddr = packet->destIpAddr;
549  pseudoHeader.reserved = 0;
550  pseudoHeader.protocol = packet->protocol;
551  pseudoHeader.length = htons(length);
552 
553  //Modify transport identifiers (TCP/UDP ports or ICMP query ID)
554  error = natTranslateTransportHeader(packet, &pseudoHeader, outBuffer,
555  outOffset);
556  }
557 
558  //Check status code
559  if(!error)
560  {
561  //Additional options can be passed to the stack along with the packet
562  ancillary = NET_DEFAULT_TX_ANCILLARY;
563 
564  //Specify TTL value
565  ancillary.ttl = packet->ttl;
566  //Specify ToS value
567  ancillary.tos = packet->tos;
568 
569  //Debug message
570  TRACE_DEBUG("NAT: Sending packet on interface %s...\r\n",
571  packet->interface->name);
572  //Dump IP packet for debugging purpose
573  natDumpPacket(packet);
574 
575  //Forward IP packet
576  error = ipv4SendDatagram(packet->interface, &pseudoHeader, outBuffer,
577  outOffset, &ancillary);
578  }
579 
580  //Free previously allocated memory
581  netBufferFree(outBuffer);
582  }
583  else
584  {
585  //Report an error
586  error = ERROR_OUT_OF_MEMORY;
587  }
588 
589  //Return status code
590  return error;
591 }
592 
593 
594 /**
595  * @brief Search the port forwarding rules for a matching entry
596  * @param[in] context Pointer to the NAT context
597  * @param[in] packet IP packet
598  * @return Pointer to the matching port forwarding rule, if any
599  **/
600 
602  const NatIpPacket *packet)
603 {
604  uint_t i;
605  NatPortFwdRule *rule;
606 
607  //Inbound or outbound traffic?
608  if(packet->interface == context->publicInterface)
609  {
610  //Loop through the list of port redirection rules
611  for(i = 0; i < context->numPortFwdRules; i++)
612  {
613  //Point to the current rule
614  rule = &context->portFwdRules[i];
615 
616  //Check protocol field
617  if(rule->protocol == packet->protocol)
618  {
619  //Check destination port number
620  if(packet->destPort >= rule->publicPortMin &&
621  packet->destPort <= rule->publicPortMax)
622  {
623  return rule;
624  }
625  }
626  }
627  }
628  else
629  {
630  //Loop through the list of port redirection rules
631  for(i = 0; i < context->numPortFwdRules; i++)
632  {
633  //Point to the current rule
634  rule = &context->portFwdRules[i];
635 
636  //Check protocol field and source IP address
637  if(rule->privateInterface == packet->interface &&
638  rule->protocol == packet->protocol &&
639  rule->privateIpAddr == packet->srcIpAddr)
640  {
641  //Check source port number
642  if(packet->srcPort >= rule->privatePortMin &&
643  packet->srcPort <= rule->privatePortMax)
644  {
645  return rule;
646  }
647  }
648  }
649  }
650 
651  //No matching port forwarding rule
652  return NULL;
653 }
654 
655 
656 /**
657  * @brief Search the NAT sessions for a matching entry
658  * @param[in] context Pointer to the NAT context
659  * @param[in] packet IP packet
660  * @return Pointer to the matching session, if any
661  **/
662 
664 {
665  uint_t i;
666  NatSession *session;
667 
668  //Inbound or outbound traffic?
669  if(packet->interface == context->publicInterface)
670  {
671  //Loop through the NAT sessions
672  for(i = 0; i < context->numSessions; i++)
673  {
674  //Point to the current session
675  session = &context->sessions[i];
676 
677  //Matching session?
678  if(session->protocol == packet->protocol &&
679  session->remoteIpAddr == packet->srcIpAddr &&
680  session->publicIpAddr == packet->destIpAddr)
681  {
682  //Matching transport identifiers?
683  if(session->protocol == IPV4_PROTOCOL_TCP &&
684  session->remotePort == packet->srcPort &&
685  session->publicPort == packet->destPort)
686  {
687  return session;
688  }
689  else if(session->protocol == IPV4_PROTOCOL_UDP &&
690  session->remotePort == packet->srcPort &&
691  session->publicPort == packet->destPort)
692  {
693  return session;
694  }
695  else if(session->protocol == IPV4_PROTOCOL_ICMP &&
696  session->publicIcmpQueryId == packet->icmpQueryId)
697  {
698  //Check the type of ICMP message
699  if(packet->icmpType == ICMP_TYPE_ECHO_REPLY ||
700  packet->icmpType == ICMP_TYPE_TIMESTAMP_REPLY ||
702  {
703  return session;
704  }
705  }
706  else
707  {
708  }
709  }
710  }
711  }
712  else
713  {
714  //Loop through the NAT sessions
715  for(i = 0; i < context->numSessions; i++)
716  {
717  //Point to the current session
718  session = &context->sessions[i];
719 
720  //Matching session?
721  if(session->privateInterface == packet->interface &&
722  session->protocol == packet->protocol &&
723  session->privateIpAddr == packet->srcIpAddr &&
724  session->remoteIpAddr == packet->destIpAddr)
725  {
726  //Matching transport identifiers?
727  if(session->protocol == IPV4_PROTOCOL_TCP &&
728  session->privatePort == packet->srcPort &&
729  session->remotePort == packet->destPort)
730  {
731  return session;
732  }
733  else if(session->protocol == IPV4_PROTOCOL_UDP &&
734  session->privatePort == packet->srcPort &&
735  session->remotePort == packet->destPort)
736  {
737  return session;
738  }
739  else if(session->protocol == IPV4_PROTOCOL_ICMP &&
740  session->privateIcmpQueryId == packet->icmpQueryId)
741  {
742  //Check the type of ICMP message
743  if(packet->icmpType == ICMP_TYPE_ECHO_REQUEST ||
746  {
747  return session;
748  }
749  }
750  else
751  {
752  }
753  }
754  }
755  }
756 
757  //No matching session
758  return NULL;
759 }
760 
761 
762 /**
763  * @brief Create a new NAT session
764  * @param[in] context Pointer to the NAT context
765  * @return Pointer to the newly created session
766  **/
767 
769 {
770  uint_t i;
771  systime_t time;
772  NatSession *session;
773  NatSession *oldestSession;
774 
775  //Loop through the NAT sessions
776  for(i = 0; i < context->numSessions; i++)
777  {
778  //Point to the current session
779  session = &context->sessions[i];
780 
781  //Check whether the session is a available for use
782  if(session->protocol == IPV4_PROTOCOL_NONE)
783  {
784  return session;
785  }
786  }
787 
788  //Get current time
789  time = osGetSystemTime();
790  //Keep track of the oldest session
791  oldestSession = NULL;
792 
793  //Loop through the NAT sessions
794  for(i = 0; i < context->numSessions; i++)
795  {
796  //Point to the current session
797  session = &context->sessions[i];
798 
799  //Keep track of the oldest session
800  if(oldestSession == NULL)
801  {
802  oldestSession = session;
803  }
804  else if((time - session->timestamp) > (time - oldestSession->timestamp))
805  {
806  oldestSession = session;
807  }
808  else
809  {
810  }
811  }
812 
813  //Return a pointer to the NAT session
814  return oldestSession;
815 }
816 
817 
818 /**
819  * @brief Allocate a new port number
820  * @param[in] context Pointer to the NAT context
821  * @return Port number
822  **/
823 
824 uint16_t natAllocatePort(NatContext *context)
825 {
826  uint_t i;
827  uint16_t port;
828  bool_t valid;
829  NatSession *session;
830 
831  //Assign a new port number
832  do
833  {
834  //Generate a random port number
837 
838  //Loop through the NAT sessions
839  for(valid = TRUE, i = 0; i < context->numSessions; i++)
840  {
841  //Point to the current session
842  session = &context->sessions[i];
843 
844  //TCP or UDP session?
845  if(session->protocol == IPV4_PROTOCOL_TCP ||
846  session->protocol == IPV4_PROTOCOL_UDP)
847  {
848  //Test whether the port number is a duplicate
849  if(session->publicPort == port)
850  {
851  valid = FALSE;
852  }
853  }
854  }
855 
856  //Repeat as necessary until a unique port number is generated
857  } while(!valid);
858 
859  //Return the port number
860  return port;
861 }
862 
863 
864 /**
865  * @brief Allocate a new ICMP query identifier
866  * @param[in] context Pointer to the NAT context
867  * @return ICMP query identifier
868  **/
869 
871 {
872  uint_t i;
873  uint16_t id;
874  bool_t valid;
875  NatSession *session;
876 
877  //Assign a new ICMP query identifier
878  do
879  {
880  //Generate a random identifier
883 
884  //Loop through the NAT sessions
885  for(valid = TRUE, i = 0; i < context->numSessions; i++)
886  {
887  //Point to the current session
888  session = &context->sessions[i];
889 
890  //ICMP session
891  if(session->protocol == IPV4_PROTOCOL_ICMP)
892  {
893  //Test whether the ICMP query identifier is a duplicate
894  if(session->publicIcmpQueryId == id)
895  {
896  valid = FALSE;
897  }
898  }
899  }
900 
901  //Repeat as necessary until a unique identifier is generated
902  } while(!valid);
903 
904  //Return the ICMP query identifier
905  return id;
906 }
907 
908 
909 /**
910  * @brief Parse transport header (TCP, UDP or ICMP)
911  * @param[in,out] packet IP packet
912  * @return Error code
913  **/
914 
916 {
917  error_t error;
918 
919  //Initialize status code
920  error = NO_ERROR;
921 
922  //Check packet type
923  if(packet->protocol == IPV4_PROTOCOL_TCP)
924  {
925  TcpHeader *header;
926 
927  //Point to the TCP header
928  header = netBufferAt(packet->buffer, packet->offset, sizeof(TcpHeader));
929 
930  //Valid TCP header?
931  if(header != NULL)
932  {
933  //Retrieve source and destination ports
934  packet->srcPort = ntohs(header->srcPort);
935  packet->destPort = ntohs(header->destPort);
936  }
937  else
938  {
939  //Report an error
940  error = ERROR_INVALID_PACKET;
941  }
942  }
943  else if(packet->protocol == IPV4_PROTOCOL_UDP)
944  {
945  UdpHeader *header;
946 
947  //Point to the UDP header
948  header = netBufferAt(packet->buffer, packet->offset, sizeof(UdpHeader));
949 
950  //Valid UDP header?
951  if(header != NULL)
952  {
953  //Retrieve source and destination ports
954  packet->srcPort = ntohs(header->srcPort);
955  packet->destPort = ntohs(header->destPort);
956  }
957  else
958  {
959  //Report an error
960  error = ERROR_INVALID_PACKET;
961  }
962  }
963  else if(packet->protocol == IPV4_PROTOCOL_ICMP)
964  {
965  IcmpQueryMessage *header;
966 
967  //Point to the ICMP header
968  header = netBufferAt(packet->buffer, packet->offset,
969  sizeof(IcmpQueryMessage));
970 
971  //Valid ICMP header?
972  if(header != NULL)
973  {
974  //Check the type of ICMP message
975  if(header->type == ICMP_TYPE_ECHO_REQUEST ||
976  header->type == ICMP_TYPE_ECHO_REPLY ||
977  header->type == ICMP_TYPE_TIMESTAMP_REQUEST ||
978  header->type == ICMP_TYPE_TIMESTAMP_REPLY ||
979  header->type == ICMP_TYPE_ADDR_MASK_REQUEST ||
980  header->type == ICMP_TYPE_ADDR_MASK_REPLY)
981  {
982  //Save ICMP message type
983  packet->icmpType = header->type;
984  //Retrieve the value of the identifier
985  packet->icmpQueryId = ntohs(header->identifier);
986  }
987  else
988  {
989  //Report an error
990  error = ERROR_UNKNOWN_TYPE;
991  }
992  }
993  else
994  {
995  //Report an error
996  error = ERROR_INVALID_PACKET;
997  }
998  }
999  else
1000  {
1001  //Unknown protocol
1002  error = ERROR_INVALID_PROTOCOL;
1003  }
1004 
1005  //Return status code
1006  return error;
1007 }
1008 
1009 
1010 /**
1011  * @brief Translate transport header (TCP, UDP or ICMP)
1012  * @param[in] packet IP packet
1013  * @param[in] pseudoHeader Pointer to the pseudo header
1014  * @param[in] buffer Multi-part buffer that holds the IP packet
1015  * @param[in] offset Packet Offset to the payload of the IP packet
1016  * @return Error code
1017  **/
1018 
1020  const Ipv4PseudoHeader *pseudoHeader, const NetBuffer *buffer,
1021  size_t offset)
1022 {
1023  error_t error;
1024 
1025  //Initialize status code
1026  error = NO_ERROR;
1027 
1028  //Check packet type
1029  if(packet->protocol == IPV4_PROTOCOL_TCP)
1030  {
1031  TcpHeader *header;
1032 
1033  //Point to the TCP header
1034  header = netBufferAt(buffer, offset, sizeof(TcpHeader));
1035 
1036  //Valid TCP header?
1037  if(header != NULL)
1038  {
1039  //Replace source and destination ports
1040  header->srcPort = htons(packet->srcPort);
1041  header->destPort = htons(packet->destPort);
1042  header->checksum = 0;
1043 
1044  //Recompute message checksum
1045  header->checksum = ipCalcUpperLayerChecksumEx(pseudoHeader,
1046  sizeof(Ipv4PseudoHeader), buffer, offset,
1047  ntohs(pseudoHeader->length));
1048  }
1049  }
1050  else if(packet->protocol == IPV4_PROTOCOL_UDP)
1051  {
1052  UdpHeader *header;
1053 
1054  //Point to the UDP header
1055  header = netBufferAt(buffer, offset, sizeof(UdpHeader));
1056 
1057  //Valid UDP header?
1058  if(header != NULL)
1059  {
1060  //Replace source and destination ports
1061  header->srcPort = htons(packet->srcPort);
1062  header->destPort = htons(packet->destPort);
1063  header->checksum = 0;
1064 
1065  //Recompute message checksum
1066  header->checksum = ipCalcUpperLayerChecksumEx(pseudoHeader,
1067  sizeof(Ipv4PseudoHeader), buffer, offset,
1068  ntohs(pseudoHeader->length));
1069  }
1070  }
1071  else if(packet->protocol == IPV4_PROTOCOL_ICMP)
1072  {
1073  IcmpQueryMessage *header;
1074 
1075  //Point to the ICMP header
1076  header = netBufferAt(buffer, offset, sizeof(IcmpQueryMessage));
1077 
1078  //Valid ICMP header?
1079  if(header != NULL)
1080  {
1081  //A NAPT device translates the ICMP Query Id and the associated
1082  //checksum in the ICMP header prior to forwarding (refer to
1083  //RFC 5508, section 3.1)
1084  header->identifier = htons(packet->icmpQueryId);
1085  header->checksum = 0;
1086 
1087  //Recompute message checksum
1088  header->checksum = ipCalcChecksumEx(buffer, offset,
1089  ntohs(pseudoHeader->length));
1090  }
1091  }
1092  else
1093  {
1094  //Unknown protocol
1095  error = ERROR_INVALID_PROTOCOL;
1096  }
1097 
1098  //Return status code
1099  return error;
1100 }
1101 
1102 
1103 /**
1104  * @brief Dump IP packet for debugging purpose
1105  * @param[in] packet IP packet
1106  **/
1107 
1108 void natDumpPacket(const NatIpPacket *packet)
1109 {
1110 #if (NAT_TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
1111  size_t length;
1112  const char_t *name;
1113 
1114  //Retrieve the length of the IP packet
1115  length = netBufferGetLength(packet->buffer);
1116 
1117  //Convert the protocol to string representation
1118  if(packet->protocol == IPV4_PROTOCOL_TCP)
1119  {
1120  name = "TCP";
1121  }
1122  else if(packet->protocol == IPV4_PROTOCOL_UDP)
1123  {
1124  name = "UDP";
1125  }
1126  else if(packet->protocol == IPV4_PROTOCOL_ICMP)
1127  {
1128  name = "ICMP";
1129  }
1130  else
1131  {
1132  name = "Unknown";
1133  }
1134 
1135  //Dump IP packet
1136  TRACE_DEBUG(" Length = %" PRIuSIZE "\r\n", length);
1137  TRACE_DEBUG(" Protocol = %d (%s)\r\n", packet->protocol, name);
1138 
1139  //Check packet type
1140  if(packet->protocol == IPV4_PROTOCOL_TCP ||
1141  packet->protocol == IPV4_PROTOCOL_UDP)
1142  {
1143  TRACE_DEBUG(" Src IP Addr = %s\r\n", ipv4AddrToString(packet->srcIpAddr, NULL));
1144  TRACE_DEBUG(" Src Port = %" PRIu16 "\r\n", packet->srcPort);
1145  TRACE_DEBUG(" Dest IP Addr = %s\r\n", ipv4AddrToString(packet->destIpAddr, NULL));
1146  TRACE_DEBUG(" Dest Port = %" PRIu16 "\r\n", packet->destPort);
1147  }
1148  else
1149  {
1150  TRACE_DEBUG(" Src IP Addr = %s\r\n", ipv4AddrToString(packet->srcIpAddr, NULL));
1151  TRACE_DEBUG(" Dest IP Addr = %s\r\n", ipv4AddrToString(packet->destIpAddr, NULL));
1152  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", packet->icmpType);
1153  TRACE_DEBUG(" Identifier = %" PRIu16 "\r\n", packet->icmpQueryId);
1154  }
1155 #endif
1156 }
1157 
1158 #endif
#define ipv4IsMulticastAddr(ipAddr)
Definition: ipv4.h:186
#define htons(value)
Definition: cpu_endian.h:413
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:716
@ ICMP_TYPE_ADDR_MASK_REQUEST
Definition: icmp.h:99
int bool_t
Definition: compiler_port.h:63
#define NAT_TCP_UDP_PORT_MIN
Definition: nat.h:81
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:411
@ IPV4_PROTOCOL_ICMP
Definition: ipv4.h:275
uint16_t ipCalcChecksumEx(const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP checksum over a multi-part buffer.
Definition: ip.c:591
Ipv4Protocol protocol
IP protocol (TCP, UDP or ICMP)
Definition: nat.h:156
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:70
Ipv4Addr destIpAddr
Definition: nat.h:125
uint16_t publicPort
External TCP or UDP port number.
Definition: nat.h:162
size_t offset
Definition: nat.h:121
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
bool_t ipv4IsBroadcastAddr(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is a broadcast address.
Definition: ipv4_misc.c:475
#define TRUE
Definition: os_port.h:50
#define NAT_ICMP_QUERY_ID_MIN
Definition: nat.h:95
systime_t timestamp
Timestamp to manage session timeout.
Definition: nat.h:166
error_t natTranslateOutboundPacket(NatContext *context, NatIpPacket *packet)
Perform address translation (outbound packet)
Definition: nat_misc.c:378
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ICMP_TYPE_TIME_EXCEEDED
Definition: icmp.h:93
#define ipv4IsLinkLocalAddr(ipAddr)
Definition: ipv4.h:182
char_t name[]
NatSession * natMatchSession(NatContext *context, const NatIpPacket *packet)
Search the NAT sessions for a matching entry.
Definition: nat_misc.c:663
@ ICMP_CODE_NET_UNREACHABLE
Definition: icmp.h:111
const NetBuffer * buffer
Definition: nat.h:120
uint16_t privatePortMin
Destination port (lower value)
Definition: nat.h:145
error_t natForwardPacket(NatContext *context, const NatIpPacket *packet)
Forward an IP packet to the specified interface.
Definition: nat_misc.c:521
uint8_t ttl
Definition: nat.h:129
IP packet.
Definition: nat.h:118
error_t natProcessPacket(NatContext *context, NetInterface *inInterface, const Ipv4PseudoHeader *inPseudoHeader, const NetBuffer *inBuffer, size_t inOffset, NetRxAncillary *ancillary)
Process IP packet.
Definition: nat_misc.c:179
const uint8_t res[]
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:322
bool_t natIsPublicInterface(NatContext *context, NetInterface *interface)
Check whether a network interface is the WAN interface.
Definition: nat_misc.c:110
IPv4 context.
Definition: ipv4.h:451
Ipv4Addr srcIpAddr
Definition: nat.h:123
uint16_t srcPort
Definition: nat.h:124
#define NAT_ICMP_SESSION_TIMEOUT
Definition: nat.h:74
uint16_t publicPortMax
Public port range to be redirected (upper value)
Definition: nat.h:142
error_t ipv4CheckDestAddr(NetInterface *interface, Ipv4Addr ipAddr)
Destination IPv4 address filtering.
Definition: ipv4_misc.c:114
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:277
Helper functions for IPv4.
NatSession * natCreateSession(NatContext *context)
Create a new NAT session.
Definition: nat_misc.c:768
#define FALSE
Definition: os_port.h:46
error_t natTranslateTransportHeader(const NatIpPacket *packet, const Ipv4PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Translate transport header (TCP, UDP or ICMP)
Definition: nat_misc.c:1019
uint16_t publicIcmpQueryId
External ICMP query identifier.
Definition: nat.h:163
uint_t numSessions
Number of NAT sessions.
Definition: nat.h:201
uint_t numPortFwdRules
Number of port redirection rules.
Definition: nat.h:199
ICMP (Internet Control Message Protocol)
uint16_t privateIcmpQueryId
Internal ICMP query identifier.
Definition: nat.h:160
error_t
Error codes.
Definition: error.h:43
Ipv4Addr privateIpAddr
Destination IP address.
Definition: nat.h:144
#define NAT_TCP_UDP_PORT_MAX
Definition: nat.h:88
uint16_t publicPortMin
Public port range to be redirected (lower value)
Definition: nat.h:141
NAT context.
Definition: nat.h:192
Ipv4Addr remoteIpAddr
Remote IP address.
Definition: nat.h:164
Port redirection rule.
Definition: nat.h:139
error_t natTranslateInboundPacket(NatContext *context, NatIpPacket *packet)
Perform address translation (inbound packet)
Definition: nat_misc.c:313
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
error_t ipv4SelectSourceAddr(NetContext *context, NetInterface **interface, Ipv4Addr destAddr, Ipv4Addr *srcAddr)
IPv4 source address selection.
Definition: ipv4_misc.c:173
@ ICMP_TYPE_TIMESTAMP_REPLY
Definition: icmp.h:96
uint16_t natAllocateIcmpQueryId(NatContext *context)
Allocate a new ICMP query identifier.
Definition: nat_misc.c:870
uint16_t natAllocatePort(NatContext *context)
Allocate a new port number.
Definition: nat_misc.c:824
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
NatPortFwdRule * portFwdRules
Port redirection rules.
Definition: nat.h:198
error_t natParseTransportHeader(NatIpPacket *packet)
Parse transport header (TCP, UDP or ICMP)
Definition: nat_misc.c:915
uint32_t netGenerateRandRange(NetContext *context, uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:983
#define NetTxAncillary
Definition: net_misc.h:36
Ipv4Protocol protocol
Definition: nat.h:122
@ ERROR_UNKNOWN_TYPE
Definition: error.h:296
NAT (IP Network Address Translator)
uint_t numPrivateInterfaces
Number of private interfaces.
Definition: nat.h:197
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:522
@ ICMP_TYPE_ECHO_REQUEST
Definition: icmp.h:90
#define Ipv4PseudoHeader
Definition: ipv4.h:39
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
void natTick(NatContext *context)
NAT timer handler.
Definition: nat_misc.c:51
bool_t natIsPrivateInterface(NatContext *context, NetInterface *interface)
Check whether a network interface is a LAN interface.
Definition: nat_misc.c:139
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
uint8_t tos
Definition: nat.h:130
Helper functions for NAT.
NatPortFwdRule * natMatchPortFwdRule(NatContext *context, const NatIpPacket *packet)
Search the port forwarding rules for a matching entry.
Definition: nat_misc.c:601
UdpHeader
Definition: udp.h:85
void natDumpPacket(const NatIpPacket *packet)
Dump IP packet for debugging purpose.
Definition: nat_misc.c:1108
uint32_t systime_t
System time.
uint16_t port
Definition: dns_common.h:270
#define ntohs(value)
Definition: cpu_endian.h:421
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
@ ICMP_TYPE_DEST_UNREACHABLE
Definition: icmp.h:86
@ IPV4_PROTOCOL_NONE
Definition: ipv4.h:274
uint16_t icmpQueryId
Definition: nat.h:128
uint32_t time
uint16_t remotePort
Remote TCP or UDP port number.
Definition: nat.h:165
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:691
error_t ipv4SendDatagram(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 datagram.
Definition: ipv4.c:1021
@ ICMP_TYPE_ECHO_REPLY
Definition: icmp.h:85
NetInterface * publicInterface
Public interface.
Definition: nat.h:194
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:278
NetInterface * privateInterfaces[NAT_MAX_PRIVATE_INTERFACES]
Private interfaces.
Definition: nat.h:196
Ipv4AddrEntry addrList[IPV4_ADDR_LIST_SIZE]
IPv4 address list.
Definition: ipv4.h:458
#define NAT_ICMP_QUERY_ID_MAX
Definition: nat.h:102
Ipv4Addr privateIpAddr
Internal IP address.
Definition: nat.h:158
Ipv4Protocol protocol
Transport protocol (TCP or UDP)
Definition: nat.h:140
@ ICMP_TYPE_ADDR_MASK_REPLY
Definition: icmp.h:100
NetInterface * interface
Definition: nat.h:119
NetInterface * privateInterface
Private interface.
Definition: nat.h:157
uint_t publicIpAddrIndex
Index of the public IP address to use.
Definition: nat.h:195
NatSession * sessions
NAT sessions (initiated from a private host)
Definition: nat.h:200
#define NAT_UDP_SESSION_TIMEOUT
Definition: nat.h:67
NetInterface * privateInterface
Destination interface.
Definition: nat.h:143
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
Ipv4Protocol
IPv4 protocol field.
Definition: ipv4.h:273
bool_t running
Operational state of the NAT.
Definition: nat.h:202
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
TcpHeader
Definition: tcp.h:365
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1468
uint16_t privatePortMax
Destination port (upper value)
Definition: nat.h:146
#define NAT_TCP_SESSION_TIMEOUT
Definition: nat.h:60
uint16_t destPort
Definition: nat.h:126
uint16_t icmpType
Definition: nat.h:127
@ ERROR_INVALID_SESSION
Definition: error.h:287
NetContext * netContext
TCP/IP stack context.
Definition: nat.h:193
error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMP Error message.
Definition: icmp.c:335
IcmpQueryMessage
Definition: icmp.h:164
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
uint16_t privatePort
Internal TCP or UDP port number.
Definition: nat.h:159
NAT session.
Definition: nat.h:155
@ ICMP_TYPE_TIMESTAMP_REQUEST
Definition: icmp.h:95
Ipv4Addr publicIpAddr
External IP address.
Definition: nat.h:161
systime_t osGetSystemTime(void)
Retrieve system time.