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.
1293 lines
43 KiB
1293 lines
43 KiB
/*
|
|
* File: nlbkd.c
|
|
* Description: This file contains the implementation of the NLB KD
|
|
* debugging extensions. Use '!load nlbkd.dll' to load
|
|
* the extensions and '!nlbkd.help' to see the supported
|
|
* extensions.
|
|
* Author: Created by shouse, 1.4.01
|
|
*/
|
|
|
|
#include "nlbkd.h"
|
|
#include "utils.h"
|
|
#include "print.h"
|
|
#include "packet.h"
|
|
#include "load.h"
|
|
|
|
WINDBG_EXTENSION_APIS ExtensionApis;
|
|
EXT_API_VERSION ApiVersion = { 1, 0, EXT_API_VERSION_NUMBER64, 0 };
|
|
|
|
#define NL 1
|
|
#define NONL 0
|
|
|
|
USHORT SavedMajorVersion;
|
|
USHORT SavedMinorVersion;
|
|
BOOL ChkTarget;
|
|
|
|
/*
|
|
* Function: WinDbgExtensionDllInit
|
|
* Description: Initializes the KD extension DLL.
|
|
* Author: Created by shouse, 1.4.01 - copied largely from ndiskd.dll
|
|
*/
|
|
VOID WinDbgExtensionDllInit (PWINDBG_EXTENSION_APIS64 lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion) {
|
|
|
|
ExtensionApis = *lpExtensionApis;
|
|
|
|
SavedMajorVersion = MajorVersion;
|
|
SavedMinorVersion = MinorVersion;
|
|
|
|
ChkTarget = (SavedMajorVersion == 0x0c) ? TRUE : FALSE;
|
|
}
|
|
|
|
/*
|
|
* Function: CheckVersion
|
|
* Description: Checks the extension DLL version against the target version.
|
|
* Author: Created by shouse, 1.4.01 - copied largely from ndiskd.dll
|
|
*/
|
|
VOID CheckVersion (VOID) {
|
|
|
|
/* For now, do nothing. */
|
|
return;
|
|
|
|
#if DBG
|
|
if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
|
|
dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
|
|
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
|
|
}
|
|
#else
|
|
if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
|
|
dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
|
|
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Function: ExtensionApiVersion
|
|
* Description: Returns the API version information.
|
|
* Author: Created by shouse, 1.4.01 - copied largely from ndiskd.dll
|
|
*/
|
|
LPEXT_API_VERSION ExtensionApiVersion (VOID) {
|
|
|
|
return &ApiVersion;
|
|
}
|
|
|
|
/*
|
|
* Function: help
|
|
* Description: Prints the usage of the NLB KD debugger extensions.
|
|
* Author: Created by shouse, 1.4.01
|
|
*/
|
|
DECLARE_API (help) {
|
|
dprintf("Network Load Balancing debugger extensions:\n");
|
|
|
|
dprintf(" version print nlbkd version\n");
|
|
dprintf(" nlbadapters [Verbosity] show all NLB adapter blocks\n");
|
|
dprintf(" nlbadapter <Adapter Block> [Verbosity] dump an NLB adapter block\n");
|
|
dprintf(" nlbctxt <Context Block> [Verbosity] dump an NLB context block\n");
|
|
dprintf(" nlbload <Load Block> [Verbosity] dump an NLB load block\n");
|
|
dprintf(" nlbparams <Params Block> [Verbosity] dump an NLB parameters block\n");
|
|
dprintf(" nlbresp <Packet> [Direction] dump the NLB private data for the specified packet\n");
|
|
dprintf(" nlbpkt <Packet> [RC Port] dump an NDIS packet whose content is determined\n");
|
|
dprintf(" on the fly (IP, UDP, TCP, heartbeat, IGMP, remote-control, etc)\n");
|
|
dprintf(" nlbether <Ether Frame> [RC Port] dump an ethernet frame. Uses same technique as nlbpkt\n");
|
|
dprintf(" nlbip <IP Packet> [RC Port] dump an IP packet. Uses same technique as nlbpkt\n");
|
|
dprintf(" nlbteams dump the linked list of NLB BDA teams\n");
|
|
dprintf(" nlbhooks dump the global NLB hook information\n");
|
|
dprintf(" nlbmac <Context Block> dump the MAC address lists (unicast and multicast) for the physical\n");
|
|
dprintf(" adapter to which this NLB instance is bound\n");
|
|
dprintf(" nlbdscr <Descriptor> dump the contents of a connection descriptor\n");
|
|
dprintf(" nlbconnq <Queue>[Index] [MaxEntries] dump the contents of a connection descriptor queue\n");
|
|
dprintf(" nlbglobalq <Queue>[Index] [MaxEntries] dump the contents of a global connection descriptor queue\n");
|
|
dprintf(" nlbfilter <pointer to context block> <protocol> <client IP>[:<client port>] <server IP>[:<server port>] [flags]\n");
|
|
dprintf(" query map function and retrieve any existing state for this tuple\n");
|
|
dprintf(" nlbhash <Context Block> <Packet> determine whether or not NLB will accept this packet\n");
|
|
dprintf("\n");
|
|
dprintf(" [Verbosity] is an optional integer from 0 to 2 that determines the level of detail displayed.\n");
|
|
dprintf(" [Direction] is an optional integer that specifies the direction of the packet (RCV=0, SND=1).\n");
|
|
dprintf(" [RC Port] is an optional UDP port used to identify whether a UDP packet might be for remote-control.\n");
|
|
dprintf(" [Flags] is an optional TCP-like packet type specification; SYN, FIN or RST.\n");
|
|
dprintf(" [MaxEntries] is an optional maximum number of entries to print (default is 10)\n");
|
|
dprintf(" [Index] is an optional queue index which can be used if the queue pointer points to an array of queues.\n");
|
|
dprintf(" The index should be specified in Addr[index], Addr{index} or Addr(index) form.\n");
|
|
dprintf("\n");
|
|
dprintf(" IP addresses can be in dotted notation or network byte order DWORDs.\n");
|
|
dprintf(" I.e., 169.128.0.101 = 0x650080a9 (in x86 memory = A9 80 00 65)\n");
|
|
dprintf(" Valid protocols include TCP, UDP, IPSec and GRE.\n");
|
|
}
|
|
|
|
/*
|
|
* Function: version
|
|
* Description: Prints the NLB KD debugger extension version information.
|
|
* Author: Created by shouse, 1.4.01 - copied largely from ndiskd.dll
|
|
*/
|
|
DECLARE_API (version) {
|
|
#if DBG
|
|
PCSTR kind = "Checked";
|
|
#else
|
|
PCSTR kind = "Free";
|
|
#endif
|
|
|
|
dprintf("%s NLB Extension DLL for Build %d debugging %s kernel for Build %d\n", kind,
|
|
VER_PRODUCTBUILD, SavedMajorVersion == 0x0c ? "Checked" : "Free", SavedMinorVersion);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbadapters
|
|
* Description: Prints all NLB adapter strucutres in use. Verbosity is always LOW.
|
|
* Author: Created by shouse, 1.5.01
|
|
*/
|
|
DECLARE_API (nlbadapters) {
|
|
ULONG dwVerbosity = VERBOSITY_LOW;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pNumAdapters;
|
|
DWORD dwAdapterSize;
|
|
ULONG dwNumAdapters;
|
|
ULONG64 pAdapter;
|
|
ULONG dwIndex;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
if (args && (*args)) {
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a verbosity was specified, get it. */
|
|
if (index == 1) dwVerbosity = atoi(&szArgList[0][0]);
|
|
|
|
/* If too many arguments were given, or the verbosity was out of range, complain. */
|
|
if ((index > 1) || (dwVerbosity > VERBOSITY_HIGH)) {
|
|
PrintUsage(USAGE_ADAPTERS);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Get the address of the global variable containing the number of NLB adapters in use. */
|
|
pNumAdapters = GetExpression(UNIV_ADAPTERS_COUNT);
|
|
|
|
if (!pNumAdapters) {
|
|
ErrorCheckSymbols(UNIV_ADAPTERS_COUNT);
|
|
return;
|
|
}
|
|
|
|
/* Get the number of adapters from the address. */
|
|
dwNumAdapters = GetUlongFromAddress(pNumAdapters);
|
|
|
|
dprintf("Network Load Balancing is currently bound to %u adapter(s).\n", dwNumAdapters);
|
|
|
|
/* Get the base address of the global array of NLB adapter structures. */
|
|
pAdapter = GetExpression(UNIV_ADAPTERS);
|
|
|
|
if (!pAdapter) {
|
|
ErrorCheckSymbols(UNIV_ADAPTERS);
|
|
return;
|
|
}
|
|
|
|
/* Find out the size of a MAIN_ADAPTER structure. */
|
|
dwAdapterSize = GetTypeSize(MAIN_ADAPTER);
|
|
|
|
/* Loop through all adapters in use and print some information about them. */
|
|
for (dwIndex = 0; dwIndex < CVY_MAX_ADAPTERS; dwIndex++) {
|
|
ULONG dwValue;
|
|
|
|
/* Retrieve the used/unused state of the adapter. */
|
|
GetFieldValue(pAdapter, MAIN_ADAPTER, MAIN_ADAPTER_FIELD_USED, dwValue);
|
|
|
|
/* If the adapter is in use, or the user specified HIGH verbosity, print the adapter. */
|
|
if (dwValue || (dwVerbosity == VERBOSITY_HIGH)) {
|
|
/* Print the adapter index. */
|
|
dprintf("\n[%u] ", dwIndex);
|
|
|
|
/* Print the adapter contents. If verbosity is high, change it to
|
|
medium - we don't want to recurse into context from here. */
|
|
PrintAdapter(pAdapter, (dwVerbosity == VERBOSITY_HIGH) ? VERBOSITY_MEDIUM : dwVerbosity);
|
|
}
|
|
|
|
/* Advance the pointer to the next index in the array of structures. */
|
|
pAdapter += dwAdapterSize;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: nlbadapter
|
|
* Description: Prints NLB adapter information. Takes an adapter pointer and an
|
|
* optional verbosity as arguments. Default verbosity is MEDIUM.
|
|
* Author: Created by shouse, 1.5.01
|
|
*/
|
|
DECLARE_API (nlbadapter) {
|
|
ULONG dwVerbosity = VERBOSITY_LOW;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pAdapter;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the adapter pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_ADAPTER);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NLB adapter block from the command line. */
|
|
pAdapter = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a verbosity was specified, get it. */
|
|
if (index == 2) dwVerbosity = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, or the verbosity was out of range, complain. */
|
|
if ((index > 2) || (dwVerbosity > VERBOSITY_HIGH)) {
|
|
PrintUsage(USAGE_ADAPTER);
|
|
return;
|
|
}
|
|
|
|
/* Print the adapter contents. */
|
|
PrintAdapter(pAdapter, dwVerbosity);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbctxt
|
|
* Description: Prints NLB context information. Takes a context pointer and an
|
|
* optional verbosity as arguments. Default verbosity is LOW.
|
|
* Author: Created by shouse, 1.21.01
|
|
*/
|
|
DECLARE_API (nlbctxt) {
|
|
ULONG dwVerbosity = VERBOSITY_LOW;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pContext;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the context pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_CONTEXT);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NLB context block from the command line. */
|
|
pContext = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a verbosity was specified, get it. */
|
|
if (index == 2) dwVerbosity = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, or the verbosity was out of range, complain. */
|
|
if ((index > 2) || (dwVerbosity > VERBOSITY_HIGH)) {
|
|
PrintUsage(USAGE_CONTEXT);
|
|
return;
|
|
}
|
|
|
|
/* Print the context contents. */
|
|
PrintContext(pContext, dwVerbosity);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbload
|
|
* Description: Prints NLB load information. Takes a load pointer and an optional
|
|
* verbosity as arguments. Default verbosity is LOW.
|
|
* Author: Created by shouse, 2.1.01
|
|
*/
|
|
DECLARE_API (nlbload) {
|
|
ULONG dwVerbosity = VERBOSITY_LOW;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pLoad;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the load pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_LOAD);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NLB load block from the command line. */
|
|
pLoad = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a verbosity was specified, get it. */
|
|
if (index == 2) dwVerbosity = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, or the verbosity was out of range, complain. */
|
|
if ((index > 2) || (dwVerbosity > VERBOSITY_HIGH)) {
|
|
PrintUsage(USAGE_LOAD);
|
|
return;
|
|
}
|
|
|
|
/* Print the load contents. */
|
|
PrintLoad(pLoad, dwVerbosity);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbparams
|
|
* Description: Prints NLB parameter information. Takes a parameter pointer and an
|
|
* optional verbosity as arguments. Default verbosity is LOW.
|
|
* Author: Created by shouse, 1.21.01
|
|
*/
|
|
DECLARE_API (nlbparams) {
|
|
ULONG dwVerbosity = VERBOSITY_LOW;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pParams;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the params pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_PARAMS);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NLB params block from the command line. */
|
|
pParams = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a verbosity was specified, get it. */
|
|
if (index == 2) dwVerbosity = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, or the verbosity was out of range, complain. */
|
|
if ((index > 2) || (dwVerbosity > VERBOSITY_HIGH)) {
|
|
PrintUsage(USAGE_PARAMS);
|
|
return;
|
|
}
|
|
|
|
/* Print the parameter contents. */
|
|
PrintParams(pParams, dwVerbosity);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbresp
|
|
* Description: Prints out the NLB private packet data for a given packet. Takes a
|
|
* packet pointer and an optional direction as arguments. If not specified,
|
|
* the packet is presumed to be on the receive path.
|
|
* Author: Created by shouse, 1.31.01
|
|
*/
|
|
DECLARE_API (nlbresp) {
|
|
ULONG dwDirection = DIRECTION_RECEIVE;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pPacket;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the packet pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_RESP);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NDIS packet from the command line. */
|
|
pPacket = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If a direction was specified, get it. */
|
|
if (index == 2) dwDirection = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, or the direction was out of range, complain. */
|
|
if ((index > 2) || (dwDirection > DIRECTION_SEND)) {
|
|
PrintUsage(USAGE_RESP);
|
|
return;
|
|
}
|
|
|
|
/* Print the NLB private data buffer contents. */
|
|
PrintResp(pPacket, dwDirection);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbpkt
|
|
* Description: Prints out the contents of an NDIS packet. Takes a packet
|
|
* pointer as an argument.
|
|
* Author: Created by chrisdar 2001.10.11
|
|
*/
|
|
DECLARE_API (nlbpkt) {
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pPkt;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
NETWORK_DATA nd;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_PKT);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the queue from the command line. */
|
|
pPkt = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If the wrong number of arguments were given, complain. */
|
|
if (index > 2 || index < 1) {
|
|
PrintUsage(USAGE_PKT);
|
|
return;
|
|
}
|
|
|
|
/* Clear out the network data structure. */
|
|
ZeroMemory(&nd, sizeof(nd));
|
|
|
|
nd.UserRCPort = CVY_DEF_RCT_PORT;
|
|
|
|
if (index > 1)
|
|
{
|
|
nd.UserRCPort = atoi(&szArgList[1][0]);
|
|
}
|
|
|
|
if (nd.UserRCPort > CVY_MAX_PORT)
|
|
{
|
|
dprintf("Invalid port: %s\n", nd.UserRCPort);
|
|
return;
|
|
}
|
|
|
|
/* Parse through the NDIS packet and retrieve the packet contents. */
|
|
{
|
|
UCHAR RawData[CVY_MAX_FRAME_SIZE + ETHER_HEADER_SIZE];
|
|
ULONG BytesRead = 0;
|
|
ULONG64 pHBData;
|
|
|
|
/* Parse the buffers in the NDIS packet and get the raw packet data out. We get
|
|
a pointer to the heartbeat data in machine memory, not debugger process memory
|
|
because for all other packets, we read from temporary stack space in the debugger
|
|
- RawData - but for heartbeats, we read directly from kernel memory space (only
|
|
because a function to do so already exits - no need to write another). */
|
|
BytesRead = ParseNDISPacket(pPkt, RawData, CVY_MAX_FRAME_SIZE + ETHER_HEADER_SIZE, &pHBData);
|
|
|
|
/* If some packet contents was successfully read, continue to process the packet. */
|
|
if (BytesRead != 0) {
|
|
/* Parse the Ethernet packet and store the information parsed in the NETWORK_DATA
|
|
structure. Note that this function recurses to also fill in IP, TCP/UDP,
|
|
heartbeat, remote control, etc. information as well. */
|
|
PopulateEthernet(pHBData, RawData, BytesRead, &nd);
|
|
|
|
/* Print the packet, including IP and TCP data (if present), or heartbeat
|
|
or remote control information, etc. */
|
|
dprintf("NDIS Packet 0x%p\n", pPkt);
|
|
PrintPacket(&nd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: nlbether
|
|
* Description: Prints out the contents of an ethernet packet. Takes a packet
|
|
* pointer as an argument.
|
|
* Author: Created by chrisdar 2001.10.11
|
|
*/
|
|
DECLARE_API (nlbether){
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pPkt;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
ULONG BytesRead;
|
|
UCHAR RawData[CVY_MAX_FRAME_SIZE];
|
|
BOOL b;
|
|
NETWORK_DATA nd;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_ETHER);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the queue from the command line. */
|
|
pPkt = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If the wrong number of arguments were given, complain. */
|
|
if (index > 2 || index < 1) {
|
|
PrintUsage(USAGE_ETHER);
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(&nd, sizeof(nd));
|
|
nd.UserRCPort = CVY_DEF_RCT_PORT;
|
|
|
|
if (index > 1)
|
|
{
|
|
nd.UserRCPort = atoi(&szArgList[1][0]);
|
|
}
|
|
|
|
if (nd.UserRCPort > CVY_MAX_PORT)
|
|
{
|
|
dprintf("Invalid port: %s\n", nd.UserRCPort);
|
|
return;
|
|
}
|
|
|
|
b = ReadMemory(pPkt, RawData, CVY_MAX_FRAME_SIZE, &BytesRead);
|
|
|
|
if (!b || BytesRead != CVY_MAX_FRAME_SIZE)
|
|
{
|
|
dprintf("Unable to read %u bytes at address %p\n", CVY_MAX_FRAME_SIZE, pPkt);
|
|
}
|
|
else
|
|
{
|
|
PopulateEthernet(pPkt + ETHER_HEADER_SIZE + GetTypeSize(MAIN_FRAME_HDR),
|
|
RawData,
|
|
CVY_MAX_FRAME_SIZE,
|
|
&nd
|
|
);
|
|
|
|
/* Print the NLB private data buffer contents. */
|
|
dprintf("Ethernet Packet 0x%p\n", pPkt);
|
|
PrintPacket(&nd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: nlbip
|
|
* Description: Prints out the contents of an ip packet. Takes a packet
|
|
* pointer as an argument.
|
|
* Author: Created by chrisdar 2001.10.11
|
|
*/
|
|
DECLARE_API (nlbip){
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
INT index = 0;
|
|
CHAR * p;
|
|
ULONG64 pPkt;
|
|
ULONG BytesRead;
|
|
UCHAR RawData[CVY_MAX_FRAME_SIZE];
|
|
BOOL b;
|
|
NETWORK_DATA nd;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_IP);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the queue from the command line. */
|
|
pPkt = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If the wrong number of arguments were given, complain. */
|
|
if (index > 2 || index < 1) {
|
|
PrintUsage(USAGE_IP);
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(&nd, sizeof(nd));
|
|
nd.UserRCPort = CVY_DEF_RCT_PORT;
|
|
|
|
if (index > 1)
|
|
{
|
|
nd.UserRCPort = atoi(&szArgList[1][0]);
|
|
}
|
|
|
|
if (nd.UserRCPort > CVY_MAX_PORT)
|
|
{
|
|
dprintf("Invalid port: %s\n", nd.UserRCPort);
|
|
return;
|
|
}
|
|
|
|
b = ReadMemory(pPkt, RawData, CVY_MAX_FRAME_SIZE, &BytesRead);
|
|
|
|
if (!b || BytesRead != CVY_MAX_FRAME_SIZE)
|
|
{
|
|
dprintf("Unable to read %u bytes at address %p\n", CVY_MAX_FRAME_SIZE, pPkt);
|
|
}
|
|
else
|
|
{
|
|
PopulateIP(RawData, CVY_MAX_FRAME_SIZE, 0, &nd);
|
|
|
|
/* Print the NLB private data buffer contents. */
|
|
dprintf("IP Packet 0x%p\n", pPkt);
|
|
PrintIP(&nd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: nlbteams
|
|
* Description: Prints all configured Bi-directional Affintiy (BDA) teams.
|
|
* Author: Created by shouse, 1.5.01
|
|
*/
|
|
DECLARE_API (nlbteams) {
|
|
ULONG64 pTeam;
|
|
ULONG64 pAddr;
|
|
ULONG dwNumTeams = 0;
|
|
ULONG dwValue;
|
|
|
|
/* No command line arguments should be given. */
|
|
if (args && (*args)) {
|
|
PrintUsage(USAGE_TEAMS);
|
|
return;
|
|
}
|
|
|
|
/* Get the base address of the global linked list of BDA teams. */
|
|
pAddr = GetExpression(UNIV_BDA_TEAMS);
|
|
|
|
if (!pAddr) {
|
|
ErrorCheckSymbols(UNIV_BDA_TEAMS);
|
|
return;
|
|
}
|
|
|
|
/* Get the pointer to the first team. */
|
|
pTeam = GetPointerFromAddress(pAddr);
|
|
|
|
dprintf("NLB bi-directional affinity teams:\n");
|
|
|
|
/* Loop through all teams in the list and print them out. */
|
|
while (pTeam) {
|
|
/* Increment the number of teams found - only used if none are found. */
|
|
dwNumTeams++;
|
|
|
|
dprintf("\n");
|
|
|
|
/* Print out the team. */
|
|
PrintBDATeam(pTeam);
|
|
|
|
/* Get the offset of the params pointer. */
|
|
if (GetFieldOffset(BDA_TEAM, BDA_TEAM_FIELD_NEXT, &dwValue))
|
|
dprintf("Can't get offset of %s in %s\n", BDA_TEAM_FIELD_NEXT, BDA_TEAM);
|
|
else {
|
|
pAddr = pTeam + dwValue;
|
|
|
|
/* Retrieve the pointer. */
|
|
pTeam = GetPointerFromAddress(pAddr);
|
|
}
|
|
}
|
|
|
|
if (!dwNumTeams) dprintf("\nNone.\n");
|
|
}
|
|
|
|
/*
|
|
* Function: nlbhooks
|
|
* Description: Prints the global NLB hook function information.
|
|
* Author: Created by shouse, 12.20.01
|
|
*/
|
|
DECLARE_API (nlbhooks) {
|
|
ULONG64 pAddr;
|
|
|
|
/* No command line arguments should be given. */
|
|
if (args && (*args)) {
|
|
PrintUsage(USAGE_HOOKS);
|
|
return;
|
|
}
|
|
|
|
/* Get the base address of the global linked list of BDA teams. */
|
|
pAddr = GetExpression(UNIV_HOOKS);
|
|
|
|
if (!pAddr) {
|
|
ErrorCheckSymbols(UNIV_HOOKS);
|
|
return;
|
|
}
|
|
|
|
dprintf("NLB kernel-mode hooks:\n");
|
|
|
|
/* Print the global NLB hook configuration and state. */
|
|
PrintHooks(pAddr);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbmac
|
|
* Description: Prints the unicast MAC address and all multicast MAC addresses
|
|
* configured on the adapter to which this instance of NLB is bound.
|
|
* Author: Created by shouse, 1.8.02
|
|
*/
|
|
DECLARE_API (nlbmac) {
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pContext;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the context pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_MAC);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the NLB context block from the command line. */
|
|
pContext = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If too many arguments were given, complain. */
|
|
if (index > 1) {
|
|
PrintUsage(USAGE_MAC);
|
|
return;
|
|
}
|
|
|
|
/* Print the context contents. */
|
|
PrintNetworkAddresses(pContext);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbdscr
|
|
* Description: Prints the contents of an NLB connection descriptor.
|
|
* Author: Created by shouse, 1.8.02
|
|
*/
|
|
DECLARE_API (nlbdscr) {
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pDescriptor;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the descriptor pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_DSCR);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the connection descriptor from the command line. */
|
|
pDescriptor = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If too many arguments were given, complain. */
|
|
if (index > 1) {
|
|
PrintUsage(USAGE_DSCR);
|
|
return;
|
|
}
|
|
|
|
/* Print the context contents. */
|
|
PrintConnectionDescriptor(pDescriptor);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbconnq
|
|
* Description: This function prints out all connection descriptors in a given
|
|
* queue of descriptors.
|
|
* Author: Created by shouse, 4.15.01
|
|
*/
|
|
DECLARE_API (nlbconnq) {
|
|
ULONG dwMaxEntries = 10;
|
|
ULONG dwIndex = 0;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pQueue;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_CONNQ);
|
|
return;
|
|
}
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* Tokenize the queue address looking for an index. This will return
|
|
a pointer to the address whether an index exists or not. */
|
|
p = mystrtok(szArgList[0], "[({");
|
|
|
|
/* Get the address of the queue. */
|
|
pQueue = (ULONG64)GetExpression(p);
|
|
|
|
/* Look for the end of the address index. If no index existed, this will return
|
|
NULL. If an index was given, this returns a string containing the index. */
|
|
p = mystrtok(NULL, "])}");
|
|
|
|
if (p) dwIndex = atoi(p);
|
|
|
|
/* If a maximum number of entries to print was specified, get it. */
|
|
if (index == 2) dwMaxEntries = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, complain. */
|
|
if (index > 2) {
|
|
PrintUsage(USAGE_CONNQ);
|
|
return;
|
|
}
|
|
|
|
/* Print the NLB connection queue. */
|
|
PrintQueue(pQueue, dwIndex, dwMaxEntries);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbglobalq
|
|
* Description: This function prints out all connection descriptors in a given
|
|
* global (GLOBAL_CONN_QUEUE) queue of descriptors.
|
|
* Author: Created by shouse, 4.15.01
|
|
*/
|
|
DECLARE_API (nlbglobalq) {
|
|
ULONG dwMaxEntries = 10;
|
|
ULONG dwIndex = 0;
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pQueue;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_CONNQ);
|
|
return;
|
|
}
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* Tokenize the queue address looking for an index. This will return
|
|
a pointer to the address whether an index exists or not. */
|
|
p = mystrtok(szArgList[0], "[({");
|
|
|
|
/* Get the address of the queue. */
|
|
pQueue = (ULONG64)GetExpression(p);
|
|
|
|
/* Look for the end of the address index. If no index existed, this will return
|
|
NULL. If an index was given, this returns a string containing the index. */
|
|
p = mystrtok(NULL, "])}");
|
|
|
|
if (p) dwIndex = atoi(p);
|
|
|
|
/* If a maximum number of entries to print was specified, get it. */
|
|
if (index == 2) dwMaxEntries = atoi(&szArgList[1][0]);
|
|
|
|
/* If too many arguments were given, complain. */
|
|
if (index > 2) {
|
|
PrintUsage(USAGE_GLOBALQ);
|
|
return;
|
|
}
|
|
|
|
/* Print the NLB global connection queue. */
|
|
PrintGlobalQueue(pQueue, dwIndex, dwMaxEntries);
|
|
}
|
|
|
|
/*
|
|
* Function: nlbhash
|
|
* Description:
|
|
* Author: Created by shouse, 4.15.01
|
|
*/
|
|
DECLARE_API (nlbhash) {
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
ULONG64 pContext;
|
|
ULONG64 pPkt;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
ULONG dwValue;
|
|
ULONG64 pParams;
|
|
|
|
/* Make sure at least one argument, the queue pointer, is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_HASH);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the queue from the command line. */
|
|
pContext = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If the wrong number of arguments were given, complain. */
|
|
if (index != 2) {
|
|
PrintUsage(USAGE_HASH);
|
|
return;
|
|
}
|
|
|
|
/* Get the pointer to the NDIS packet from the second argument. */
|
|
pPkt = (ULONG64)GetExpression(&szArgList[1][0]);
|
|
|
|
/* Get the MAIN_CTXT_CODE from the structure to make sure that this address
|
|
indeed points to a valid NLB context block. */
|
|
GetFieldValue(pContext, MAIN_CTXT, MAIN_CTXT_FIELD_CODE, dwValue);
|
|
|
|
if (dwValue != MAIN_CTXT_CODE) {
|
|
dprintf(" Error: Invalid NLB context block. Wrong code found (0x%08x).\n", dwValue);
|
|
return;
|
|
}
|
|
|
|
/* Parse through the NDIS packet and retrieve the packet contents. */
|
|
{
|
|
UCHAR RawData[CVY_MAX_FRAME_SIZE + ETHER_HEADER_SIZE];
|
|
ULONG BytesRead = 0;
|
|
ULONG64 pHBData;
|
|
|
|
/* Parse the buffers in the NDIS packet and get the raw packet data out. We get
|
|
a pointer to the heartbeat data in machine memory, not debugger process memory
|
|
because for all other packets, we read from temporary stack space in the debugger
|
|
- RawData - but for heartbeats, we read directly from kernel memory space (only
|
|
because a function to do so already exits - no need to write another). */
|
|
BytesRead = ParseNDISPacket(pPkt, RawData, CVY_MAX_FRAME_SIZE + ETHER_HEADER_SIZE, &pHBData);
|
|
|
|
/* If some packet contents was successfully read, continue to process the packet. */
|
|
if (BytesRead != 0) {
|
|
NETWORK_DATA nd;
|
|
|
|
/* Clear out the network data structure. */
|
|
ZeroMemory(&nd, sizeof(nd));
|
|
|
|
/* Get the pointer to the NLB parameters. */
|
|
GetFieldOffset(MAIN_CTXT, MAIN_CTXT_FIELD_PARAMS, &dwValue);
|
|
|
|
pParams = pContext + dwValue;
|
|
|
|
/* Get the remote control port. */
|
|
GetFieldValue(pParams, CVY_PARAMS, CVY_PARAMS_FIELD_REMOTE_CONTROL_PORT, dwValue);
|
|
|
|
/* Set the remote control port in the network data block. */
|
|
nd.UserRCPort = dwValue;
|
|
|
|
/* Parse the Ethernet packet and store the information parsed in the NETWORK_DATA
|
|
structure. Note that this function recurses to also fill in IP, TCP/UDP,
|
|
heartbeat, remote control, etc. information as well. */
|
|
PopulateEthernet(pHBData, RawData, BytesRead, &nd);
|
|
|
|
/* Print the packet, including IP and TCP data (if present), or heartbeat
|
|
or remote control information, etc. */
|
|
dprintf("NDIS Packet 0x%p\n", pPkt);
|
|
PrintPacket(&nd);
|
|
|
|
/* Now call into the filtering extension to determine the fate of this packet. */
|
|
dprintf("\n");
|
|
PrintHash(pContext, &nd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: nlbfilter
|
|
* Description: This function will perform the NLB hashing algorithm to determine
|
|
* whether a given packet - identified by a (Src IP, Src port, Dst IP,
|
|
* Dst port) tuple would be handled by this host or another host.
|
|
* Further, if the connection is a known TCP connection, the associated
|
|
* descriptor and state information are displayed.
|
|
* Author: Created by shouse, 1.11.02
|
|
*/
|
|
DECLARE_API (nlbfilter) {
|
|
CHAR szArgList[10][MAX_PATH];
|
|
CHAR szArgBuffer[MAX_PATH];
|
|
UCHAR cFlags = NLB_FILTER_FLAGS_CONN_DATA;
|
|
ULONG64 pLoad;
|
|
ULONG dwClientIPAddress;
|
|
ULONG dwClientPort;
|
|
ULONG dwServerIPAddress;
|
|
ULONG dwServerPort;
|
|
USHORT wProtocol;
|
|
INT index = 0;
|
|
CHAR * p;
|
|
|
|
/* Make sure that the load pointer is there. */
|
|
if (!args || !(*args)) {
|
|
PrintUsage(USAGE_FILTER);
|
|
return;
|
|
}
|
|
|
|
/* Get the address of the load module from the command line. */
|
|
pLoad = (ULONG64)GetExpression(args);
|
|
|
|
/* Copy the argument list into a temporary buffer. */
|
|
strcpy(szArgBuffer, args);
|
|
|
|
/* Peel out all of the tokenized strings. */
|
|
for (p = mystrtok(szArgBuffer, " \t,"); p && *p; p = mystrtok(NULL, " \t,"))
|
|
strcpy(&szArgList[index++][0], p);
|
|
|
|
/* If too many arguments were given, complain. */
|
|
if ((index > 5) || (index < 4)) {
|
|
PrintUsage(USAGE_FILTER);
|
|
return;
|
|
}
|
|
|
|
/* Find the protocol specification. */
|
|
if (!_stricmp(szArgList[1], "TCP")) {
|
|
wProtocol = TCPIP_PROTOCOL_TCP;
|
|
} else if (!_stricmp(szArgList[1], "UDP")) {
|
|
wProtocol = TCPIP_PROTOCOL_UDP;
|
|
} else if (!_stricmp(szArgList[1], "IPSec")) {
|
|
wProtocol = TCPIP_PROTOCOL_IPSEC1;
|
|
} else if (!_stricmp(szArgList[1], "PPTP")) {
|
|
wProtocol = TCPIP_PROTOCOL_PPTP;
|
|
} else if (!_stricmp(szArgList[1], "GRE")) {
|
|
wProtocol = TCPIP_PROTOCOL_GRE;
|
|
} else if (!_stricmp(szArgList[1], "ICMP")) {
|
|
wProtocol = TCPIP_PROTOCOL_ICMP;
|
|
} else {
|
|
dprintf("Invalid protocol: %s\n", szArgList[1]);
|
|
return;
|
|
}
|
|
|
|
/* The client port defaults to unspecified. */
|
|
dwClientPort = 0;
|
|
|
|
/* If we find a colon in the client specification, then we expect that
|
|
its an IP:port specification. */
|
|
p = strchr(szArgList[2], ':');
|
|
|
|
/* If we found the port string, separate the IP from the string with
|
|
a NUL character and extract the port value. */
|
|
if (p != NULL) {
|
|
*p = UNICODE_NULL;
|
|
p++;
|
|
|
|
dwClientPort = atoi(p);
|
|
|
|
/* Make sure the port is between 1 and 65535. */
|
|
if ((dwClientPort == 0) || (dwClientPort > CVY_MAX_PORT)) {
|
|
dprintf("Invalid port: %s\n", dwClientPort);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* If we find a '.' in the IP address, then we need to convert it using inet_addr.
|
|
If there is no '.', then we assume its already a DWORD in network byte order. */
|
|
if (strchr(szArgList[2], '.'))
|
|
dwClientIPAddress = inet_addr(szArgList[2]);
|
|
else
|
|
dwClientIPAddress = (ULONG)GetExpression(&szArgList[2][0]);
|
|
|
|
/* The server port defaults to unspecified. */
|
|
dwServerPort = 0;
|
|
|
|
/* If we find a colon in the server specification, then we expect that
|
|
its an IP:port specification. */
|
|
p = strchr(szArgList[3], ':');
|
|
|
|
/* If we found the port string, separate the IP from the string with
|
|
a NUL character and extract the port value. */
|
|
if (p != NULL) {
|
|
*p = UNICODE_NULL;
|
|
p++;
|
|
|
|
dwServerPort = atoi(p);
|
|
|
|
/* Make sure the port is between 1 and 65535. */
|
|
if ((dwServerPort == 0) || (dwServerPort > CVY_MAX_PORT)) {
|
|
dprintf("Invalid port: %s\n", dwServerPort);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* If we find a '.' in the IP address, then we need to convert it using inet_addr.
|
|
If there is no '.', then we assume its already a DWORD in network byte order. */
|
|
if (strchr(szArgList[3], '.'))
|
|
dwServerIPAddress = inet_addr(szArgList[3]);
|
|
else
|
|
dwServerIPAddress = (ULONG)GetExpression(&szArgList[3][0]);
|
|
|
|
cFlags = NLB_FILTER_FLAGS_CONN_DATA;
|
|
|
|
/* If an seventh argument has been specified, it is TCP packet type, which should be SYN, DATA, FIN or RST. */
|
|
if (index >= 5) {
|
|
if (!_stricmp(szArgList[4], "SYN")) {
|
|
cFlags |= NLB_FILTER_FLAGS_CONN_UP;
|
|
} else if (!_stricmp(szArgList[4], "FIN")) {
|
|
cFlags |= NLB_FILTER_FLAGS_CONN_DOWN;
|
|
} else if (!_stricmp(szArgList[4], "RST")) {
|
|
cFlags |= NLB_FILTER_FLAGS_CONN_RESET;
|
|
} else {
|
|
dprintf("Invalid connection flags: %s\n", szArgList[4]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (wProtocol) {
|
|
case TCPIP_PROTOCOL_TCP:
|
|
|
|
if (dwServerPort == 0) {
|
|
dprintf("A server port is required\n");
|
|
return;
|
|
}
|
|
|
|
if (dwClientPort == 0)
|
|
{
|
|
if ((cFlags == NLB_FILTER_FLAGS_CONN_DOWN) ||
|
|
(cFlags == NLB_FILTER_FLAGS_CONN_RESET))
|
|
{
|
|
dprintf("RST/FIN filtering requires a client port\n");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
cFlags = NLB_FILTER_FLAGS_CONN_UP;
|
|
}
|
|
}
|
|
|
|
if (dwServerPort != PPTP_CTRL_PORT)
|
|
{
|
|
break;
|
|
}
|
|
|
|
wProtocol = TCPIP_PROTOCOL_PPTP;
|
|
|
|
/* This fall-through is INTENTIONAL. In this case, we're verified the TCP
|
|
parameters, but discovered that because the server port was 1723, this
|
|
is actually PPTP, so force it through the PPTP verification as well. */
|
|
case TCPIP_PROTOCOL_PPTP:
|
|
|
|
dwServerPort = PPTP_CTRL_PORT;
|
|
|
|
if (dwClientPort == 0)
|
|
{
|
|
if ((cFlags == NLB_FILTER_FLAGS_CONN_DOWN) ||
|
|
(cFlags == NLB_FILTER_FLAGS_CONN_RESET))
|
|
{
|
|
dprintf("RST/FIN filtering requires a client port\n");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
cFlags = NLB_FILTER_FLAGS_CONN_UP;
|
|
}
|
|
}
|
|
|
|
break;
|
|
case TCPIP_PROTOCOL_UDP:
|
|
|
|
if (dwServerPort == 0)
|
|
{
|
|
dprintf("A server port is required\n");
|
|
return;
|
|
}
|
|
|
|
if ((dwServerPort != IPSEC_CTRL_PORT) && (dwServerPort != IPSEC_NAT_PORT))
|
|
{
|
|
if (cFlags != NLB_FILTER_FLAGS_CONN_DATA)
|
|
{
|
|
dprintf("Connection flags are not valid for UDP packets\n");
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
wProtocol = TCPIP_PROTOCOL_IPSEC1;
|
|
|
|
/* This fall-through is INTENTIONAL. In this case, we're verified the TCP
|
|
parameters, but discovered that because the server port was 1723, this
|
|
is actually PPTP, so force it through the PPTP verification as well. */
|
|
case TCPIP_PROTOCOL_IPSEC1:
|
|
|
|
if (dwServerPort == 0)
|
|
{
|
|
dwServerPort = IPSEC_CTRL_PORT;
|
|
}
|
|
|
|
if (dwServerPort == IPSEC_CTRL_PORT)
|
|
{
|
|
if (dwClientPort == 0)
|
|
{
|
|
dwClientPort = IPSEC_CTRL_PORT;
|
|
}
|
|
|
|
if (dwClientPort != IPSEC_CTRL_PORT)
|
|
{
|
|
dprintf("IPSec packets destined for server port 500 must originate from client port 500\n");
|
|
return;
|
|
}
|
|
}
|
|
else if (dwServerPort == IPSEC_NAT_PORT)
|
|
{
|
|
if (dwClientPort == 0)
|
|
{
|
|
dprintf("A client port is required\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf("IPSec packets are always destined for either port 500 or 4500\n");
|
|
return;
|
|
}
|
|
|
|
break;
|
|
case TCPIP_PROTOCOL_GRE:
|
|
|
|
if (cFlags != NLB_FILTER_FLAGS_CONN_DATA)
|
|
{
|
|
dprintf("Connection flags are not valid for GRE packets\n");
|
|
return;
|
|
}
|
|
|
|
dwServerPort = PPTP_CTRL_PORT;
|
|
dwClientPort = PPTP_CTRL_PORT;
|
|
|
|
break;
|
|
case TCPIP_PROTOCOL_ICMP:
|
|
|
|
if (cFlags != NLB_FILTER_FLAGS_CONN_DATA)
|
|
{
|
|
dprintf("Connection flags are not valid for ICMP packets\n");
|
|
return;
|
|
}
|
|
|
|
dwServerPort = 0;
|
|
dwClientPort = 0;
|
|
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* Hash on this tuple and print the results. */
|
|
PrintFilter(pLoad, dwClientIPAddress, dwClientPort, dwServerIPAddress, dwServerPort, wProtocol, cFlags);
|
|
}
|
|
|