net/nat: Add TCP entry expiration logic
Add TCP entry expiration logic for NAT, with entries changed from sq to dq for fast removal. Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
0a4e01d712
commit
8239ddeef4
|
@ -158,6 +158,10 @@
|
|||
#define sq_for_every(q, p) \
|
||||
for ((p) = (q)->head; (p) != NULL; (p) = (p)->flink)
|
||||
|
||||
#define sq_for_every_safe(q, p, tmp) \
|
||||
for((p) = (q)->head, (tmp) = (p) ? (p)->flink : NULL; \
|
||||
(p) != NULL; (p) = (tmp), (tmp) = (p) ? (p)->flink : NULL)
|
||||
|
||||
#define sq_rem(p, q) \
|
||||
do \
|
||||
{ \
|
||||
|
|
|
@ -9,3 +9,13 @@ config NET_NAT
|
|||
depends on NET_IPFORWARD
|
||||
---help---
|
||||
Enable or disable Network Address Translation (NAT) function.
|
||||
|
||||
config NET_NAT_TCP_EXPIRE_SEC
|
||||
int "TCP NAT entry expiration seconds"
|
||||
default 86400
|
||||
depends on NET_NAT
|
||||
---help---
|
||||
The expiration time for idle TCP entry in NAT.
|
||||
|
||||
Note: The default value 86400 is suggested by RFC2663, Section 2.6,
|
||||
Page 5.
|
||||
|
|
|
@ -79,7 +79,7 @@ static int ipv4_nat_inbound_tcp(FAR struct ipv4_hdr_s *ipv4)
|
|||
FAR struct tcp_hdr_s *tcp =
|
||||
(FAR struct tcp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
|
||||
FAR struct ipv4_nat_entry *entry =
|
||||
ipv4_nat_inbound_entry_find(IP_PROTO_TCP, tcp->destport);
|
||||
ipv4_nat_inbound_entry_find(IP_PROTO_TCP, tcp->destport, true);
|
||||
if (!entry)
|
||||
{
|
||||
/* Inbound without entry is OK (e.g. towards NuttX itself), skip NAT. */
|
||||
|
@ -340,7 +340,7 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev,
|
|||
bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port)
|
||||
{
|
||||
FAR struct ipv4_nat_entry *entry =
|
||||
ipv4_nat_inbound_entry_find(protocol, port);
|
||||
ipv4_nat_inbound_entry_find(protocol, port, false);
|
||||
|
||||
/* Not checking ip is enough for single NAT device, may save external_ip in
|
||||
* entry for multiple device support in future.
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/queue.h>
|
||||
|
||||
|
@ -37,7 +38,7 @@
|
|||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static sq_queue_t g_entries;
|
||||
static dq_queue_t g_entries;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
|
@ -69,6 +70,45 @@ static uint16_t ipv4_nat_select_port(uint8_t protocol, uint16_t local_port)
|
|||
return local_port;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_entry_refresh
|
||||
*
|
||||
* Description:
|
||||
* Refresh a NAT entry, update its expiration time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* entry - The entry to refresh.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry)
|
||||
{
|
||||
switch (entry->protocol)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case IP_PROTO_TCP:
|
||||
/* NOTE: According to RFC2663, Section 2.6, Page 5, we can reduce the
|
||||
* time to 4min if we have received FINs from both side of one
|
||||
* connection, and keep 24h for other TCP connections. However, full
|
||||
* cone NAT may have multiple connections on one entry, so this
|
||||
* optimization may not work and we only use one expiration time.
|
||||
*/
|
||||
|
||||
entry->expire_time = TICK2SEC(clock_systime_ticks()) +
|
||||
CONFIG_NET_NAT_TCP_EXPIRE_SEC;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
# warning Missing logic
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_ICMP
|
||||
# warning Missing logic
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_entry_create
|
||||
*
|
||||
|
@ -103,10 +143,33 @@ ipv4_nat_entry_create(uint8_t protocol, uint16_t external_port,
|
|||
entry->local_ip = local_ip;
|
||||
entry->local_port = local_port;
|
||||
|
||||
sq_addfirst((FAR sq_entry_t *)entry, &g_entries);
|
||||
ipv4_nat_entry_refresh(entry);
|
||||
|
||||
dq_addfirst((FAR dq_entry_t *)entry, &g_entries);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_entry_delete
|
||||
*
|
||||
* Description:
|
||||
* Delete a NAT entry and remove from entry list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* entry - The entry to remove.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void ipv4_nat_entry_delete(FAR struct ipv4_nat_entry *entry)
|
||||
{
|
||||
ninfo("INFO: Removing NAT entry proto=%d, local=%x:%d, external=:%d\n",
|
||||
entry->protocol, entry->local_ip, entry->local_port,
|
||||
entry->external_port);
|
||||
|
||||
dq_rem((FAR dq_entry_t *)entry, &g_entries);
|
||||
kmm_free(entry);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -120,6 +183,7 @@ ipv4_nat_entry_create(uint8_t protocol, uint16_t external_port,
|
|||
* Input Parameters:
|
||||
* protocol - The L4 protocol of the packet.
|
||||
* external_port - The external port of the packet.
|
||||
* refresh - Whether to refresh the selected entry.
|
||||
*
|
||||
* Returned Value:
|
||||
* Pointer to entry on success; null on failure
|
||||
|
@ -127,17 +191,35 @@ ipv4_nat_entry_create(uint8_t protocol, uint16_t external_port,
|
|||
****************************************************************************/
|
||||
|
||||
FAR struct ipv4_nat_entry *
|
||||
ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port)
|
||||
ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port,
|
||||
bool refresh)
|
||||
{
|
||||
FAR sq_entry_t *p;
|
||||
sq_for_every(&g_entries, p)
|
||||
FAR sq_entry_t *tmp;
|
||||
uint32_t current_time = TICK2SEC(clock_systime_ticks());
|
||||
|
||||
sq_for_every_safe((FAR sq_queue_t *)&g_entries, p, tmp)
|
||||
{
|
||||
FAR struct ipv4_nat_entry *entry = (FAR struct ipv4_nat_entry *)p;
|
||||
|
||||
/* Remove expired entries. */
|
||||
|
||||
if (entry->expire_time < current_time)
|
||||
{
|
||||
ipv4_nat_entry_delete(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->protocol == protocol &&
|
||||
entry->external_port == external_port)
|
||||
{
|
||||
/* TODO: Use hash table, or move recent node to head. */
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
ipv4_nat_entry_refresh(entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
@ -169,15 +251,28 @@ ipv4_nat_outbound_entry_find(uint8_t protocol, in_addr_t local_ip,
|
|||
uint16_t local_port)
|
||||
{
|
||||
FAR sq_entry_t *p;
|
||||
sq_for_every(&g_entries, p)
|
||||
FAR sq_entry_t *tmp;
|
||||
uint32_t current_time = TICK2SEC(clock_systime_ticks());
|
||||
|
||||
sq_for_every_safe((FAR sq_queue_t *)&g_entries, p, tmp)
|
||||
{
|
||||
FAR struct ipv4_nat_entry *entry = (FAR struct ipv4_nat_entry *)p;
|
||||
|
||||
/* Remove expired entries. */
|
||||
|
||||
if (entry->expire_time < current_time)
|
||||
{
|
||||
ipv4_nat_entry_delete(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->protocol == protocol &&
|
||||
net_ipv4addr_cmp(entry->local_ip, local_ip) &&
|
||||
entry->local_port == local_port)
|
||||
{
|
||||
/* TODO: Use hash table, or move recent node to head. */
|
||||
|
||||
ipv4_nat_entry_refresh(entry);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,13 +43,14 @@
|
|||
|
||||
struct ipv4_nat_entry
|
||||
{
|
||||
/* Support for single-linked lists.
|
||||
/* Support for doubly-linked lists.
|
||||
*
|
||||
* TODO: Implement a general hash table, and use it to optimize performance
|
||||
* here.
|
||||
*/
|
||||
|
||||
FAR struct ipv4_nat_entry *flink;
|
||||
FAR struct ipv4_nat_entry *blink;
|
||||
|
||||
/* Local Network External Network
|
||||
* |----------------|
|
||||
|
@ -67,7 +68,7 @@ struct ipv4_nat_entry
|
|||
uint16_t external_port; /* The external port of local (private) host. */
|
||||
uint8_t protocol; /* L4 protocol (TCP, UDP etc). */
|
||||
|
||||
/* TODO: Timeout check and remove outdated entry. */
|
||||
uint32_t expire_time; /* The expiration time of this entry. */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -184,6 +185,7 @@ bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port);
|
|||
* Input Parameters:
|
||||
* protocol - The L4 protocol of the packet.
|
||||
* external_port - The external port of the packet.
|
||||
* refresh - Whether to refresh the selected entry.
|
||||
*
|
||||
* Returned Value:
|
||||
* Pointer to entry on success; null on failure
|
||||
|
@ -191,7 +193,8 @@ bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port);
|
|||
****************************************************************************/
|
||||
|
||||
FAR struct ipv4_nat_entry *
|
||||
ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port);
|
||||
ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port,
|
||||
bool refresh);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipv4_nat_outbound_entry_find
|
||||
|
|
Loading…
Reference in New Issue