You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
844 lines
35 KiB
844 lines
35 KiB
/*
|
|
* File: nlbkd.c
|
|
* Description: This file contains the implementation of the utility functions
|
|
* to populate the NLB KD network packet structures used to print
|
|
* out the contents of a given network packet.
|
|
*
|
|
* Author: Created by shouse, 12.20.01
|
|
*/
|
|
|
|
#include "nlbkd.h"
|
|
#include "utils.h"
|
|
#include "print.h"
|
|
#include "packet.h"
|
|
#include "load.h"
|
|
|
|
/*
|
|
* Function: PopulateRemoteControl
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartUDP - location in data array where the UDP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateRemoteControl(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartRC, PNETWORK_DATA pnd)
|
|
{
|
|
ULONG ulValue = 0;
|
|
PCHAR pszStruct = NULL;
|
|
PCHAR pszMember = NULL;
|
|
|
|
if (ulBufLen < ulStartRC + NLB_REMOTE_CONTROL_MIN_NEEDED_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("Remote control packet is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the relative positions of quantities in IOCTL_REMOTE_HDR
|
|
//
|
|
pszStruct = IOCTL_REMOTE_HDR;
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_CODE;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCCode), &(RawData[ulValue]), sizeof(pnd->RCCode));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_VERSION;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCVersion), &(RawData[ulValue]), sizeof(pnd->RCVersion));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_HOST;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCHost), &(RawData[ulValue]), sizeof(pnd->RCHost));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_CLUSTER;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCCluster), &(RawData[ulValue]), sizeof(pnd->RCCluster));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_ADDR;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCAddr), &(RawData[ulValue]), sizeof(pnd->RCAddr));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_ID;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCId), &(RawData[ulValue]), sizeof(pnd->RCId));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = IOCTL_REMOTE_HDR_IOCTRL;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStartRC;
|
|
CopyMemory(&(pnd->RCIoctrl), &(RawData[ulValue]), sizeof(pnd->RCIoctrl));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateICMP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartICMP - location in data array where the ICMP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateICMP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartICMP, PNETWORK_DATA pnd)
|
|
{
|
|
//
|
|
// Just a stub for now. There is nothing in the payload that we are currently interested in.
|
|
//
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateIGMP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartIGMP - location in data array where the IGMP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateIGMP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartIGMP, PNETWORK_DATA pnd)
|
|
{
|
|
if (ulBufLen < ulStartIGMP + IGMP_HEADER_AND_PAYLOAD_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("IGMP packet is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
pnd->IGMPVersion = (RawData[ulStartIGMP + IGMP_OFFSET_VERSION_AND_TYPE] & 0xF0) >> 4; // Shift down 4 bits since we want the value in the upper byte.
|
|
pnd->IGMPType = RawData[ulStartIGMP + IGMP_OFFSET_VERSION_AND_TYPE] & 0x0F;
|
|
|
|
CopyMemory(&(pnd->IGMPGroupIPAddr), &(RawData[ulStartIGMP + IGMP_OFFSET_GROUP_IP_ADDR]), sizeof(pnd->IGMPGroupIPAddr));
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateTCP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartTCP - location in data array where the TCP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateTCP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartTCP, PNETWORK_DATA pnd)
|
|
{
|
|
if (ulBufLen < ulStartTCP + TCP_MIN_HEADER_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("TCP header is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
pnd->SourcePort = (RawData[ulStartTCP + TCP_OFFSET_SOURCE_PORT_START] << 8) +
|
|
RawData[ulStartTCP + TCP_OFFSET_SOURCE_PORT_START + 1];
|
|
|
|
pnd->DestPort = (RawData[ulStartTCP + TCP_OFFSET_DEST_PORT_START] << 8) +
|
|
RawData[ulStartTCP + TCP_OFFSET_DEST_PORT_START + 1];
|
|
|
|
pnd->TCPSeqNum = (RawData[ulStartTCP + TCP_OFFSET_SEQUENCE_NUM_START] << 24) +
|
|
(RawData[ulStartTCP + TCP_OFFSET_SEQUENCE_NUM_START + 1] << 16) +
|
|
(RawData[ulStartTCP + TCP_OFFSET_SEQUENCE_NUM_START + 2] << 8) +
|
|
RawData[ulStartTCP + TCP_OFFSET_SEQUENCE_NUM_START + 3];
|
|
|
|
pnd->TCPAckNum = (RawData[ulStartTCP + TCP_OFFSET_ACK_NUM_START] << 24) +
|
|
(RawData[ulStartTCP + TCP_OFFSET_ACK_NUM_START + 1] << 16) +
|
|
(RawData[ulStartTCP + TCP_OFFSET_ACK_NUM_START + 2] << 8) +
|
|
RawData[ulStartTCP + TCP_OFFSET_ACK_NUM_START + 3];
|
|
|
|
pnd->TCPFlags = RawData[ulStartTCP + TCP_OFFSET_FLAGS] & 0x3F; // Masked with 3F because only the first 6 bits in the word correspond to the TCP flags
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateUDP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartUDP - location in data array where the UDP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateUDP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartUDP, PNETWORK_DATA pnd)
|
|
{
|
|
ULONG ulRCCode;
|
|
BOOL bIsRCSource;
|
|
BOOL bIsRCDest;
|
|
|
|
if (ulBufLen < ulStartUDP + UDP_HEADER_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("UDP header is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
pnd->SourcePort = (RawData[ulStartUDP + UDP_OFFSET_SOURCE_PORT_START] << 8) +
|
|
RawData[ulStartUDP + UDP_OFFSET_SOURCE_PORT_START + 1];
|
|
pnd->DestPort = (RawData[ulStartUDP + UDP_OFFSET_DEST_PORT_START] << 8) +
|
|
RawData[ulStartUDP + UDP_OFFSET_DEST_PORT_START + 1];
|
|
|
|
//
|
|
// Is this a remote control packet?
|
|
//
|
|
pnd->RemoteControl = NLB_RC_PACKET_NO;
|
|
bIsRCSource = (CVY_DEF_RCT_PORT_OLD == pnd->SourcePort) || (pnd->UserRCPort == pnd->SourcePort);
|
|
bIsRCDest = (CVY_DEF_RCT_PORT_OLD == pnd->DestPort) || (pnd->UserRCPort == pnd->DestPort);
|
|
if (bIsRCSource || bIsRCDest)
|
|
{
|
|
// if (CVY_DEF_RCT_PORT_OLD == pnd->SourcePort || CVY_DEF_RCT_PORT_OLD == pnd->DestPort ||
|
|
// pnd->UserRCPort == pnd->SourcePort || pnd->UserRCPort == pnd->DestPort)
|
|
// {
|
|
//
|
|
// Read first 4 bytes of UDP payload, which is where the remote control
|
|
// code will be if this is a remote control packet
|
|
//
|
|
CopyMemory(&ulRCCode, &(RawData[ulStartUDP + UDP_OFFSET_PAYLOAD_START]), sizeof(ulRCCode));
|
|
|
|
if (IOCTL_REMOTE_CODE == ulRCCode)
|
|
{
|
|
//
|
|
// Yes, it is remote control.
|
|
//
|
|
// pnd->IsRemoteControl = TRUE;
|
|
|
|
//
|
|
// Is it a request or a reply?
|
|
//
|
|
if (bIsRCSource && bIsRCDest)
|
|
{
|
|
// Ambiguous
|
|
pnd->RemoteControl = NLB_RC_PACKET_AMBIGUOUS;
|
|
}
|
|
else if (bIsRCSource)
|
|
{
|
|
// Request
|
|
pnd->RemoteControl = NLB_RC_PACKET_REPLY;
|
|
}
|
|
else if (bIsRCDest)
|
|
{
|
|
// Reply
|
|
pnd->RemoteControl = NLB_RC_PACKET_REQUEST;
|
|
}
|
|
|
|
PopulateRemoteControl(RawData, ulBufLen, ulStartUDP + UDP_HEADER_SIZE, pnd);
|
|
}
|
|
} else if (pnd->DestPort == IPSEC_CTRL_PORT) {
|
|
/* Look for IPSec SYN equivalents - Initial Contact Main Mode Security Associations. */
|
|
PopulateIPSecControl(RawData, ulBufLen, ulStartUDP + UDP_HEADER_SIZE, pnd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateGRE
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartGRE - location in data array where the GRE header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateGRE(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartGRE, PNETWORK_DATA pnd)
|
|
{
|
|
//
|
|
// Just a stub for now. There is nothing in the payload that we are currently interested in.
|
|
//
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateIPSec
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartIPSec - location in data array where the IPSec header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateIPSec(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartIPSec, PNETWORK_DATA pnd)
|
|
{
|
|
//
|
|
// Just a stub for now. There is nothing in the payload that we are currently interested in.
|
|
//
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateIPSecControl
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartIPSec - location in data array where the IPSec header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by shouse, 1.13.02
|
|
*/
|
|
VOID PopulateIPSecControl(PUCHAR RawData, ULONG ulBufLen, ULONG ulStartIPSec, PNETWORK_DATA pnd)
|
|
{
|
|
/* Pointer to the IKE header. */
|
|
PIPSEC_ISAKMP_HDR pISAKMPHeader = (PIPSEC_ISAKMP_HDR)&RawData[ulStartIPSec];
|
|
/* Pointer to the subsequent generic payloads in the IKE packet. */
|
|
PIPSEC_GENERIC_HDR pGenericHeader;
|
|
|
|
/* The initiator cookie - should be non-zero if this is really an IKE packet. */
|
|
UCHAR EncapsulatedIPSecICookie[IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH] = IPSEC_ISAKMP_ENCAPSULATED_IPSEC_ICOOKIE;
|
|
/* The Microsoft client vendor ID - used to determine whether or not the client supports initial contact notification. */
|
|
UCHAR VIDMicrosoftClient[IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH] = IPSEC_VENDOR_ID_MICROSOFT;
|
|
|
|
/* Whether or not we've determined the client to be compatible. */
|
|
BOOLEAN bInitialContactEnabled = FALSE;
|
|
/* Whether or not this is indeed an initial contact. */
|
|
BOOLEAN bInitialContact = FALSE;
|
|
|
|
/* The length of the IKE packet. */
|
|
ULONG cISAKMPPacketLength;
|
|
/* The next payload code in the IKE payload chain. */
|
|
UCHAR NextPayload;
|
|
/* The number of bytes from the beginning of the IKE header to the end of the available buffer. */
|
|
ULONG cUDPDataLength;
|
|
/* A re-usable length parameter. */
|
|
ULONG cLength;
|
|
|
|
/* Assume its not an initial contact for now. */
|
|
pnd->IPSecInitialContact = FALSE;
|
|
|
|
/* The number of bytes left is the length of the buffer, minus the beginning of the IKE header. */
|
|
cUDPDataLength = ulBufLen - ulStartIPSec;
|
|
|
|
/* The UDP data should be at least as long as the initiator cookie. If the packet is
|
|
UDP encapsulated IPSec, then the I cookie will be 0 to indicate such. */
|
|
if (cUDPDataLength < IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH)
|
|
return;
|
|
|
|
/* Calculate the size of the ICookie. */
|
|
cLength = sizeof(UCHAR) * IPSEC_ISAKMP_HEADER_ICOOKIE_LENGTH;
|
|
|
|
/* Need to check the init cookie, which will distinguish clients behind a NAT,
|
|
which also send their IPSec (ESP) traffic to UDP port 500. If the I cookie
|
|
is zero, then this is NOT an IKE packet. */
|
|
if (cLength == RtlCompareMemory((PVOID)IPSEC_ISAKMP_GET_ICOOKIE_POINTER(pISAKMPHeader), (PVOID)&EncapsulatedIPSecICookie[0], cLength))
|
|
return;
|
|
|
|
/* At this point, this packet should be IKE, so the UDP data should be at least
|
|
as long as an ISAKMP header. */
|
|
if (cUDPDataLength < IPSEC_ISAKMP_HEADER_LENGTH)
|
|
return;
|
|
|
|
/* Get the total length of the IKE packet from the ISAKMP header. */
|
|
cISAKMPPacketLength = IPSEC_ISAKMP_GET_PACKET_LENGTH(pISAKMPHeader);
|
|
|
|
/* The IKE packet should be at least as long as an ISAKMP header (a whole lot longer, actually). */
|
|
if (cISAKMPPacketLength < IPSEC_ISAKMP_HEADER_LENGTH)
|
|
return;
|
|
|
|
/* Sanity check - the UDP data length and IKE packet length SHOULD be the same, unless the packet
|
|
is fragmented. If it is, then we can only look into the packet as far as the UDP data length.
|
|
If that's not far enough for us to find what we need, then we might miss an initial contact
|
|
main mode SA; the consequence of which is that we might not accept this connection if we are
|
|
in non-optimized mode, because we'll treat this like data, which requires a descriptor lookup -
|
|
if this is an initial contact, chances are great that no descriptor will exist and all hosts
|
|
in the cluster will drop the packet. */
|
|
if (cUDPDataLength < cISAKMPPacketLength)
|
|
/* Only look as far as the end of the UDP packet. */
|
|
cISAKMPPacketLength = cUDPDataLength;
|
|
|
|
/* Get the first payload type out of the ISAKMP header. */
|
|
NextPayload = IPSEC_ISAKMP_GET_NEXT_PAYLOAD(pISAKMPHeader);
|
|
|
|
/* IKE security associations are identified by a payload type byte in the header.
|
|
Check that first - this does not ensure that this is what we are looking for
|
|
because this check will not exclude, for instance, main mode re-keys. */
|
|
if (NextPayload != IPSEC_ISAKMP_SA)
|
|
return;
|
|
|
|
/* Calculate a pointer to the fist generic payload, which is directly after the ISAKMP header. */
|
|
pGenericHeader = (PIPSEC_GENERIC_HDR)((PUCHAR)pISAKMPHeader + IPSEC_ISAKMP_HEADER_LENGTH);
|
|
|
|
/* We are looping through the generic payloads looking for the vendor ID and/or notify information. */
|
|
while ((PUCHAR)pGenericHeader <= ((PUCHAR)pISAKMPHeader + cISAKMPPacketLength - IPSEC_GENERIC_HEADER_LENGTH)) {
|
|
/* Extract the payload length from the generic header. */
|
|
USHORT cPayloadLength = IPSEC_GENERIC_GET_PAYLOAD_LENGTH(pGenericHeader);
|
|
|
|
/* Not all clients are going to support this (in fact, only the Microsoft client
|
|
will support it, so we need to first see what the vendor ID of the client is.
|
|
if it is a Microsoft client that supports the initial contact vendor ID, then
|
|
we'll look for the initial contact, which provides better stickiness for IPSec
|
|
connections. If either the client is non-MS, or if it is not a version that
|
|
supports initial contact, then we can revert to the "second-best" solution,
|
|
which is to provide stickiness _between_ Main Mode SAs. This means that if a
|
|
client re-keys their Main Mode session, they _may_ be rebalanced to another
|
|
server. This is still better than the old UDP implementation, but the only
|
|
way to provide full session support for IPSec (without the distributed session
|
|
table nightmare) is to be able to distinguish initial Main Mode SAs from sub-
|
|
sequent Main Mode SAs (re-keys). */
|
|
if (NextPayload == IPSEC_ISAKMP_VENDOR_ID) {
|
|
PIPSEC_VENDOR_HDR pVendorHeader = (PIPSEC_VENDOR_HDR)pGenericHeader;
|
|
|
|
/* Make sure that the vendor ID payload is at least as long as a vendor ID. */
|
|
if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH))
|
|
return;
|
|
|
|
/* Calculate the size of the Vendor ID. */
|
|
cLength = sizeof(UCHAR) * IPSEC_VENDOR_HEADER_VENDOR_ID_LENGTH;
|
|
|
|
/* Look for the Microsoft client vendor ID. If it is the right version, then we know that
|
|
the client is going to appropriately set the initial contact information, allowing NLB
|
|
to provide the best possible support for session stickiness. */
|
|
if (cLength == RtlCompareMemory((PVOID)IPSEC_VENDOR_ID_GET_ID_POINTER(pVendorHeader), (PVOID)&VIDMicrosoftClient[0], cLength)) {
|
|
/* Make sure that their is a version number attached to the Microsoft Vendor ID. Not
|
|
all vendor IDs have versions attached, but the Microsoft vendor ID should. */
|
|
if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_VENDOR_ID_PAYLOAD_LENGTH))
|
|
return;
|
|
|
|
if (IPSEC_VENDOR_ID_GET_VERSION(pVendorHeader) >= IPSEC_VENDOR_ID_MICROSOFT_MIN_VERSION) {
|
|
/* Microsoft clients whose version is greater than or equal to 4 will support
|
|
initial contact. Non-MS clients, or old MS clients will not, so they
|
|
receive decent, but not guaranteed sitckines, based solely on MM SAs. */
|
|
bInitialContactEnabled = TRUE;
|
|
}
|
|
}
|
|
} else if (NextPayload == IPSEC_ISAKMP_NOTIFY) {
|
|
PIPSEC_NOTIFY_HDR pNotifyHeader = (PIPSEC_NOTIFY_HDR)pGenericHeader;
|
|
|
|
/* Make sure that the notify payload is the correct length. */
|
|
if (cPayloadLength < (IPSEC_GENERIC_HEADER_LENGTH + IPSEC_NOTIFY_PAYLOAD_LENGTH))
|
|
return;
|
|
|
|
if (IPSEC_NOTIFY_GET_NOTIFY_MESSAGE(pNotifyHeader) == IPSEC_NOTIFY_INITIAL_CONTACT) {
|
|
/* This is an initial contact notification from the client, which means that this is
|
|
the first time that the client has contacted this server; more precisely, the client
|
|
currently has no state associated with this peer. NLB will "re-balance" on initial
|
|
contact notifications, but not other Main Mode key exchanges as long as it can
|
|
determine that the client will comply with initial contact notification. */
|
|
bInitialContact = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Get the next payload type out of the generic header. */
|
|
NextPayload = IPSEC_GENERIC_GET_NEXT_PAYLOAD(pGenericHeader);
|
|
|
|
/* Calculate a pointer to the next generic payload. */
|
|
pGenericHeader = (PIPSEC_GENERIC_HDR)((PUCHAR)pGenericHeader + cPayloadLength);
|
|
}
|
|
|
|
/* If the vendor ID did not indicate that this client supports initial contact notification,
|
|
then mark this as an IC MMSA, and we go with the less-than-optimal solution of treating Main
|
|
Mode SAs as the connection boundaries, which potentially breaks sessions on MM SA re-keys. */
|
|
if (!bInitialContactEnabled) {
|
|
pnd->IPSecInitialContact = TRUE;
|
|
return;
|
|
}
|
|
|
|
/* If this was a Main Mode SA from a client that supports initial contact, but did not
|
|
specify the initial contact vendor ID, then this is a re-key for an existing session. */
|
|
if (!bInitialContact)
|
|
return;
|
|
|
|
/* We have found an Initial Contact Main Mode Security Association. */
|
|
pnd->IPSecInitialContact = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateIP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartIP - location in data array where the IP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateIP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStart, PNETWORK_DATA pnd)
|
|
{
|
|
if (ulBufLen < ulStart + IP_MIN_HEADER_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("IP header is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
pnd->HeadLen = (RawData[ulStart + IP_OFFSET_HEADER_LEN] & 0xF)*4; // *4 because the header stores the number of 32-bit words
|
|
|
|
pnd->TotLen = (RawData[ulStart + IP_OFFSET_TOTAL_LEN] << 8) +
|
|
RawData[ulStart + IP_OFFSET_TOTAL_LEN + 1];
|
|
// CopyMemory(&(pnd->TotLen), &(RawData[ulStart + IP_OFFSET_TOTAL_LEN]), sizeof(pnd->TotLen));
|
|
|
|
pnd->Protocol = RawData[ulStart + IP_OFFSET_PROTOCOL];
|
|
|
|
CopyMemory(&(pnd->SourceIPAddr), &(RawData[ulStart + IP_OFFSET_SOURCE_IP]), sizeof(pnd->SourceIPAddr));
|
|
|
|
CopyMemory(&(pnd->DestIPAddr), &(RawData[ulStart + IP_OFFSET_DEST_IP]), sizeof(pnd->DestIPAddr));
|
|
|
|
switch((int) pnd->Protocol)
|
|
{
|
|
case TCPIP_PROTOCOL_ICMP:
|
|
PopulateICMP(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
case TCPIP_PROTOCOL_IGMP:
|
|
PopulateIGMP(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
case TCPIP_PROTOCOL_TCP:
|
|
PopulateTCP(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
case TCPIP_PROTOCOL_UDP:
|
|
PopulateUDP(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
case TCPIP_PROTOCOL_GRE:
|
|
PopulateGRE(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
case TCPIP_PROTOCOL_IPSEC1:
|
|
case TCPIP_PROTOCOL_IPSEC2:
|
|
PopulateIPSec(RawData, ulBufLen, ulStart + pnd->HeadLen, pnd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateARP
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStartARP - location in data array where the ARP header begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateARP(PUCHAR RawData, ULONG ulBufLen, ULONG ulStart, PNETWORK_DATA pnd)
|
|
{
|
|
if (ulBufLen < ulStart + ARP_HEADER_AND_PAYLOAD_SIZE)
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("ARP packet is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
CopyMemory(&(pnd->ARPSenderMAC), &(RawData[ulStart + ARP_OFFSET_SENDER_MAC]) , sizeof(pnd->ARPSenderMAC));
|
|
CopyMemory(&(pnd->ARPSenderIP) , &(RawData[ulStart + ARP_OFFSET_SENDER_IP]), sizeof(pnd->ARPSenderIP));
|
|
CopyMemory(&(pnd->ARPTargetMAC), &(RawData[ulStart + ARP_OFFSET_TARGET_MAC]), sizeof(pnd->ARPTargetMAC));
|
|
CopyMemory(&(pnd->ARPTargetIP) , &(RawData[ulStart + ARP_OFFSET_TARGET_IP]), sizeof(pnd->ARPTargetIP));
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateNLBHeartbeat
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: ULONG64 pPkt - pointer to the original data structure in memory of the host being debugged.
|
|
* PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStart - location in data array where the heartbeat data begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateNLBHeartbeat(ULONG64 pPkt, PUCHAR RawData, ULONG ulBufLen, ULONG ulStart, PNETWORK_DATA pnd)
|
|
{
|
|
ULONG ulValue = 0;
|
|
PCHAR pszStruct = NULL;
|
|
PCHAR pszMember = NULL;
|
|
|
|
//
|
|
// Use this to print out heartbeat details by calling PrintHeartbeat written by SHouse.
|
|
//
|
|
pnd->HBPtr = pPkt;
|
|
|
|
if (ulBufLen < ulStart + sizeof(MAIN_FRAME_HDR))
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("NLB heartbeat header is not the minimum required length.\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the relative positions of quantities in MAIN_FRAME_HDR
|
|
//
|
|
pszStruct = MAIN_FRAME_HDR;
|
|
|
|
pszMember = MAIN_FRAME_HDR_FIELD_CODE;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStart;
|
|
CopyMemory(&(pnd->HBCode), &(RawData[ulValue]), sizeof(pnd->HBCode));
|
|
}
|
|
else
|
|
{
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
if (pnd->HBCode != MAIN_FRAME_CODE) {
|
|
/* Mark the packet invalid. */
|
|
pnd->bValid = FALSE;
|
|
|
|
dprintf("NLB heartbeat magic numbers do not match.\n");
|
|
}
|
|
|
|
pszMember = MAIN_FRAME_HDR_FIELD_VERSION;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStart;
|
|
CopyMemory(&(pnd->HBVersion), &(RawData[ulValue]), sizeof(pnd->HBVersion));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = MAIN_FRAME_HDR_FIELD_HOST;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStart;
|
|
CopyMemory(&(pnd->HBHost), &(RawData[ulValue]), sizeof(pnd->HBHost));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = MAIN_FRAME_HDR_FIELD_CLIP;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStart;
|
|
CopyMemory(&(pnd->HBCluster), &(RawData[ulValue]), sizeof(pnd->HBCluster));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
|
|
pszMember = MAIN_FRAME_HDR_FIELD_DIP;
|
|
if (!GetFieldOffset(pszStruct, pszMember, &ulValue))
|
|
{
|
|
ulValue += ulStart;
|
|
CopyMemory(&(pnd->HBDip), &(RawData[ulValue]), sizeof(pnd->HBDip));
|
|
}
|
|
else
|
|
{
|
|
dprintf("Error reading field offset of %s in structure %s\n", pszMember, pszStruct);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateConvoyHeartbeat
|
|
* Description: Stores properties of a remote control packet for subsequent printing.
|
|
* Args: ULONG64 pPkt - pointer to the original data structure in memory of the host being debugged.
|
|
* PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* ULONG ulStart - location in data array where the heartbeat data begins
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateConvoyHeartbeat(ULONG64 pPkt, PUCHAR RawData, ULONG ulBufLen, ULONG ulStart, PNETWORK_DATA pnd)
|
|
{
|
|
//
|
|
// Just a stub for now. We won't deal with Convoy hosts.
|
|
//
|
|
}
|
|
|
|
/*
|
|
* Function: PopulateEthernet
|
|
* Description: Determines what type of data is in ethernet frame and calls function
|
|
* store properties for printing as appropriate.
|
|
* Args: ULONG64 pPkt - pointer to the original data structure in memory of the host being debugged.
|
|
* PUCHAR RawData - pointer to a byte array that we will read from
|
|
* ULONG ulBufLen - size of the data array in bytes
|
|
* PNETWORK_DATA pnd - data structure where extracted properties are stored
|
|
* Author: Created by chrisdar 2001.11.02
|
|
*/
|
|
VOID PopulateEthernet(ULONG64 pPkt, PUCHAR RawData, ULONG ulBufLen, PNETWORK_DATA pnd)
|
|
{
|
|
/* Initially assume what we parse will be valid. */
|
|
pnd->bValid = TRUE;
|
|
|
|
CopyMemory(&(pnd->DestMACAddr) , &(RawData[ETHER_OFFSET_DEST_MAC]), sizeof(pnd->DestMACAddr));
|
|
CopyMemory(&(pnd->SourceMACAddr), &(RawData[ETHER_OFFSET_SOURCE_MAC]), sizeof(pnd->SourceMACAddr));
|
|
|
|
pnd->EtherFrameType = (RawData[ETHER_OFFSET_FRAME_TYPE_START] << 8) +
|
|
RawData[ETHER_OFFSET_FRAME_TYPE_START + 1];
|
|
|
|
//
|
|
// Determine payload type and fill accordingly
|
|
//
|
|
switch(pnd->EtherFrameType)
|
|
{
|
|
case TCPIP_IP_SIG:
|
|
PopulateIP(RawData, ulBufLen, ETHER_HEADER_SIZE, pnd);
|
|
break;
|
|
case TCPIP_ARP_SIG:
|
|
PopulateARP(RawData, ulBufLen, ETHER_HEADER_SIZE, pnd);
|
|
break;
|
|
case MAIN_FRAME_SIG:
|
|
PopulateNLBHeartbeat(pPkt, RawData, ulBufLen, ETHER_HEADER_SIZE, pnd);
|
|
break;
|
|
case MAIN_FRAME_SIG_OLD:
|
|
PopulateConvoyHeartbeat(pPkt, RawData, ulBufLen, ETHER_HEADER_SIZE, pnd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: ParseNDISPacket
|
|
* Description: This function walks the list of NDIS buffers in a packet and
|
|
* copies the packet data into a buffer supplied by the caller.
|
|
* Author: Created by chrisdar, 1.13.02
|
|
*/
|
|
ULONG ParseNDISPacket (ULONG64 pPkt, PUCHAR pRawData, ULONG BufferSize, PULONG64 ppHBData) {
|
|
ULONG64 BufAddr;
|
|
ULONG64 TailAddr;
|
|
ULONG64 MappedSystemVAAddr;
|
|
USHORT usBufCount = 0;
|
|
ULONG BufferByteCount;
|
|
ULONG BytesRemaining;
|
|
ULONG TotalBytesRead = 0;
|
|
ULONG BytesRead;
|
|
BOOL bSuccess = FALSE;
|
|
BOOL b;
|
|
|
|
BytesRemaining = BufferSize;
|
|
*ppHBData = 0;
|
|
|
|
GetFieldValue(pPkt, NDIS_PACKET, "Private.Head", BufAddr);
|
|
GetFieldValue(pPkt, NDIS_PACKET, "Private.Tail", TailAddr);
|
|
|
|
while (BufAddr != 0)
|
|
{
|
|
usBufCount++;
|
|
|
|
if (CheckControlC())
|
|
{
|
|
return TotalBytesRead;
|
|
}
|
|
|
|
//
|
|
// Note we could test BytesRemaining in the while clause instead of here. But we need the
|
|
// number of chained buffers for the packet when we call PopulateEthernet later, so we
|
|
// branch around the extract code as required.
|
|
//
|
|
if (BytesRemaining > 0)
|
|
{
|
|
GetFieldValue(BufAddr, NDIS_BUFFER, "MappedSystemVa", MappedSystemVAAddr);
|
|
GetFieldValue(BufAddr, NDIS_BUFFER, "ByteCount", BufferByteCount);
|
|
|
|
if (BufferByteCount > BytesRemaining)
|
|
{
|
|
dprintf("\nNeed %u bytes of temp buffer space to read in buffer %u, but have room for only %u. Read what we can then process the data.\n",
|
|
BufferByteCount,
|
|
usBufCount,
|
|
BytesRemaining
|
|
);
|
|
BufferByteCount = BytesRemaining;
|
|
}
|
|
|
|
b = ReadMemory(MappedSystemVAAddr, &pRawData[BufferSize - BytesRemaining], BufferByteCount, &BytesRead);
|
|
|
|
if (!b || BytesRead != BufferByteCount)
|
|
{
|
|
//
|
|
// No sense in continuing since we need a continuous subset of the data to make sense of
|
|
// the contents.
|
|
//
|
|
dprintf("\nUnable to read %u bytes at address %p. Aborting...\n", BufferByteCount, MappedSystemVAAddr);
|
|
return TotalBytesRead;
|
|
}
|
|
else
|
|
{
|
|
bSuccess = TRUE;
|
|
TotalBytesRead += BytesRead;
|
|
BytesRemaining -= BytesRead;
|
|
}
|
|
}
|
|
|
|
if (BufAddr == TailAddr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
GetFieldValue(BufAddr, NDIS_BUFFER, "Next", BufAddr);
|
|
}
|
|
|
|
dprintf("\nNumber of NDIS buffers associated with packet = %d\n\n", usBufCount);
|
|
|
|
if (bSuccess)
|
|
{
|
|
//
|
|
// The first argument to the PopulateEthernet function is a pointer to the
|
|
// heartbeat data (whether or not the packet is a heartbeat will be sorted
|
|
// out by PopulateEthernet and PrintPacket, and the pointer is ignored if the
|
|
// packet isn't a heartbeat). The pointer is used by SHouse's PrintHeartbeat.
|
|
//
|
|
// We assert that the last buffer in the chain will always contain the heartbeat.
|
|
// In other words, a heartbeat isn't followed by another buffer, and a heartbeat
|
|
// is never fragmented across multiple buffers. With this assertion, the last
|
|
// value of MappedSystemVAAddr points to the heartbeat's buffer.
|
|
//
|
|
// When the number of chained buffers is 1, the buffer is a simple ethernet frame
|
|
// and we can calculate the beginning of the heartbeat.
|
|
//
|
|
// When the chain has more than one buffer, the address of the last buffer is the
|
|
// beginning of the heartbeat, so we can use this location (MappedSystemVAAddr)
|
|
// unmodified.
|
|
//
|
|
*ppHBData = MappedSystemVAAddr;
|
|
|
|
if (usBufCount == 1)
|
|
{
|
|
*ppHBData = MappedSystemVAAddr + ETHER_HEADER_SIZE + GetTypeSize(MAIN_FRAME_HDR);
|
|
}
|
|
}
|
|
|
|
return TotalBytesRead;
|
|
}
|