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