net/nat: Add UDP support
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
8d401db5b9
commit
a3a669a5f6
@ -20,6 +20,17 @@ config NET_NAT_TCP_EXPIRE_SEC
|
|||||||
Note: The default value 86400 is suggested by RFC2663, Section 2.6,
|
Note: The default value 86400 is suggested by RFC2663, Section 2.6,
|
||||||
Page 5.
|
Page 5.
|
||||||
|
|
||||||
|
config NET_NAT_UDP_EXPIRE_SEC
|
||||||
|
int "UDP NAT entry expiration seconds"
|
||||||
|
default 240
|
||||||
|
depends on NET_NAT
|
||||||
|
---help---
|
||||||
|
The expiration time for idle UDP entry in NAT.
|
||||||
|
|
||||||
|
Note: RFC2663 (Section 2.6, Page 5) suggests that non-TCP sessions
|
||||||
|
that have not been used for a couple of minutes can be assumed to be
|
||||||
|
terminated.
|
||||||
|
|
||||||
config NET_NAT_ICMP_EXPIRE_SEC
|
config NET_NAT_ICMP_EXPIRE_SEC
|
||||||
int "ICMP NAT entry expiration seconds"
|
int "ICMP NAT entry expiration seconds"
|
||||||
default 60
|
default 60
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <nuttx/net/icmp.h>
|
#include <nuttx/net/icmp.h>
|
||||||
#include <nuttx/net/tcp.h>
|
#include <nuttx/net/tcp.h>
|
||||||
|
#include <nuttx/net/udp.h>
|
||||||
|
|
||||||
#include "nat/nat.h"
|
#include "nat/nat.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
@ -103,6 +104,65 @@ static int ipv4_nat_inbound_tcp(FAR struct ipv4_hdr_s *ipv4)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: ipv4_nat_inbound_udp
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check if a received UDP 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 NAT device and is targeting at the address
|
||||||
|
* assigned to the device.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP
|
||||||
|
static int ipv4_nat_inbound_udp(FAR struct ipv4_hdr_s *ipv4)
|
||||||
|
{
|
||||||
|
uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
|
||||||
|
FAR struct udp_hdr_s *udp =
|
||||||
|
(FAR struct udp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
|
||||||
|
FAR struct ipv4_nat_entry *entry =
|
||||||
|
ipv4_nat_inbound_entry_find(IP_PROTO_UDP, udp->destport, true);
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
/* Inbound without entry is OK (e.g. towards NuttX itself), skip NAT. */
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modify port and checksum. */
|
||||||
|
|
||||||
|
if (udp->udpchksum != 0) /* UDP checksum has special case 0 (no checksum) */
|
||||||
|
{
|
||||||
|
chksum_adjust(udp->udpchksum, udp->destport, entry->local_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
udp->destport = entry->local_port;
|
||||||
|
|
||||||
|
/* Modify address and checksum. */
|
||||||
|
|
||||||
|
if (udp->udpchksum != 0) /* UDP checksum has special case 0 (no checksum) */
|
||||||
|
{
|
||||||
|
chksum_adjust(udp->udpchksum, ipv4->destipaddr, entry->local_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
chksum_adjust(ipv4->ipchksum, ipv4->destipaddr, entry->local_ip);
|
||||||
|
net_ipv4addr_hdrcopy(ipv4->destipaddr, &entry->local_ip);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: ipv4_nat_inbound_icmp
|
* Name: ipv4_nat_inbound_icmp
|
||||||
*
|
*
|
||||||
@ -213,6 +273,66 @@ static int ipv4_nat_outbound_tcp(FAR struct net_driver_s *dev,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: ipv4_nat_outbound_udp
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check if we want to perform NAT with this outbound UDP 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_UDP
|
||||||
|
static int ipv4_nat_outbound_udp(FAR struct net_driver_s *dev,
|
||||||
|
FAR struct ipv4_hdr_s *ipv4)
|
||||||
|
{
|
||||||
|
uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
|
||||||
|
FAR struct udp_hdr_s *udp =
|
||||||
|
(FAR struct udp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
|
||||||
|
FAR struct ipv4_nat_entry *entry = ipv4_nat_outbound_entry_find(
|
||||||
|
dev, IP_PROTO_UDP, net_ip4addr_conv32(ipv4->srcipaddr), udp->srcport);
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
/* Outbound entry creation failed, should have corresponding entry. */
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modify port and checksum. */
|
||||||
|
|
||||||
|
if (udp->udpchksum != 0) /* UDP checksum has special case 0 (no checksum) */
|
||||||
|
{
|
||||||
|
chksum_adjust(udp->udpchksum, udp->srcport, entry->external_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
udp->srcport = entry->external_port;
|
||||||
|
|
||||||
|
/* Modify address and checksum. */
|
||||||
|
|
||||||
|
if (udp->udpchksum != 0) /* UDP checksum has special case 0 (no checksum) */
|
||||||
|
{
|
||||||
|
chksum_adjust(udp->udpchksum, ipv4->srcipaddr, dev->d_ipaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
chksum_adjust(ipv4->ipchksum, ipv4->srcipaddr, dev->d_ipaddr);
|
||||||
|
net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: ipv4_nat_outbound_icmp
|
* Name: ipv4_nat_outbound_icmp
|
||||||
*
|
*
|
||||||
@ -379,7 +499,8 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_UDP
|
#ifdef CONFIG_NET_UDP
|
||||||
# warning Missing logic
|
case IP_PROTO_UDP:
|
||||||
|
return ipv4_nat_inbound_udp(ipv4);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_ICMP
|
#ifdef CONFIG_NET_ICMP
|
||||||
@ -430,7 +551,8 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_UDP
|
#ifdef CONFIG_NET_UDP
|
||||||
# warning Missing logic
|
case IP_PROTO_UDP:
|
||||||
|
return ipv4_nat_outbound_udp(dev, ipv4);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_ICMP
|
#ifdef CONFIG_NET_ICMP
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "icmp/icmp.h"
|
#include "icmp/icmp.h"
|
||||||
#include "nat/nat.h"
|
#include "nat/nat.h"
|
||||||
#include "tcp/tcp.h"
|
#include "tcp/tcp.h"
|
||||||
|
#include "udp/udp.h"
|
||||||
|
|
||||||
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
||||||
|
|
||||||
@ -145,7 +146,22 @@ static uint16_t ipv4_nat_select_port(FAR struct net_driver_s *dev,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_UDP
|
#ifdef CONFIG_NET_UDP
|
||||||
# warning Missing logic
|
case IP_PROTO_UDP:
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_NET_UDP_NO_STACK
|
||||||
|
union ip_binding_u u;
|
||||||
|
u.ipv4.laddr = dev->d_draddr;
|
||||||
|
u.ipv4.raddr = INADDR_ANY;
|
||||||
|
|
||||||
|
/* TODO: Try keep origin port as possible. */
|
||||||
|
|
||||||
|
return HTONS(udp_select_port(PF_INET, &u));
|
||||||
|
#else
|
||||||
|
return ipv4_nat_select_port_without_stack(IP_PROTO_UDP,
|
||||||
|
dev->d_draddr,
|
||||||
|
local_port);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_ICMP
|
#ifdef CONFIG_NET_ICMP
|
||||||
@ -212,7 +228,10 @@ static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_UDP
|
#ifdef CONFIG_NET_UDP
|
||||||
# warning Missing logic
|
case IP_PROTO_UDP:
|
||||||
|
entry->expire_time = TICK2SEC(clock_systime_ticks()) +
|
||||||
|
CONFIG_NET_NAT_UDP_EXPIRE_SEC;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_ICMP
|
#ifdef CONFIG_NET_ICMP
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#include <nuttx/net/udp.h>
|
#include <nuttx/net/udp.h>
|
||||||
|
|
||||||
#include "devif/devif.h"
|
#include "devif/devif.h"
|
||||||
|
#include "nat/nat.h"
|
||||||
#include "netdev/netdev.h"
|
#include "netdev/netdev.h"
|
||||||
#include "inet/inet.h"
|
#include "inet/inet.h"
|
||||||
#include "udp/udp.h"
|
#include "udp/udp.h"
|
||||||
@ -533,7 +534,13 @@ uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
|
|||||||
g_last_udp_port = 4096;
|
g_last_udp_port = 4096;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (udp_find_conn(domain, u, HTONS(g_last_udp_port)) != NULL);
|
while (udp_find_conn(domain, u, HTONS(g_last_udp_port)) != NULL
|
||||||
|
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
||||||
|
|| (domain == PF_INET &&
|
||||||
|
ipv4_nat_port_inuse(IP_PROTO_UDP, u->ipv4.laddr,
|
||||||
|
HTONS(g_last_udp_port)))
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
/* Initialize and return the connection structure, bind it to the
|
/* Initialize and return the connection structure, bind it to the
|
||||||
* port number
|
* port number
|
||||||
@ -816,7 +823,13 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr)
|
|||||||
* and port ?
|
* and port ?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (udp_find_conn(conn->domain, &conn->u, portno) == NULL)
|
if (udp_find_conn(conn->domain, &conn->u, portno) == NULL
|
||||||
|
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
|
||||||
|
&& !(conn->domain == PF_INET &&
|
||||||
|
ipv4_nat_port_inuse(IP_PROTO_UDP, conn->u.ipv4.laddr,
|
||||||
|
portno))
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
/* No.. then bind the socket to the port */
|
/* No.. then bind the socket to the port */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user