VirtualBox

Opened 13 months ago

Closed 9 months ago

Last modified 5 months ago

#21560 closed defect (fixed)

NAT Network + LWIP: UDP proxy expires too early

Reported by: fth0 Owned by:
Component: network/NAT Version: VirtualBox-7.0.6
Keywords: NAT Network, LWIP UDP proxy Cc:
Guest type: all Host type: all

Description

TL;DR:

When using the NAT Network networking mode, the LWIP UDP proxy expires after being idle for 18 to 21 seconds, which is sometimes less than the intended 20 seconds. There's probably a simple bugfix by changing a comparison operator.


Detailed explanation:

src/VBox/Devices/Network/lwip-new/src/include/lwip/udp.h:

/**
 * Time in seconds a proxy udp pcb is kept alive without outgoing
 * traffic.
 *
 * E.g. RFC 3948 (read "VPN") uses default NAT keepalive of 20
 * seconds.
 */
#define UDP_PROXY_EXPIRATION   20 /* seconds */

#define UDP_PROXY_TMR_INTERVAL 3000 /* milliseconds */

The comment explains the intention to keep the UDP proxy alive for 20 seconds, and a 3 seconds timer is used to implement that, so far, so good.

src/VBox/Devices/Network/lwip-new/src/core/udp.c

void
udp_proxy_input(struct pbuf *p, struct netif *inp)
{
  [...]
  pcb->proxy_cnt = 0;   /* (1) */
  [...]
}

void
udp_proxy_tmr(void)
{
  [...]
  const int limit = ((UDP_PROXY_EXPIRATION /* sec */ * 1000 /* msec/sec */
                      + UDP_PROXY_TMR_INTERVAL /* msec */ - 1)
                     / UDP_PROXY_TMR_INTERVAL /* msec */);   /* (2) */
  [...]
  pprev = &udp_proxy_pcbs;
  pcb = udp_proxy_pcbs;
  while (pcb != NULL) {
    struct udp_pcb *xpcb;

    if (++pcb->proxy_cnt < limit) {   /* (3) */
      pprev = &pcb->next;
      pcb = pcb->next;
      continue;
    }
    [...]
    (*xpcb->recv.ip4)(xpcb->recv_arg, xpcb,
                      NULL, /* signals expiration timeout */
                      ipX_2_ip(&xpcb->remote_ip), xpcb->remote_port);
  }
  [...]
}

(1) Each UDP proxy has a counter which is reset to 0 after each sent packet.

(2) In the timer handling function, the limit variable is calculated to 7 timer intervals (7 * 3 = 21 >= 20). But since the timer is global for all UDP proxies and packets, it was (usually) already running when the last packet was sent. In consequence, the effective idle time of a UDP proxy is (usually) less than the counted timer intervals and a UDP proxy gets expired after being idle for between 18 and 21 seconds, which obviously breaks the goal of the 20-seconds NAT keep alive packets of RFC 3948.

(3) IMHO an easy fix would be to change the comparison with the limit variable from "<" to "<=", leading effectively to idle times of at least 7 full timer intervals (21 to 24 seconds) being allowed.

Change History (4)

comment:1 by fth0, 13 months ago

For the possible implications of this bug (e.g. breaking IPsec VPN connections at seemingly random times), see NAT Network Creates Spurious Translation for IPSEC VPN.

comment:2 by Aleksey Ilyushin, 11 months ago

Thank you for detailed explanation. I've applied your suggested fix, it will be included into the next maintenance release.

comment:3 by galitsyn, 9 months ago

Resolution: fixed
Status: newclosed

Hello,

We just released VirtualBox 7.0.10. This issue should be fixed in this release. Culd you please give it a try? Packages are available on our downloads page.

comment:4 by fth0, 9 months ago

I discovered the bug while investigating another user's issue in the VirtualBox forum. Since the bug fix was done exactly as proposed by me and since I don't have a test setup, I'll assess the bug fix as correct without testing it.

Note: See TracTickets for help on using tickets.

© 2023 Oracle
ContactPrivacy policyTerms of Use