- Fix timeout values

- Don't reply to ARP requests unless they are address to us
 - We now reset the NCE timeout if we receive a packet from the neighbor
 - Fixes ARP flooding (bug 4879)

svn path=/trunk/; revision=43354
This commit is contained in:
Cameron Gutman 2009-10-10 07:43:39 +00:00
parent 6e2700c9e9
commit 05c582bcbd
5 changed files with 75 additions and 16 deletions

View file

@ -24,7 +24,7 @@ typedef struct ARP_HEADER {
#define ARP_OPCODE_REPLY WH2N(0x0002) /* ARP reply */
BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface);
BOOLEAN ARPTransmit(PIP_ADDRESS Address, PVOID LinkAddress, PIP_INTERFACE Interface);
VOID ARPReceive(
PVOID Context,

View file

@ -44,11 +44,14 @@ typedef struct NEIGHBOR_CACHE_ENTRY {
#define NUD_PERMANENT 0x02
#define NUD_STALE 0x04
/* Number of seconds before the NCE times out */
#define ARP_TIMEOUT 30
/* Number of seconds between ARP transmissions */
#define ARP_RATE 10
#define ARP_RATE 900
/* Number of seconds before the NCE times out */
#define ARP_TIMEOUT ARP_RATE + 15
/* Number of seconds before retransmission */
#define ARP_TIMEOUT_RETRANSMISSION 5
extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];
@ -98,6 +101,9 @@ ULONG NBCopyNeighbors(
PIP_INTERFACE Interface,
PIPARP_ENTRY ArpTable);
VOID NBResetNeighborTimeout(
PIP_ADDRESS Address);
#endif /* __NEIGHBOR_H */
/* EOF */

View file

@ -108,7 +108,8 @@ VOID ARPTransmitComplete(
}
BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface)
BOOLEAN ARPTransmit(PIP_ADDRESS Address, PVOID LinkAddress,
PIP_INTERFACE Interface)
/*
* FUNCTION: Creates an ARP request and transmits it on a network
* ARGUMENTS:
@ -152,7 +153,7 @@ BOOLEAN ARPTransmit(PIP_ADDRESS Address, PIP_INTERFACE Interface)
(UCHAR)ProtoAddrLen, /* Protocol address length */
Interface->Address, /* Sender's (local) hardware address */
&Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */
NULL, /* Don't care */
LinkAddress, /* Target's (remote) hardware address */
&Address->Address.IPv4Address, /* Target's (remote) protocol address */
ARP_OPCODE_REQUEST); /* ARP request */
@ -225,7 +226,8 @@ VOID ARPReceive(
Header->HWAddrLen, 0, ARP_TIMEOUT);
}
if (Header->Opcode != ARP_OPCODE_REQUEST)
if (Header->Opcode != ARP_OPCODE_REQUEST ||
!AddrIsEqual(&Address, &Interface->Unicast))
return;
/* This is a request for our address. Swap the addresses and

View file

@ -93,10 +93,12 @@ VOID IPDispatchProtocol(
*/
{
UINT Protocol;
IP_ADDRESS SrcAddress;
switch (IPPacket->Type) {
case IP_ADDRESS_V4:
Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr);
break;
case IP_ADDRESS_V6:
/* FIXME: IPv6 adresses not supported */
@ -107,6 +109,8 @@ VOID IPDispatchProtocol(
return;
}
NBResetNeighborTimeout(&SrcAddress);
if (Protocol < IP_PROTOCOL_TABLE_SIZE)
{
/* Call the appropriate protocol handler */
@ -219,7 +223,7 @@ VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
/* Send a gratuitous ARP packet to update the route caches of
* other computers */
if (IF != Loopback)
ARPTransmit(NULL, IF);
ARPTransmit(NULL, NULL, IF);
}
BOOLEAN IPRegisterInterface(

View file

@ -105,20 +105,35 @@ VOID NBTimeout(VOID)
TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
for (PrevNCE = &NeighborCache[i].Cache;
(NCE = *PrevNCE) != NULL;
PrevNCE = &NCE->Next) {
(NCE = *PrevNCE) != NULL;) {
/* Check if event timer is running */
if (NCE->EventTimer > 0) {
ASSERT(!(NCE->State & NUD_PERMANENT));
NCE->EventCount++;
if (NCE->EventCount % ARP_RATE == 0)
NBSendSolicit(NCE);
if (NCE->EventTimer - NCE->EventCount == 0) {
if ((NCE->EventCount > ARP_RATE &&
NCE->EventCount % ARP_TIMEOUT_RETRANSMISSION == 0) ||
(NCE->EventCount == ARP_RATE))
{
/* We haven't gotten a packet from them in
* EventCount seconds so we mark them as stale
* and solicit now */
NCE->State |= NUD_STALE;
NBSendSolicit(NCE);
}
if (NCE->EventTimer - NCE->EventCount == 0) {
/* Solicit one last time */
NBSendSolicit(NCE);
NCE->EventCount = 0;
/* Unlink and destroy the NCE */
*PrevNCE = NCE->Next;
NBFlushPacketQueue(NCE, NDIS_STATUS_REQUEST_ABORTED);
exFreePool(NCE);
continue;
}
}
PrevNCE = &NCE->Next;
}
TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
@ -188,7 +203,8 @@ VOID NBSendSolicit(PNEIGHBOR_CACHE_ENTRY NCE)
{
TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
ARPTransmit(&NCE->Address, NCE->Interface);
ARPTransmit(&NCE->Address, NCE->LinkAddress,
NCE->Interface);
}
PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(
@ -302,6 +318,37 @@ VOID NBUpdateNeighbor(
NBSendPackets( NCE );
}
VOID
NBResetNeighborTimeout(PIP_ADDRESS Address)
{
KIRQL OldIrql;
UINT HashValue;
PNEIGHBOR_CACHE_ENTRY NCE;
TI_DbgPrint(DEBUG_NCACHE, ("Resetting NCE timout for 0x%s\n", A2S(Address)));
HashValue = *(PULONG)(&Address->Address);
HashValue ^= HashValue >> 16;
HashValue ^= HashValue >> 8;
HashValue ^= HashValue >> 4;
HashValue &= NB_HASHMASK;
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
for (NCE = NeighborCache[HashValue].Cache;
NCE != NULL;
NCE = NCE->Next)
{
if (AddrIsEqual(Address, &NCE->Address))
{
NCE->EventCount = 0;
break;
}
}
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
}
PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(
PIP_ADDRESS Address)
/*