net/nat: Fix ICMP Error MSG Processing
1. Don't assert on IGMP inside ICMP, just ignore it. 2. Check we have full IP header inside ICMP payload before accessing it. 3. `inner_l4hdrbak` need to be `L4_MAXHDRLEN`, not `L4_MAXHDRLEN/2`. Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
980102c536
commit
5a10367312
@ -96,7 +96,7 @@ ipv4_nat_outbound_internal(FAR struct net_driver_s *dev,
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline uint16_t ipv4_nat_l4_hdrlen(uint8_t proto)
|
static inline uint8_t ipv4_nat_l4_hdrlen(uint8_t proto)
|
||||||
{
|
{
|
||||||
switch (proto)
|
switch (proto)
|
||||||
{
|
{
|
||||||
@ -113,7 +113,7 @@ static inline uint16_t ipv4_nat_l4_hdrlen(uint8_t proto)
|
|||||||
return ICMP_HDRLEN;
|
return ICMP_HDRLEN;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
DEBUGASSERT(false);
|
nwarn("WARNING: Unsupported protocol %u inside ICMP\n", proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -336,13 +336,24 @@ ipv4_nat_inbound_icmp(FAR struct ipv4_hdr_s *ipv4,
|
|||||||
|
|
||||||
FAR struct ipv4_hdr_s *inner =
|
FAR struct ipv4_hdr_s *inner =
|
||||||
(FAR struct ipv4_hdr_s *)(icmp + 1);
|
(FAR struct ipv4_hdr_s *)(icmp + 1);
|
||||||
FAR void *inner_l4 = L4_HDR(inner);
|
FAR void *inner_l4;
|
||||||
int16_t inner_l4len = ((ipv4->len[0] << 8) + ipv4->len[1]) -
|
uint16_t outer_l3len = (ipv4->len[0] << 8) + ipv4->len[1];
|
||||||
((intptr_t)inner_l4 - (intptr_t)ipv4);
|
int16_t inner_l4len;
|
||||||
uint16_t inner_l4hdrbak[L4_MAXHDRLEN / 2];
|
int16_t inner_l4hdrlen;
|
||||||
uint16_t inner_l4hdrlen;
|
uint16_t inner_l4hdrbak[L4_MAXHDRLEN];
|
||||||
|
|
||||||
if (inner_l4len < 8)
|
/* Make sure we have a full inner IPv4 header. */
|
||||||
|
|
||||||
|
if (outer_l3len < (uintptr_t)(inner + 1) - (uintptr_t)ipv4)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inner_l4 = L4_HDR(inner);
|
||||||
|
inner_l4len = (intptr_t)ipv4 + outer_l3len - (intptr_t)inner_l4;
|
||||||
|
inner_l4hdrlen = ipv4_nat_l4_hdrlen(inner->proto);
|
||||||
|
inner_l4hdrlen = MIN(inner_l4len, inner_l4hdrlen);
|
||||||
|
if (inner_l4hdrlen < 8)
|
||||||
{
|
{
|
||||||
/* RFC792: The original L4 data should be at least 64 bits. */
|
/* RFC792: The original L4 data should be at least 64 bits. */
|
||||||
|
|
||||||
@ -351,8 +362,6 @@ ipv4_nat_inbound_icmp(FAR struct ipv4_hdr_s *ipv4,
|
|||||||
|
|
||||||
/* Try backup origin L4 header for later checksum update. */
|
/* Try backup origin L4 header for later checksum update. */
|
||||||
|
|
||||||
inner_l4hdrlen = MIN(inner_l4len,
|
|
||||||
ipv4_nat_l4_hdrlen(inner->proto));
|
|
||||||
DEBUGASSERT((intptr_t)inner_l4 - (intptr_t)ipv4 + inner_l4hdrlen
|
DEBUGASSERT((intptr_t)inner_l4 - (intptr_t)ipv4 + inner_l4hdrlen
|
||||||
<= CONFIG_IOB_BUFSIZE);
|
<= CONFIG_IOB_BUFSIZE);
|
||||||
memcpy(inner_l4hdrbak, inner_l4, inner_l4hdrlen);
|
memcpy(inner_l4hdrbak, inner_l4, inner_l4hdrlen);
|
||||||
@ -558,13 +567,24 @@ ipv4_nat_outbound_icmp(FAR struct net_driver_s *dev,
|
|||||||
|
|
||||||
FAR struct ipv4_hdr_s *inner =
|
FAR struct ipv4_hdr_s *inner =
|
||||||
(FAR struct ipv4_hdr_s *)(icmp + 1);
|
(FAR struct ipv4_hdr_s *)(icmp + 1);
|
||||||
FAR void *inner_l4 = L4_HDR(inner);
|
FAR void *inner_l4;
|
||||||
int16_t inner_l4len = ((ipv4->len[0] << 8) + ipv4->len[1]) -
|
uint16_t outer_l3len = (ipv4->len[0] << 8) + ipv4->len[1];
|
||||||
((intptr_t)inner_l4 - (intptr_t)ipv4);
|
int16_t inner_l4len;
|
||||||
uint16_t inner_l4hdrbak[L4_MAXHDRLEN / 2];
|
int16_t inner_l4hdrlen;
|
||||||
uint16_t inner_l4hdrlen;
|
uint16_t inner_l4hdrbak[L4_MAXHDRLEN];
|
||||||
|
|
||||||
if (inner_l4len < 8)
|
/* Make sure we have a full inner IPv4 header. */
|
||||||
|
|
||||||
|
if (outer_l3len < (uintptr_t)(inner + 1) - (uintptr_t)ipv4)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inner_l4 = L4_HDR(inner);
|
||||||
|
inner_l4len = (intptr_t)ipv4 + outer_l3len - (intptr_t)inner_l4;
|
||||||
|
inner_l4hdrlen = ipv4_nat_l4_hdrlen(inner->proto);
|
||||||
|
inner_l4hdrlen = MIN(inner_l4len, inner_l4hdrlen);
|
||||||
|
if (inner_l4hdrlen < 8)
|
||||||
{
|
{
|
||||||
/* RFC792: The original L4 data should be at least 64 bits. */
|
/* RFC792: The original L4 data should be at least 64 bits. */
|
||||||
|
|
||||||
@ -573,8 +593,6 @@ ipv4_nat_outbound_icmp(FAR struct net_driver_s *dev,
|
|||||||
|
|
||||||
/* Try backup origin L4 header for later checksum update. */
|
/* Try backup origin L4 header for later checksum update. */
|
||||||
|
|
||||||
inner_l4hdrlen = MIN(inner_l4len,
|
|
||||||
ipv4_nat_l4_hdrlen(inner->proto));
|
|
||||||
DEBUGASSERT((intptr_t)inner_l4 - (intptr_t)ipv4 + inner_l4hdrlen
|
DEBUGASSERT((intptr_t)inner_l4 - (intptr_t)ipv4 + inner_l4hdrlen
|
||||||
<= CONFIG_IOB_BUFSIZE);
|
<= CONFIG_IOB_BUFSIZE);
|
||||||
memcpy(inner_l4hdrbak, inner_l4, inner_l4hdrlen);
|
memcpy(inner_l4hdrbak, inner_l4, inner_l4hdrlen);
|
||||||
|
Loading…
Reference in New Issue
Block a user