xbox-kernel/private/ntos/net/ipicmp.cpp
2020-09-30 17:17:25 +02:00

318 lines
12 KiB
C++

// ---------------------------------------------------------------------------------------
// ipicmp.cpp
//
// Copyright (C) Microsoft Corporation
// ---------------------------------------------------------------------------------------
#include "xnp.h"
#include "xnver.h"
// ---------------------------------------------------------------------------------------
// CIcmpHdr
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_ICMP
#include <pshpack1.h>
class CIcmpHdr
{
// Definitions -----------------------------------------------------------------------
#define ICMPTYPE_ECHO_REPLY 0
#define ICMPTYPE_DESTINATION_UNREACHABLE 3
#define ICMPCODE_NET_UNREACHABLE 0
#define ICMPCODE_HOST_UNREACHABLE 1
#define ICMPCODE_PROTOCOL_UNREACHABLE 2
#define ICMPCODE_PORT_UNREACHABLE 3
#define ICMPCODE_CANT_FRAGMENT_WITH_DF 4
#define ICMPCODE_SRCROUTE_FAILED 5
#define ICMPCODE_DEST_NET_UNKNOWN 6
#define ICMPCODE_DEST_HOST_UNKNOWN 7
#define ICMPCODE_SRC_HOST_ISOLATED 8
#define ICMPCODE_DEST_NET_PROHIBITED 9
#define ICMPCODE_DEST_HOST_PROHIBITED 10
#define ICMPCODE_NET_UNREACHABLE_TOS 11
#define ICMPCODE_HOST_UNREACHABLE_TOS 12
#define ICMPTYPE_SOURCE_QUENCH 4
#define ICMPTYPE_REDIRECT 5
#define ICMPCODE_REDIRECT_NET 0
#define ICMPCODE_REDIRECT_HOST 1
#define ICMPCODE_REDIRECT_NET_TOS 2
#define ICMPCODE_REDIRECT_HOST_TOS 3
#define ICMPTYPE_ECHO_REQUEST 8
#define ICMPTYPE_ROUTER_ADVERTISEMENT 9
#define ICMPTYPE_ROUTER_SOLICIATION 10
#define ICMPTYPE_TIME_EXCEEDED 11
#define ICMPCODE_TTL_EXCEEDED 0
#define ICMPCODE_REASSEMBLY_TIMEOUT 1
#define ICMPTYPE_PARAMETER_PROBLEM 12
#define ICMPCODE_PTR_INDICATES_ERROR 0
#define ICMPCODE_MISSING_REQD_OPTION 1
#define ICMPTYPE_TIMESTAMP_REQUEST 13
#define ICMPTYPE_TIMESTAMP_REPLY 14
#define ICMPTYPE_INFORMATION_REQUEST 15
#define ICMPTYPE_INFORMATION_REPLY 16
#define ICMPTYPE_ADDRESSMASK_REQUEST 17
#define ICMPTYPE_ADDRESSMASK_REPLY 18
// Trace Support ---------------------------------------------------------------------
public:
char * Str()
{
switch (_bType)
{
case ICMPTYPE_ECHO_REPLY:
return("Echo Reply");
break;
case ICMPTYPE_DESTINATION_UNREACHABLE:
{
switch (_bCode)
{
case ICMPCODE_NET_UNREACHABLE:
return("Net Unreachable");
case ICMPCODE_HOST_UNREACHABLE:
return("Host Unreachable");
case ICMPCODE_PROTOCOL_UNREACHABLE:
return("Protocol Unreachable");
case ICMPCODE_PORT_UNREACHABLE:
return("Port Unreachable");
case ICMPCODE_CANT_FRAGMENT_WITH_DF:
return("Can't Fragment With DF");
case ICMPCODE_SRCROUTE_FAILED:
return("Source Route Failed");
case ICMPCODE_DEST_NET_UNKNOWN:
return("Destination Net Unknown");
case ICMPCODE_DEST_HOST_UNKNOWN:
return("Destination Host Unknown");
case ICMPCODE_SRC_HOST_ISOLATED:
return("Source Host Isolated");
case ICMPCODE_DEST_NET_PROHIBITED:
return("Destination Net Prohibited");
case ICMPCODE_NET_UNREACHABLE_TOS:
return("Network Unreachable For Tos");
case ICMPCODE_HOST_UNREACHABLE_TOS:
return("Host Unreachable For Tos");
default:
return("Destination Unreachable");
}
}
case ICMPTYPE_SOURCE_QUENCH:
return("Source Quench");
break;
case ICMPTYPE_REDIRECT:
{
switch (_bCode)
{
case ICMPCODE_REDIRECT_NET:
return("Redirect Datagrams For Net");
case ICMPCODE_REDIRECT_HOST:
return("Redirect Datagrams For Host");
case ICMPCODE_REDIRECT_NET_TOS:
return("Redirect Datagrams For Net And Tos");
case ICMPCODE_REDIRECT_HOST_TOS:
return("Redirect Datagrams For Host And Tos");
default:
return("Redirect");
}
}
case ICMPTYPE_ECHO_REQUEST:
return("Echo Request");
break;
case ICMPTYPE_ROUTER_ADVERTISEMENT:
return("Router Advertisement");
break;
case ICMPTYPE_TIME_EXCEEDED:
{
switch (_bCode)
{
case ICMPCODE_TTL_EXCEEDED:
return("Ttl Exceeded");
case ICMPCODE_REASSEMBLY_TIMEOUT:
return("Reassembly Timeout");
default:
return("Time Exceeded");
}
}
case ICMPTYPE_PARAMETER_PROBLEM:
{
switch (_bCode)
{
case ICMPCODE_MISSING_REQD_OPTION:
return("Missing Required Option");
default:
return("Parameter Problem");
}
}
case ICMPTYPE_TIMESTAMP_REQUEST:
return("Timestamp Request");
case ICMPTYPE_TIMESTAMP_REPLY:
return("Timestamp Reply");
case ICMPTYPE_INFORMATION_REQUEST:
return("Information Request");
case ICMPTYPE_INFORMATION_REPLY:
return("Information Reply");
case ICMPTYPE_ADDRESSMASK_REQUEST:
return("Address Mask Request");
case ICMPTYPE_ADDRESSMASK_REPLY:
return("Address Mask Reply");
default:
return("Unknown");
}
}
// Data ------------------------------------------------------------------------------
public:
BYTE _bType; // One of ICMPTYPE_* above
BYTE _bCode; // One of ICMPCODE_* above
WORD _wChecksum; // Checksum
DWORD _dwData; // Data (depends on _bType)
};
#include <poppack.h>
// ---------------------------------------------------------------------------------------
// CXnIp::IcmpRecv
// ---------------------------------------------------------------------------------------
void CXnIp::IcmpRecv(CPacket* ppkt, CIpHdr * pIpHdr, void * pvData, UINT cbData)
{
ICHECK(IP, UDPC|SDPC);
if (cbData < sizeof(CIcmpHdr))
{
TraceSz1(pktWarn, "[DISCARD] ICMP header doesn't fit in the packet (%d bytes)", cbData);
return;
}
if (tcpipxsum(0, pvData, cbData) != 0xFFFF)
{
TraceSz(pktWarn, "[DISCARD] ICMP header checksum failed");
return;
}
CIcmpHdr * pIcmpHdr = (CIcmpHdr *)pvData;
TraceSz4(pktRecv, "[ICMP <%d/%d> %s][cb=%d]",
pIcmpHdr->_bType, pIcmpHdr->_bCode, pIcmpHdr->Str(),
cbData - sizeof(CIcmpHdr));
if (ppkt->TestFlags(PKTF_RECV_BROADCAST|PKTF_RECV_LOOPBACK))
{
TraceSz1(pktWarn, "[DISCARD] ICMP packet received via %s",
ppkt->TestFlags(PKTF_RECV_BROADCAST) ? "broadcast" : "loopback");
return;
}
#ifdef XNET_FEATURE_ROUTE
if ( pIcmpHdr->_bType == ICMPTYPE_REDIRECT
&& ( pIcmpHdr->_bCode == ICMPCODE_REDIRECT_NET
|| pIcmpHdr->_bCode == ICMPCODE_REDIRECT_HOST
|| pIcmpHdr->_bCode == ICMPCODE_REDIRECT_NET_TOS
|| pIcmpHdr->_bCode == ICMPCODE_REDIRECT_HOST_TOS))
{
pvData = (BYTE *)pvData + sizeof(CIcmpHdr);
cbData -= sizeof(CIcmpHdr);
if (cbData < sizeof(CIpHdr))
{
TraceSz(pktWarn, "[DISCARD] ICMP embedded IP header doesn't fit in the packet");
return;
}
CIpHdr * pIpHdrIcmp = (CIpHdr *)pvData;
UINT cbIpHdrIcmp = pIpHdrIcmp->VerifyHdrLen();
if (cbIpHdrIcmp == 0)
{
TraceSz(pktWarn, "[DISCARD] ICMP embedded IP header version is incorrect");
return;
}
if (cbData < (cbIpHdrIcmp + 8))
{
TraceSz(pktWarn, "[DISCARD] ICMP embedded IP header and 64-bits of data doesn't fit in the packet");
return;
}
// The embedded IP header is supposed to have originated from this host, and
// we would never have added IP options, so we can check that here.
if (cbIpHdrIcmp != sizeof(CIpHdr))
{
TraceSz(pktWarn, "[DISCARD] ICMP embedded IP header has options");
return;
}
TraceSz3(pktRecv, "[REDIRECT] Rerouting %s from gateway %s to gateway %s",
pIpHdrIcmp->_ipaDst.Str(), pIpHdr->_ipaSrc.Str(), CIpAddr(pIcmpHdr->_dwData).Str());
RouteRedirect(pIpHdrIcmp->_ipaDst, pIpHdr->_ipaSrc, CIpAddr(pIcmpHdr->_dwData));
return;
}
#endif
if (pIcmpHdr->_bType == ICMPTYPE_ECHO_REQUEST)
{
if (!pIpHdr->_ipaSrc.IsValidUnicast())
{
TraceSz1(pktWarn, "[DISCARD] ICMP echo from bad source address %s",
pIpHdr->_ipaSrc.Str());
return;
}
if (pIpHdr->GetOptLen() > 0)
{
TraceSz(pktWarn, "[DISCARD] ICMP echo packet with IP header options");
return;
}
// Don't allow Ping'er to make us consume gratuitous amounts of pool memory
if (cbData > sizeof(CIcmpHdr) + 64)
{
TraceSz1(pktWarn, "[DISCARD] ICMP echo request with too much optional data (%d)",
cbData - sizeof(CIcmpHdr));
return;
}
CPacket * ppktReply = PacketAlloc(PTAG_CIcmpEchoPacket,
PKTF_TYPE_IP|PKTF_XMIT_INSECURE|PKTF_POOLALLOC,
cbData);
if (ppktReply == NULL)
{
TraceSz(pktWarn, "[DISCARD] Out of memory allocating ICMP echo reply packet");
return;
}
CIpHdr * pIpHdrReply = ppktReply->GetIpHdr();
memcpy(pIpHdrReply, pIpHdr, sizeof(CIpHdr) + cbData);
CIcmpHdr * pIcmpHdrReply = (CIcmpHdr *)(pIpHdrReply + 1);
pIcmpHdrReply->_bType = ICMPTYPE_ECHO_REPLY;
pIcmpHdrReply->_wChecksum = 0;
pIcmpHdrReply->_wChecksum = (WORD)~tcpipxsum(0, pIcmpHdrReply, cbData);
TraceSz(pktRecv, "[REPLY] Replying to ICMP echo request");
IpFillAndXmit(ppktReply, pIpHdr->_ipaSrc, IPPROTOCOL_ICMP);
return;
}
TraceSz3(pktWarn, "[DISCARD] No support ICMP <%d/%d> %s",
pIcmpHdr->_bType, pIcmpHdr->_bCode, pIcmpHdr->Str());
}
#endif