net/nat: Add ICMP ECHO (REQUEST & REPLY) support
Support ICMP ECHO REQUEST & REPLY. Id of ICMP is processed like port of TCP in NAT. However, our ICMP stack doesn't have a method to manage id allocation like tcp_selectport(), the id is set by apps (like icmp_ping.c) without conflict avoidance, so not adding such conflict avoidance logic to ICMP stack when implementing NAT. Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
f498102512
commit
8d401db5b9
@ -19,3 +19,13 @@ config NET_NAT_TCP_EXPIRE_SEC
|
||||
|
||||
Note: The default value 86400 is suggested by RFC2663, Section 2.6,
|
||||
Page 5.
|
||||
|
||||
config NET_NAT_ICMP_EXPIRE_SEC
|
||||
int "ICMP NAT entry expiration seconds"
|
||||
default 60
|
||||
depends on NET_NAT
|
||||
---help---
|
||||
The expiration time for idle ICMP entry in NAT.
|
||||
|
||||
Note: The default value 60 is suggested by RFC5508, Section 3.2,
|
||||
Page 8.
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/net/icmp.h>
|
||||
#include <nuttx/net/tcp.h>
|
||||
|
||||
#include "nat/nat.h"
|
||||
@ -102,6 +103,64 @@ static int ipv4_nat_inbound_tcp(FAR struct ipv4_hdr_s *ipv4)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_inbound_icmp
|
||||
*
|
||||
* Description:
|
||||
* Check if a received ICMP packet belongs to a NAT entry. If so, translate
|
||||
* it.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ipv4 - Points to the IPv4 header with dev->d_buf.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if NAT is successfully applied, or is not enabled for
|
||||
* this packet;
|
||||
* A negated errno value is returned if error occured.
|
||||
*
|
||||
* Assumptions:
|
||||
* Packet is received on g_dev and is targeting at the address assigned to
|
||||
* g_dev.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
static int ipv4_nat_inbound_icmp(FAR struct ipv4_hdr_s *ipv4)
|
||||
{
|
||||
uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
|
||||
FAR struct icmp_hdr_s *icmp =
|
||||
(FAR struct icmp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
|
||||
FAR struct ipv4_nat_entry *entry;
|
||||
|
||||
switch (icmp->type)
|
||||
{
|
||||
/* TODO: Support other ICMP types. */
|
||||
|
||||
case ICMP_ECHO_REQUEST:
|
||||
case ICMP_ECHO_REPLY:
|
||||
entry = ipv4_nat_inbound_entry_find(IP_PROTO_ICMP, icmp->id, true);
|
||||
if (!entry)
|
||||
{
|
||||
/* Inbound without entry is OK, skip NAT. */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Modify id and checksum. */
|
||||
|
||||
chksum_adjust(icmp->icmpchksum, icmp->id, entry->local_port);
|
||||
icmp->id = entry->local_port;
|
||||
|
||||
/* Modify address and checksum. */
|
||||
|
||||
chksum_adjust(ipv4->ipchksum, ipv4->destipaddr, entry->local_ip);
|
||||
net_ipv4addr_hdrcopy(ipv4->destipaddr, &entry->local_ip);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_outbound_tcp
|
||||
*
|
||||
@ -154,6 +213,67 @@ static int ipv4_nat_outbound_tcp(FAR struct net_driver_s *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_outbound_icmp
|
||||
*
|
||||
* Description:
|
||||
* Check if we want to perform NAT with this outbound ICMP packet before
|
||||
* sending it. If so, translate it.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - The device to sent the packet.
|
||||
* ipv4 - Points to the IPv4 header to be filled into dev->d_buf later.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned if NAT is successfully applied, or is not enabled for
|
||||
* this packet;
|
||||
* A negated errno value is returned if error occured.
|
||||
*
|
||||
* Assumptions:
|
||||
* Packet will be sent on NAT device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
static int ipv4_nat_outbound_icmp(FAR struct net_driver_s *dev,
|
||||
FAR struct ipv4_hdr_s *ipv4)
|
||||
{
|
||||
uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
|
||||
FAR struct icmp_hdr_s *icmp =
|
||||
(FAR struct icmp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
|
||||
FAR struct ipv4_nat_entry *entry;
|
||||
|
||||
switch (icmp->type)
|
||||
{
|
||||
/* TODO: Support other ICMP types. */
|
||||
|
||||
case ICMP_ECHO_REQUEST:
|
||||
case ICMP_ECHO_REPLY:
|
||||
entry = ipv4_nat_outbound_entry_find(
|
||||
dev, IP_PROTO_ICMP, net_ip4addr_conv32(ipv4->srcipaddr),
|
||||
icmp->id);
|
||||
if (!entry)
|
||||
{
|
||||
/* Outbound entry creation failed. */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Modify id and checksum. */
|
||||
|
||||
chksum_adjust(icmp->icmpchksum, icmp->id, entry->external_port);
|
||||
icmp->id = entry->external_port;
|
||||
|
||||
/* Modify address and checksum. */
|
||||
|
||||
chksum_adjust(ipv4->ipchksum, ipv4->srcipaddr, dev->d_ipaddr);
|
||||
net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -263,7 +383,8 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
# warning Missing logic
|
||||
case IP_PROTO_ICMP:
|
||||
return ipv4_nat_inbound_icmp(ipv4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -313,7 +434,8 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
# warning Missing logic
|
||||
case IP_PROTO_ICMP:
|
||||
return ipv4_nat_outbound_icmp(dev, ipv4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -30,11 +30,21 @@
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/queue.h>
|
||||
|
||||
#include "icmp/icmp.h"
|
||||
#include "nat/nat.h"
|
||||
#include "tcp/tcp.h"
|
||||
|
||||
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* TODO: Why we limit to 32000 in net stack? */
|
||||
|
||||
#define NAT_PORT_REASSIGN_MAX 32000
|
||||
#define NAT_PORT_REASSIGN_MIN 4096
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -72,9 +82,9 @@ static uint16_t ipv4_nat_select_port_without_stack(
|
||||
uint16_t hport = NTOHS(portno);
|
||||
while (ipv4_nat_port_inuse(protocol, ip, portno))
|
||||
{
|
||||
if (++hport >= 32000) /* TODO: Why we limit to 32000 in net stack? */
|
||||
if (++hport >= NAT_PORT_REASSIGN_MAX)
|
||||
{
|
||||
hport = 4096;
|
||||
hport = NAT_PORT_REASSIGN_MIN;
|
||||
}
|
||||
|
||||
portno = HTONS(hport);
|
||||
@ -139,7 +149,29 @@ static uint16_t ipv4_nat_select_port(FAR struct net_driver_s *dev,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
# warning Missing logic
|
||||
case IP_PROTO_ICMP:
|
||||
{
|
||||
#ifdef CONFIG_NET_ICMP_SOCKET
|
||||
uint16_t id = local_port;
|
||||
uint16_t hid = NTOHS(id);
|
||||
while (icmp_findconn(dev, id) ||
|
||||
ipv4_nat_port_inuse(IP_PROTO_ICMP, dev->d_draddr, id))
|
||||
{
|
||||
if (++hid >= NAT_PORT_REASSIGN_MAX)
|
||||
{
|
||||
hid = NAT_PORT_REASSIGN_MIN;
|
||||
}
|
||||
|
||||
id = HTONS(hid);
|
||||
}
|
||||
|
||||
return id;
|
||||
#else
|
||||
return ipv4_nat_select_port_without_stack(IP_PROTO_ICMP,
|
||||
dev->d_draddr,
|
||||
local_port);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -184,7 +216,10 @@ static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
# warning Missing logic
|
||||
case IP_PROTO_ICMP:
|
||||
entry->expire_time = TICK2SEC(clock_systime_ticks()) +
|
||||
CONFIG_NET_NAT_ICMP_EXPIRE_SEC;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user