Source code of Windows XP (NT5)
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.

3231 lines
96 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\ip\fltrdrvr\driver.c
  5. Abstract:
  6. Revision History:
  7. --*/
  8. #include "globals.h"
  9. #include <align.h>
  10. #include <ipinfo.h>
  11. #ifdef DRIVER_PERF
  12. #define RecordTimeIn() { \
  13. InterlockedIncrement(&g_dwNumPackets); \
  14. KeQuerySystemTime(&liTimeIn); \
  15. }
  16. #define RecordTimeOut(){ \
  17. KeQuerySystemTime(&liTimeOut); \
  18. ExInterlockedAddLargeInteger(&g_liTotalTime, \
  19. liTimeOut.QuadPart - liTimeIn.QuadPart), \
  20. &g_slPerfLock); \
  21. }
  22. #define IncrementFragments() InterlockedIncrement(&g_dwFragments)
  23. #define IncrementCache1() InterlockedIncrement(&g_dwCache1)
  24. #define IncrementCache2() InterlockedIncrement(&g_dwCache2)
  25. #define IncrementWalk1() InterlockedIncrement(&g_dwWalk1)
  26. #define IncrementWalk2() InterlockedIncrement(&g_dwWalk2)
  27. #define IncrementForward() InterlockedIncrement(&g_dwForw)
  28. #define IncrementWalkCache() InterlockedIncrement(&g_dwWalkCache)
  29. #else
  30. #define RecordTimeIn()
  31. #define RecordTimeOut()
  32. #define IncrementFragments()
  33. #define IncrementCache1()
  34. #define IncrementCache2()
  35. #define IncrementWalk1()
  36. #define IncrementWalk2()
  37. #define IncrementForward()
  38. #define IncrementWalkCache()
  39. #endif // DRIVER_PERF
  40. #define PROT_IPSECESP 50
  41. #define PROT_IPSECAH 51
  42. //
  43. // The IPSEC AH payload
  44. //
  45. typedef struct _AH {
  46. UCHAR ah_next;
  47. UCHAR ah_len;
  48. USHORT ah_reserved;
  49. ULONG ah_spi;
  50. ULONG ah_replay;
  51. } AH, *PAH;
  52. #define SIZE_OF_IPSECAH sizeof(AH)
  53. #if LOOKUPROUTE
  54. void
  55. LookupRoute (IPRouteLookupData *pRLData, IPRouteEntry *pIPRTE);
  56. #endif
  57. #if DOFRAGCHECKING
  58. DWORD
  59. GetFragIndex(DWORD dwProt);
  60. #endif
  61. VOID __fastcall
  62. FragCacheUpdate(
  63. ULARGE_INTEGER uliSrcDstAddr,
  64. PVOID pInContext,
  65. PVOID pOutContext,
  66. DWORD dwId,
  67. FORWARD_ACTION faAction
  68. );
  69. BOOL
  70. CheckAddress(IPAddr ipAddr, DWORD dwInterfaceId);
  71. VOID
  72. SendTCPReset(UNALIGNED IPHeader * pIpHeader,
  73. BYTE * pbRestOfPacket,
  74. ULONG uiPacketLength);
  75. VOID
  76. SendUDPUnreachable(UNALIGNED IPHeader * pIpHeader,
  77. BYTE * pbRestOfPacket,
  78. ULONG uiPacketLength);
  79. BOOL
  80. CheckRedirectAddress(UNALIGNED IPHeader *IPHead, DWORD dwInterface);
  81. VOID
  82. LogFiltHit(
  83. FORWARD_ACTION Action,
  84. BOOL fIn,
  85. DWORD dwFilterRule,
  86. PFILTER_INTERFACE pIf,
  87. UNALIGNED IPHeader *pIpHeader,
  88. BYTE *pbRestOfPacket,
  89. UINT uiPacketLength);
  90. VOID
  91. FiltHit(PFILTER pf,
  92. PFILTER_INTERFACE pIf,
  93. FORWARD_ACTION Action,
  94. UNALIGNED IPHeader *pIpHeader,
  95. BYTE *pbRestOfPacket,
  96. UINT uiPacketLength,
  97. BOOL fIn);
  98. VOID
  99. RegisterFragAttack(
  100. PFILTER_INTERFACE pIf,
  101. UNALIGNED IPHeader *pIpHeader,
  102. BYTE *pbRestOfPacket,
  103. UINT uiSize);
  104. VOID
  105. RegisterFullDeny(
  106. PFILTER_INTERFACE pIf,
  107. UNALIGNED IPHeader *pIpHeader,
  108. BYTE *pbRestOfPacket,
  109. UINT uiSize);
  110. VOID
  111. RegisterUnusedICMP(PFILTER_INTERFACE pIf,
  112. UNALIGNED IPHeader *pIpHeader,
  113. BYTE *pbRestOfPacket,
  114. UINT uiSize);
  115. VOID
  116. RegisterSpoof( PFILTER_INTERFACE pIf,
  117. UNALIGNED IPHeader *pIpHeader,
  118. BYTE *pbRestOfPacket,
  119. UINT uiSize);
  120. VOID
  121. LogData(
  122. PFETYPE pfeType,
  123. PFILTER_INTERFACE pIf,
  124. DWORD dwFilterRule,
  125. UNALIGNED IPHeader *pIpHeader,
  126. BYTE *pbRestOfPacket,
  127. UINT uiPacketLength);
  128. VOID
  129. AdvanceLog(PPFLOGINTERFACE pLog);
  130. PFILTER
  131. LookForFilter(PFILTER_INTERFACE pIf,
  132. ULARGE_INTEGER UNALIGNED * puliSrcDstAddr,
  133. PULARGE_INTEGER puliProtoSrcDstPort,
  134. DWORD dwSum,
  135. DWORD dwFlags);
  136. PFILTER
  137. CheckFragAllowed(
  138. PFILTER_INTERFACE pIf,
  139. UNALIGNED IPHeader *pIp);
  140. BOOL
  141. CheckForTcpCtl(
  142. PFILTER_INTERFACE pIf,
  143. DWORD Prot,
  144. UNALIGNED IPHeader *pIp,
  145. PBYTE pbRest,
  146. DWORD dwSize);
  147. //
  148. // definitions
  149. //
  150. #define GLOBS_UNREACH 0x1
  151. #define GLOBS_SPOOF 0x2
  152. #define GLOBS_SYN 0x4
  153. #define GLOBS_REDIRECT 0x8
  154. #define GLOBS_SYNDrop 0x10
  155. #define GLOBS_TCPGood 0x20
  156. #define OutCacheMatch(uliAddr,uliPort,outCtxt,pOutCache) \
  157. ((uliAddr).QuadPart is pOutCache->uliSrcDstAddr.QuadPart) and \
  158. ((uliPort).QuadPart is pOutCache->uliProtoSrcDstPort.QuadPart) and \
  159. (pOutCache->pOutContext is (outCtxt))
  160. #define InCacheMatch(uliAddr,uliPort,inCtxt,pInCache) \
  161. ((uliAddr).QuadPart is pInCache->uliSrcDstAddr.QuadPart) and \
  162. ((uliPort).QuadPart is pInCache->uliProtoSrcDstPort.QuadPart) and \
  163. (pInCache->pInContext is (inCtxt))
  164. #define GenericFilterMatch(uliAddr,uliPort, pFilter) \
  165. ((uliAddr).QuadPart is pFilter->uliSrcDstAddr.QuadPart) and \
  166. ((uliPort).QuadPart is pFilter->uliProtoSrcDstPort.QuadPart)
  167. #define InFilterMatch(uliAddr,uliPort, pInFilter) \
  168. ((uliAddr).QuadPart is pInFilter->uliSrcDstAddr.QuadPart) and \
  169. ((uliPort).QuadPart is pInFilter->uliProtoSrcDstPort.QuadPart)
  170. #define OutFilterMatch(uliAddr,uliPort,pOutFilter) \
  171. ((uliAddr).QuadPart is pOutFilter->uliSrcDstAddr.QuadPart) and \
  172. ((uliPort).QuadPart is pOutFilter->uliProtoSrcDstPort.QuadPart)
  173. //
  174. // There is a race condition in that when the cache match is done, the code first
  175. // copies out the value of the pointer to the entry and then InterlockedIncrements
  176. // the dwCount variable. The race condition can occur because between the time the
  177. // matching code keeps a ref. to the entry and increments the variable some other
  178. // thread could remove the entry from that cache (i.e update that entry) and put
  179. // it at the tail of the free list. Then if the entry ALSO comes to the head
  180. // of the list BEFORE the other thread has the chance to increment the var, then
  181. // the following Update macros will see a dwCount of 0 and begin to use this block
  182. // But the other thread will assume valid values in the cache entry
  183. // and use those values. The chances of this hapenning are so so so low that I am
  184. // going ahead with this model
  185. //
  186. #define OutCacheUpdate(uliAddr,uliPort,outCtxt,eaAct,dwId,pdwHit) { \
  187. PFILTER_OUTCACHE __pTemp; \
  188. PLIST_ENTRY __pNode; \
  189. TRACE(CACHE,("IPFLTDRV: Attempting out cache update\n")); \
  190. __pNode = ExInterlockedRemoveHeadList(&g_freeOutFilters,&g_lOutFilterLock); \
  191. __pTemp = CONTAINING_RECORD(__pNode,FILTER_OUTCACHE,leFreeLink); \
  192. if(__pTemp isnot NULL) \
  193. { \
  194. if(__pTemp->lCount <= 0) \
  195. { \
  196. __pTemp->uliSrcDstAddr = (uliAddr); \
  197. __pTemp->uliProtoSrcDstPort = (uliPort); \
  198. __pTemp->pOutContext = (outCtxt); \
  199. __pTemp->eaOutAction = (eaAct); \
  200. __pTemp->pOutFilter = (pdwHit); \
  201. __pTemp = (PFILTER_OUTCACHE)InterlockedExchangePointer(&g_filters.ppOutCache[(dwId)], \
  202. __pTemp); \
  203. ExInterlockedInsertTailList(&g_freeOutFilters, \
  204. &(__pTemp->leFreeLink),&g_lOutFilterLock); \
  205. TRACE(CACHE,("IPFLTDRV: Managed out cache update - ignore next msg\n")); \
  206. } \
  207. else \
  208. { \
  209. ExInterlockedInsertTailList(&g_freeOutFilters, \
  210. &(__pTemp->leFreeLink), \
  211. &g_lOutFilterLock); \
  212. } \
  213. } \
  214. TRACE(CACHE,("IPFLTDRV: Couldnt get into out cache for update\n")); \
  215. }
  216. #define InCacheUpdate(uliAddr,uliPort,inCtxt,eaAct,dwId,pfHit) { \
  217. PFILTER_INCACHE __pTemp; \
  218. PLIST_ENTRY __pNode; \
  219. TRACE(CACHE,("IPFLTDRV: Attempting in cache update\n")); \
  220. __pNode = ExInterlockedRemoveHeadList(&g_freeInFilters,&g_lInFilterLock); \
  221. __pTemp = CONTAINING_RECORD(__pNode,FILTER_INCACHE,leFreeLink); \
  222. if(__pTemp isnot NULL) \
  223. { \
  224. if(__pTemp->lCount <= 0) \
  225. { \
  226. __pTemp->uliSrcDstAddr = (uliAddr); \
  227. __pTemp->uliProtoSrcDstPort = (uliPort); \
  228. __pTemp->pInContext = (inCtxt); \
  229. __pTemp->eaInAction = (eaAct); \
  230. __pTemp->pOutContext = NULL; \
  231. __pTemp->pInFilter = (pfHit); \
  232. __pTemp->pOutFilter = NULL; \
  233. __pTemp = (PFILTER_INCACHE)InterlockedExchangePointer(&g_filters.ppInCache[(dwId)], \
  234. __pTemp); \
  235. ExInterlockedInsertTailList(&g_freeInFilters, \
  236. &(__pTemp->leFreeLink),&g_lInFilterLock); \
  237. TRACE(CACHE,("IPFLTDRV: Managed out cache update - ignore next msg\n")); \
  238. } \
  239. else \
  240. { \
  241. ExInterlockedInsertTailList(&g_freeInFilters, \
  242. &(__pTemp->leFreeLink), \
  243. &g_lInFilterLock); \
  244. } \
  245. } \
  246. TRACE(CACHE,("IPFLTDRV: Couldnt get into in cache for update\n")); \
  247. }
  248. #define InCacheFullUpdate(uliAddr,uliPort,inCtxt,eaInAct,outCtxt,eaOutAct,dwId,pdwHit1,pdwHit2){ \
  249. PFILTER_INCACHE __pTemp; \
  250. PLIST_ENTRY __pNode; \
  251. TRACE(CACHE,("IPFLTDRV: Attempting in cache full update\n")); \
  252. __pNode = ExInterlockedRemoveHeadList(&g_freeInFilters,&g_lInFilterLock); \
  253. __pTemp = CONTAINING_RECORD(__pNode,FILTER_INCACHE,leFreeLink); \
  254. if(__pTemp isnot NULL) \
  255. { \
  256. if(__pTemp->lCount <= 0) \
  257. { \
  258. __pTemp->uliSrcDstAddr = (uliAddr); \
  259. __pTemp->uliProtoSrcDstPort = (uliPort); \
  260. __pTemp->pInContext = (inCtxt); \
  261. __pTemp->eaInAction = (eaInAct); \
  262. __pTemp->pOutContext = (outCtxt); \
  263. __pTemp->eaOutAction = (eaOutAct); \
  264. __pTemp->pInFilter = (pdwHit1); \
  265. __pTemp->pOutFilter = (pdwHit2); \
  266. __pTemp->lOutEpoch = outCtxt->lEpoch; \
  267. __pTemp = (PFILTER_INCACHE)InterlockedExchangePointer(&g_filters.ppInCache[(dwId)], \
  268. __pTemp); \
  269. ExInterlockedInsertTailList(&g_freeInFilters, \
  270. &(__pTemp->leFreeLink),&g_lInFilterLock); \
  271. TRACE(CACHE,("IPFLTDRV: Managed in cache full update - ignore next msg\n")); \
  272. } \
  273. else \
  274. { \
  275. ExInterlockedInsertTailList(&g_freeInFilters, \
  276. &(__pTemp->leFreeLink), \
  277. &g_lInFilterLock); \
  278. } \
  279. } \
  280. TRACE(CACHE,("IPFLTDRV: Couldnt get into in cache for full update\n")); \
  281. }
  282. #define InCacheOutUpdate(outCtxt,eaAct,dwId,pInCache,pdwHit) { \
  283. PFILTER_INCACHE __pTemp; \
  284. (pInCache)->pOutContext = outCtxt; \
  285. (pInCache)->pOutFilter = (pdwHit); \
  286. (pInCache)->eaOutAction = (eaAct); \
  287. (pInCache)->lOutEpoch = outCtxt->lEpoch; \
  288. __pTemp = (PFILTER_INCACHE)InterlockedExchangePointer(&g_filters.ppInCache[(dwId)], \
  289. (pInCache)); \
  290. if(__pTemp isnot (pInCache)) \
  291. { \
  292. ExInterlockedInsertTailList(&g_freeInFilters, \
  293. &(__pTemp->leFreeLink),&g_lInFilterLock); \
  294. } \
  295. } \
  296. #define LockCache(pCache){ \
  297. InterlockedIncrement(&((pCache)->lCount)); \
  298. }
  299. #define ReleaseCache(pCache){ \
  300. InterlockedDecrement(&((pCache)->lCount)); \
  301. }
  302. #define REGISTER register
  303. #define PRINT_IPADDR(x) \
  304. ((x)&0x000000FF),(((x)&0x0000FF00)>>8),(((x)&0x00FF0000)>>16),(((x)&0xFF000000)>>24)
  305. #define \
  306. FilterDriverLookupCachedInterface( \
  307. _Index, \
  308. _Link, \
  309. _pIf \
  310. ) \
  311. ( (((_pIf) = InterlockedProbeCache(g_filters.pInterfaceCache, (_Index), (_Link))) && \
  312. (_pIf)->dwIpIndex == (_Index) && (_pIf)->dwLinkIpAddress == (_Link)) \
  313. ? (_pIf) \
  314. : (((_pIf) = FilterDriverLookupInterface((_Index), (_Link))) \
  315. ? (InterlockedUpdateCache(g_filters.pInterfaceCache, (_Index),(_Link),(_pIf)), \
  316. (_pIf)) \
  317. : NULL) )
  318. //FORWARD_ACTION __fastcall
  319. FORWARD_ACTION
  320. MatchFilter(
  321. UNALIGNED IPHeader *pIpHeader,
  322. BYTE *pbRestOfPacket,
  323. UINT uiPacketLength,
  324. UINT RecvInterfaceIndex,
  325. UINT SendInterfaceIndex,
  326. IPAddr RecvLinkNextHop,
  327. IPAddr SendLinkNextHop
  328. )
  329. /*++
  330. --*/
  331. {
  332. FORWARD_ACTION faAction;
  333. if (IP_ADDR_EQUAL(RecvLinkNextHop, MAXULONG))
  334. {
  335. return FORWARD;
  336. }
  337. faAction = MatchFilterp(pIpHeader,
  338. pbRestOfPacket,
  339. uiPacketLength,
  340. RecvInterfaceIndex,
  341. SendInterfaceIndex,
  342. RecvLinkNextHop,
  343. SendLinkNextHop,
  344. NULL,
  345. NULL,
  346. FALSE,
  347. FALSE);
  348. TRACE(ACTION,(
  349. "FILTER: %d.%d.%d.%d->%d.%d.%d.%d %d (%x) %x -> %x:%x action %s\n",
  350. PRINT_IPADDR(pIpHeader->iph_src),
  351. PRINT_IPADDR(pIpHeader->iph_dest),
  352. pIpHeader->iph_protocol,
  353. *((DWORD UNALIGNED *) pbRestOfPacket),
  354. RecvInterfaceIndex,
  355. SendInterfaceIndex,
  356. (faAction == FORWARD)?"FORWARD":"DROP"
  357. ));
  358. return faAction;
  359. }
  360. FORWARD_ACTION
  361. MatchFilterp(
  362. UNALIGNED IPHeader *pIpHeader,
  363. BYTE *pbRestOfPacket,
  364. UINT uiPacketLength,
  365. UINT RecvInterfaceIndex,
  366. UINT SendInterfaceIndex,
  367. IPAddr RecvLinkNextHop,
  368. IPAddr SendLinkNextHop,
  369. INTERFACE_CONTEXT RecvInterfaceContext,
  370. INTERFACE_CONTEXT SendInterfaceContext,
  371. BOOL fInnerCall,
  372. BOOL fIoctlCall
  373. )
  374. {
  375. REGISTER PFILTER_INTERFACE pInInterface, pOutInterface;
  376. ULARGE_INTEGER UNALIGNED * puliSrcDstAddr;
  377. ULARGE_INTEGER uliProtoSrcDstPort;
  378. REGISTER FORWARD_ACTION eaAction;
  379. REGISTER ULARGE_INTEGER uliAddr;
  380. REGISTER ULARGE_INTEGER uliPort;
  381. LOCK_STATE LockState, LockStateExt;
  382. DWORD dwIndex, dwSum;
  383. REGISTER DWORD i;
  384. UNALIGNED WORD *pwPort;
  385. REGISTER PFILTER_INCACHE pInCache;
  386. REGISTER PFILTER_OUTCACHE pOutCache;
  387. PFILTER pf, pf1;
  388. DWORD dwGlobals = 0;
  389. UNALIGNED IPHeader *RedirectHeader;
  390. PBYTE pbRest;
  391. UINT uiLength;
  392. BOOLEAN bFirstFrag = FALSE;
  393. DWORD dwId, dwFragIndex;
  394. KIRQL kiCurrIrql;
  395. PLIST_ENTRY pleNode;
  396. PF_FORWARD_ACTION pfAction = PF_PASS;
  397. #ifdef DRIVER_PERF
  398. LARGE_INTEGER liTimeIn, liTimeOut;
  399. #endif
  400. //
  401. // If the packet is part of a fragment, accept it
  402. // 3 13 bits
  403. // |---|-------------| ---> Network Byte Order
  404. // Fl Frag Offset
  405. // Need to and with 0x1fff (in nbo) which would be 0xff1f in little endian
  406. //
  407. #ifdef BASE_PERF
  408. return FORWARD;
  409. #else // BASE_PERF
  410. RecordTimeIn();
  411. if (!fIoctlCall)
  412. {
  413. //
  414. // Call the extension driver if there is any. Also, pass the
  415. // extension driver's interface contexts and the interface indexes.
  416. //
  417. AcquireReadLock(&g_Extension.ExtLock, &LockStateExt);
  418. if (g_Extension.ExtPointer)
  419. {
  420. //
  421. // We will be accessing the interface so obtain a read lock on them.
  422. //
  423. pfAction = g_Extension.ExtPointer(
  424. (unsigned char *)pIpHeader,
  425. pbRestOfPacket,
  426. uiPacketLength,
  427. RecvInterfaceIndex,
  428. SendInterfaceIndex,
  429. RecvLinkNextHop,
  430. SendLinkNextHop
  431. );
  432. //
  433. // If the action returned is FORWARD or DROP, then forward the action as it is.
  434. // Any other action must be taken by the filter driver only.
  435. //
  436. if (pfAction == PF_FORWARD)
  437. {
  438. ReleaseReadLock(&g_Extension.ExtLock, &LockStateExt);
  439. return(FORWARD);
  440. }
  441. else if (pfAction == PF_DROP)
  442. {
  443. ReleaseReadLock(&g_Extension.ExtLock, &LockStateExt);
  444. return(DROP);
  445. }
  446. }
  447. ReleaseReadLock(&g_Extension.ExtLock, &LockStateExt);
  448. //
  449. // Quick check to see if there are bound interfaces.
  450. // We make this check only for callouts coming directly from IP.
  451. //
  452. if (!g_ulBoundInterfaceCount)
  453. {
  454. return(FORWARD);
  455. }
  456. //
  457. // Lookup the the filter driver interfaces.
  458. //
  459. AcquireReadLock(&g_filters.ifListLock, &LockState);
  460. if (RecvInterfaceIndex != INVALID_IF_INDEX)
  461. {
  462. FilterDriverLookupCachedInterface(
  463. RecvInterfaceIndex,
  464. RecvLinkNextHop,
  465. pInInterface
  466. );
  467. }
  468. else
  469. {
  470. pInInterface = NULL;
  471. }
  472. if (SendInterfaceIndex != INVALID_IF_INDEX)
  473. {
  474. FilterDriverLookupCachedInterface(
  475. SendInterfaceIndex,
  476. SendLinkNextHop,
  477. pOutInterface
  478. );
  479. }
  480. else
  481. {
  482. pOutInterface = NULL;
  483. }
  484. }
  485. else
  486. {
  487. AcquireReadLock(&g_filters.ifListLock, &LockState);
  488. pInInterface = (PFILTER_INTERFACE)RecvInterfaceContext;
  489. pOutInterface = (PFILTER_INTERFACE)SendInterfaceContext;
  490. }
  491. //
  492. // Normal filter driver processing continues at this point.
  493. //
  494. if(!pInInterface && !pOutInterface)
  495. {
  496. //
  497. // Quick check for this case, there are filter driver
  498. // interfaces just that nothing of our interest.
  499. //
  500. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  501. return (FORWARD);
  502. }
  503. if((pIpHeader->iph_offset & 0xff1f) is 0)
  504. {
  505. if (pIpHeader->iph_offset & 0x0020)
  506. {
  507. //
  508. // If it is the first IPSEC fragment forward it, or drop it
  509. // based on the state of fragment filter.
  510. //
  511. if((pIpHeader->iph_protocol is PROT_IPSECAH) ||
  512. (pIpHeader->iph_protocol is PROT_IPSECESP))
  513. {
  514. if (pInInterface && pInInterface->CountNoFrag.lInUse)
  515. {
  516. RegisterFragAttack(
  517. pInInterface,
  518. pIpHeader,
  519. pbRestOfPacket,
  520. uiPacketLength);
  521. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  522. return(DROP);
  523. }
  524. else
  525. {
  526. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  527. return(FORWARD);
  528. }
  529. }
  530. if (pInInterface && pInInterface->CountFragCache.lInUse)
  531. {
  532. TRACE(FRAG,("IPFLTDRV: Packet is the first fragment\n"));
  533. bFirstFrag = TRUE;
  534. }
  535. }
  536. }
  537. else
  538. {
  539. WORD wFrag;
  540. TRACE(FRAG,("IPFLTDRV: Packet is a fragment\n"));
  541. RecordTimeOut();
  542. IncrementFragments();
  543. eaAction = FORWARD;
  544. do
  545. {
  546. if(pInInterface is NULL)
  547. {
  548. TRACE(FRAG,("IPFLTDRV: InInterface is NULL on FRAG - forward\n"));
  549. break;
  550. }
  551. if (!pInInterface->CountFragCache.lInUse &&
  552. !pInInterface->CountSynOrFrag.lInUse &&
  553. !pInInterface->CountNoFrag.lInUse
  554. )
  555. {
  556. //
  557. // None of the fragment filters are being used.
  558. // FORWARD
  559. //
  560. TRACE(FRAG,("IPFLTDRV: No FRAG filters being used - forward\n"));
  561. break;
  562. }
  563. if (pInInterface->CountSynOrFrag.lInUse &&
  564. ((pIpHeader->iph_protocol == 6) ||
  565. (pIpHeader->iph_protocol == 17) ||
  566. (pIpHeader->iph_protocol == 1)) )
  567. {
  568. //
  569. // allowing only valid-looking frags.
  570. //
  571. wFrag = net_short(pIpHeader->iph_offset) & 0x1fff;
  572. }
  573. else
  574. {
  575. //
  576. // allowing all of these frags.
  577. //
  578. wFrag = (WORD)g_FragThresholdSize;
  579. }
  580. //
  581. // compute extent of this fragment. If it is bigger than
  582. // 64K, log it and drop it.
  583. //
  584. if( (wFrag < (WORD)g_FragThresholdSize)
  585. ||
  586. (((wFrag << 3) +
  587. (((UINT)net_short(pIpHeader->iph_length)) - (((pIpHeader->iph_verlen)&0x0f)<<2)))
  588. > 0xFFFF) )
  589. {
  590. eaAction = DROP;
  591. TRACE(FRAG,("IPFLTDRV: SynOrFrag attck - DROP\n"));
  592. break;
  593. }
  594. //
  595. // The Fragment-Cache filter takes precedence over other
  596. // fragment filter.
  597. //
  598. if ((pInInterface->CountFragCache.lInUse) &&
  599. (pIpHeader->iph_protocol != PROT_IPSECAH) &&
  600. (pIpHeader->iph_protocol != PROT_IPSECESP))
  601. {
  602. //
  603. // If it is a IPSEC fragment forward it, don't touch it
  604. // as IPSec fragment are not kept in the cache.
  605. //
  606. BOOL bFound = FALSE;
  607. TRACE(FRAG,("IPFLTDRV: FRAG Offset is 0x%04x\n", pIpHeader->iph_offset));
  608. uliProtoSrcDstPort.LowPart =
  609. MAKELONG(MAKEWORD(pIpHeader->iph_protocol,0x00),0x0000);
  610. dwId =
  611. MAKELONG(
  612. LOWORD(uliProtoSrcDstPort.LowPart), pIpHeader->iph_id);
  613. puliSrcDstAddr =
  614. (PULARGE_INTEGER)(&(pIpHeader->iph_src));
  615. //
  616. // Look up id in frag table and check for a match
  617. //
  618. dwFragIndex = dwId % g_dwFragTableSize;
  619. TRACE(FRAG,(
  620. "IPFLTDRV: Checking fragment cache for index %d\n",
  621. dwFragIndex
  622. ));
  623. KeAcquireSpinLock(&g_kslFragLock, &kiCurrIrql);
  624. for(pleNode = g_pleFragTable[dwFragIndex].Flink;
  625. pleNode isnot &(g_pleFragTable[dwFragIndex]);
  626. pleNode = pleNode->Flink)
  627. {
  628. PFRAG_INFO pfiFragInfo;
  629. pfiFragInfo =
  630. CONTAINING_RECORD(pleNode, FRAG_INFO, leCacheLink);
  631. if((pfiFragInfo->uliSrcDstAddr.QuadPart ==
  632. puliSrcDstAddr->QuadPart) &&
  633. (pfiFragInfo->pvInContext == pInInterface) &&
  634. (pfiFragInfo->pvOutContext == pOutInterface) &&
  635. (pfiFragInfo->dwId == dwId))
  636. {
  637. TRACE(FRAG,("IPFLTDRV: FRAG: Found entry %x\n", pfiFragInfo));
  638. eaAction = pfiFragInfo->faAction;
  639. KeQueryTickCount((PLARGE_INTEGER)&(pfiFragInfo->llLastAccess));
  640. bFound = TRUE;
  641. break;
  642. }
  643. }
  644. KeReleaseSpinLock(&g_kslFragLock, kiCurrIrql);
  645. //
  646. // This fragment was found in the fragment cache.
  647. //
  648. if (bFound)
  649. {
  650. break;
  651. }
  652. }
  653. if (pInInterface->CountNoFrag.lInUse)
  654. {
  655. //
  656. // Fragment filter is in use
  657. //
  658. eaAction = DROP;
  659. break;
  660. }
  661. #if DOFRAGCHECKING
  662. if(eaAction == FORWARD)
  663. {
  664. pf = CheckFragAllowed(pInInterface,
  665. pIpHeader);
  666. eaAction = pInInterface->eaInAction;
  667. if(pf)
  668. {
  669. eaAction ^= 1;
  670. }
  671. FiltHit(pf,
  672. pInInterface,
  673. eaAction,
  674. pIpHeader,
  675. pbRestOfPacket,
  676. uiPacketLength,
  677. TRUE);
  678. }
  679. #endif // if DOFRAGCHECKING
  680. } while(FALSE);
  681. if (eaAction == DROP)
  682. {
  683. //
  684. // bogus.
  685. //
  686. RegisterFragAttack(
  687. pInInterface,
  688. pIpHeader,
  689. pbRestOfPacket,
  690. uiPacketLength);
  691. }
  692. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  693. TRACE(FRAG,(
  694. "IPFLTDRV: FRAG: Returning %s for frag\n",
  695. (eaAction is DROP)?"DROP":"FORWARD"
  696. ));
  697. return eaAction;
  698. }
  699. #if 0
  700. //
  701. // Extract all the information out of the header
  702. //
  703. if((pIpHeader->iph_protocol == PROT_IPSECAH)
  704. &&
  705. !fInnerCall
  706. &&
  707. (uiPacketLength > SIZE_OF_IPSECAH))
  708. {
  709. //
  710. // if this is the call from the stack, call again
  711. // to check on the IPSEC header. If that succeeds, then
  712. // check on the upper layer protocol fields.
  713. //
  714. if(MatchFilterp(
  715. pIpHeader,
  716. pbRestOfPacket,
  717. uiPacketLength,
  718. RecvIntefaceContext,
  719. SendInterfaceContext,
  720. TRUE) == DROP)
  721. {
  722. return(DROP);
  723. }
  724. pbRest = pbRestOfPacket + SIZE_OF_IPSECAH;
  725. uiLength = uiPacketLength - SIZE_OF_IPSECAH;
  726. //
  727. // get the next protocol from the IPSEC header
  728. //
  729. uliProtoSrcDstPort.LowPart =
  730. MAKELONG(MAKEWORD(((UNALIGNED PAH)pbRest)->ah_next,0x00),0x0000);
  731. }
  732. else
  733. {
  734. pbRest = pbRestOfPacket;
  735. uiLength = uiPacketLength;
  736. uliProtoSrcDstPort.LowPart =
  737. MAKELONG(MAKEWORD(pIpHeader->iph_protocol,0x00),0x0000);
  738. }
  739. #endif
  740. pbRest = pbRestOfPacket;
  741. uiLength = uiPacketLength;
  742. uliProtoSrcDstPort.LowPart =
  743. MAKELONG(MAKEWORD(pIpHeader->iph_protocol,0x00),0x0000);
  744. pwPort = (UNALIGNED WORD *)pbRest;
  745. puliSrcDstAddr = (PULARGE_INTEGER)(&(pIpHeader->iph_src));
  746. dwId =
  747. MAKELONG(LOWORD(uliProtoSrcDstPort.LowPart), pIpHeader->iph_id);
  748. //
  749. // Ports make sense only for TCP and UDP
  750. //
  751. //
  752. // TCP/UDP header
  753. // 0 15 16 31
  754. // |----|----|----|----|----|----|----|----|
  755. // | Source Port | Dst Port |
  756. //
  757. switch(uliProtoSrcDstPort.LowPart)
  758. {
  759. case 1: //ICMP
  760. {
  761. BYTE bType, bCode;
  762. //
  763. // The type and code go into high part. Make sure there is enough
  764. // data.
  765. //
  766. if(uiLength >= 2)
  767. {
  768. uliProtoSrcDstPort.HighPart = MAKELONG(pwPort[0],0x0000);
  769. //
  770. // two checks: unassigned port check and incoming
  771. // redirect address check may be requested. The first
  772. // is done only if this is a frame sent from this
  773. // machine. the second is done only if this is
  774. // a frame sent by this machine.
  775. // Note, spoof checking, if needed, is done in the
  776. // common path.
  777. switch(pwPort[0] & 0xff)
  778. {
  779. UNALIGNED IPHeader * IpHead;
  780. PICMPHeader pIcmp;
  781. case ICMP_DEST_UNREACH:
  782. dwGlobals |= GLOBS_UNREACH;
  783. break;
  784. case ICMP_REDIRECT:
  785. if(uiLength >= (sizeof(ICMPHeader) +
  786. sizeof(IPHeader) ) )
  787. {
  788. dwGlobals |= GLOBS_REDIRECT;
  789. pIcmp = (PICMPHeader)pbRest;
  790. RedirectHeader = (UNALIGNED IPHeader *)(pIcmp + 1);
  791. }
  792. break;
  793. }
  794. }
  795. else
  796. {
  797. //
  798. // if mal-formed, use invalid codes
  799. //
  800. uliProtoSrcDstPort.HighPart = MAKELONG(0xffff, 0x0000);
  801. }
  802. break;
  803. }
  804. case 6: //TCP
  805. {
  806. DWORD dwFlags1;
  807. UNALIGNED TCPHeader *pTcpHdr =
  808. (UNALIGNED TCPHeader *)pbRest;
  809. //
  810. // if a valid TCP packet, compute whether it is a SYN or
  811. // an established connection. If the frame is invalid, assume
  812. // it is a SYN.
  813. //
  814. if(uiLength >= sizeof(TCPHeader))
  815. {
  816. dwGlobals |= GLOBS_TCPGood;
  817. //
  818. // Now all the funky stuff with the flags.
  819. //
  820. if(pTcpHdr->tcp_flags & ( TCP_FLAG_ACK | TCP_FLAG_RST ) )
  821. {
  822. dwFlags1 = ESTAB_FLAGS;
  823. }
  824. else
  825. {
  826. dwFlags1 = 0;
  827. }
  828. //
  829. // Set the LP1 byte of theProtoSrcDstPort
  830. //
  831. uliProtoSrcDstPort.LowPart |=
  832. MAKELONG(MAKEWORD(0x00,LOWORD(LOBYTE(dwFlags1))),0x0000);
  833. }
  834. }
  835. //
  836. // and fall through to the common TCP/UDP code.
  837. //
  838. case 17: //UDP
  839. {
  840. if(uiLength >= 4)
  841. {
  842. uliProtoSrcDstPort.HighPart = MAKELONG(pwPort[0],pwPort[1]);
  843. }
  844. else
  845. {
  846. //
  847. // malformed. Use invalid port numbers
  848. //
  849. uliProtoSrcDstPort.HighPart = 0;
  850. }
  851. break;
  852. }
  853. default:
  854. {
  855. uliProtoSrcDstPort.HighPart = 0x00000000;
  856. break;
  857. }
  858. }
  859. TRACE(CACHE,(
  860. "IPFLTDRV: Addr Large Int: High= %0#8x Low= %0#8x\n",
  861. puliSrcDstAddr->HighPart,
  862. puliSrcDstAddr->LowPart
  863. ));
  864. TRACE(CACHE,(
  865. "IPFLTDRV: Packet value is Src: %0#8x Dst: %0#8x\n",
  866. pIpHeader->iph_src,
  867. pIpHeader->iph_dest
  868. ));
  869. TRACE(CACHE,(
  870. "IPFLTDRV: Proto/Port:High= %0#8x Low= %0#8x\n",
  871. uliProtoSrcDstPort.HighPart,
  872. uliProtoSrcDstPort.LowPart
  873. ));
  874. TRACE(CACHE,("IPFLTDRV: Iph is %x\n",pIpHeader));
  875. TRACE(CACHE,("IPFLTDRV: Addr of src is %x\n",&(pIpHeader->iph_src)));
  876. TRACE(CACHE,("IPFLTDRV: Ptr to LI is %x\n",puliSrcDstAddr));
  877. TRACE(CACHE,(
  878. "IPFLTDRV: Interfaces - IN: %x OUT: %x\n",
  879. pInInterface,
  880. pOutInterface
  881. ));
  882. //
  883. // Sum up the fields and get the cache index. We make sure the sum
  884. // is assymetric, i.e. a packet from A->B goes to different bucket
  885. // than one from B->A
  886. //
  887. dwSum = pIpHeader->iph_src +
  888. pIpHeader->iph_dest +
  889. pIpHeader->iph_dest +
  890. PROTOCOLPART(uliProtoSrcDstPort.LowPart) +
  891. uliProtoSrcDstPort.HighPart;
  892. TRACE(CACHE,("IPFLTDRV: Sum of field is %0#8x ",dwSum));
  893. dwIndex = dwSum % g_dwCacheSize;
  894. TRACE(CACHE,("IPFLTDRV: Cache Index is %d \n",dwIndex));
  895. //
  896. // If the inInterface is NULL means we originated the Packet so we only apply the
  897. // out filter set to it
  898. //
  899. if(pInInterface is NULL)
  900. {
  901. //
  902. // Just an out interface to consider
  903. //
  904. if(pOutInterface->CountFullDeny.lInUse)
  905. {
  906. //
  907. // full deny is in force. Just drop it
  908. //
  909. RegisterFullDeny(
  910. pOutInterface,
  911. pIpHeader,
  912. pbRestOfPacket,
  913. uiPacketLength);
  914. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  915. return DROP;
  916. }
  917. //
  918. // sending from this machine. Check for reporting an UNREACH
  919. // condition
  920. //
  921. #if 0 // don't do this
  922. if(dwGlobals & GLOBS_UNREACH)
  923. {
  924. //
  925. // it is an ICMP unreachable. See if this interface
  926. // is interested in these.
  927. //
  928. if(pOutInterface->CountUnused.lInUse)
  929. {
  930. RegisterUnusedICMP(pOutInterface,
  931. pIpHeader,
  932. pbRestOfPacket,
  933. uiPacketLength);
  934. }
  935. }
  936. #endif
  937. pOutCache = g_filters.ppOutCache[dwIndex];
  938. TRACE(CACHE,("IPFLTDRV: In Interface is NULL\n"));
  939. //
  940. // Try for a quick cache probe
  941. //
  942. LockCache(pOutCache);
  943. if(OutCacheMatch(*puliSrcDstAddr,uliProtoSrcDstPort,pOutInterface,pOutCache))
  944. {
  945. TRACE(CACHE,("IPFLTDRV: OutCache Match\n"));
  946. eaAction = pOutCache->eaOutAction;
  947. ReleaseCache(pOutCache);
  948. FiltHit(pOutCache->pOutFilter,
  949. pOutCache->pOutContext,
  950. eaAction,
  951. pIpHeader,
  952. pbRestOfPacket,
  953. uiPacketLength,
  954. FALSE);
  955. // InterlockedIncrement(pOutCache->pdwOutHitCounter);
  956. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  957. TRACE(ACTION,(
  958. "IPFLTDRV: Packet is being %s\n",
  959. (eaAction is DROP)?"DROPPED":"FORWARDED"
  960. ));
  961. RecordTimeOut();
  962. IncrementCache1();
  963. return eaAction;
  964. }
  965. ReleaseCache(pOutCache);
  966. TRACE(CACHE,("IPFLTDRV: Didnt match cache entry\n"));
  967. TRACE(CACHE,("IPFLTDRV: Walking out filter list\n"));
  968. pf = LookForFilter(pOutInterface,
  969. puliSrcDstAddr,
  970. &uliProtoSrcDstPort,
  971. dwSum,
  972. 0);
  973. if(pf)
  974. {
  975. //
  976. // Update the out cache
  977. //
  978. eaAction = pOutInterface->eaOutAction ^ 0x00000001;
  979. if((eaAction == DROP)
  980. &&
  981. pOutInterface->CountCtl.lInUse)
  982. {
  983. //
  984. // it's a drop and this interface is allowing all
  985. // TCP control frames. See if this is a TCP control
  986. // frame.
  987. if(CheckForTcpCtl(
  988. pOutInterface,
  989. PROTOCOLPART(uliProtoSrcDstPort.LowPart),
  990. pIpHeader,
  991. pbRestOfPacket,
  992. uiPacketLength))
  993. {
  994. pf = 0;
  995. eaAction = FORWARD;
  996. }
  997. }
  998. if(pf)
  999. {
  1000. OutCacheUpdate(*puliSrcDstAddr,
  1001. uliProtoSrcDstPort,
  1002. pOutInterface,
  1003. eaAction,
  1004. dwIndex,
  1005. pf);
  1006. FiltHit(pf,
  1007. pOutInterface,
  1008. eaAction,
  1009. pIpHeader,
  1010. pbRestOfPacket,
  1011. uiPacketLength,
  1012. FALSE);
  1013. }
  1014. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1015. TRACE(ACTION,(
  1016. "IPFLTDRV: Packet is being %s\n",
  1017. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1018. ));
  1019. RecordTimeOut();
  1020. IncrementWalk1();
  1021. return eaAction;
  1022. }
  1023. TRACE(CACHE,("IPFLTDRV: Didnt match any out filters\n"));
  1024. eaAction = pOutInterface->eaOutAction;
  1025. if((eaAction == DROP)
  1026. &&
  1027. pOutInterface->CountCtl.lInUse)
  1028. {
  1029. if(CheckForTcpCtl(pOutInterface,
  1030. PROTOCOLPART(uliProtoSrcDstPort.LowPart),
  1031. pIpHeader,
  1032. pbRestOfPacket,
  1033. uiPacketLength))
  1034. {
  1035. eaAction = FORWARD;
  1036. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1037. TRACE(ACTION,("IPFLTDRV: Packet is being FORWARDED\n"));
  1038. RecordTimeOut();
  1039. IncrementWalk1();
  1040. return eaAction;
  1041. }
  1042. }
  1043. OutCacheUpdate(*puliSrcDstAddr,
  1044. uliProtoSrcDstPort,
  1045. pOutInterface,
  1046. eaAction,
  1047. dwIndex,
  1048. NULL);
  1049. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1050. TRACE(ACTION,(
  1051. "IPFLTDRV: Packet is being %s\n",
  1052. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1053. ));
  1054. RecordTimeOut();
  1055. IncrementWalk1();
  1056. // InterlockedIncrement(&g_dwNumHitsDefaultOut);
  1057. return eaAction;
  1058. }
  1059. else
  1060. {
  1061. PFILTER pfHit;
  1062. if(pInInterface->CountFullDeny.lInUse)
  1063. {
  1064. RegisterFullDeny(
  1065. pInInterface,
  1066. pIpHeader,
  1067. pbRestOfPacket,
  1068. uiPacketLength);
  1069. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1070. eaAction = DROP;
  1071. if (bFirstFrag)
  1072. {
  1073. FragCacheUpdate(*puliSrcDstAddr,
  1074. pInInterface,
  1075. pOutInterface,
  1076. dwId,
  1077. eaAction);
  1078. }
  1079. return(eaAction);
  1080. }
  1081. pInCache = g_filters.ppInCache[dwIndex];
  1082. //
  1083. // In Interface isnot NULL.
  1084. //
  1085. LockCache(pInCache);
  1086. if(InCacheMatch(*puliSrcDstAddr,uliProtoSrcDstPort,pInInterface,pInCache))
  1087. {
  1088. //
  1089. // We have a cache hit
  1090. //
  1091. eaAction = pInCache->eaInAction;
  1092. //
  1093. // if dropping a frame meant for this machine,
  1094. // see if the TCP CTL override applies
  1095. //
  1096. if((eaAction == DROP)
  1097. &&
  1098. !pOutInterface
  1099. &&
  1100. pInInterface->CountCtl.lInUse)
  1101. {
  1102. if(CheckForTcpCtl(pInInterface,
  1103. PROTOCOLPART(uliProtoSrcDstPort.LowPart),
  1104. pIpHeader,
  1105. pbRestOfPacket,
  1106. uiPacketLength))
  1107. {
  1108. eaAction = FORWARD;
  1109. }
  1110. }
  1111. //
  1112. // if not DROP check for spoofing.
  1113. //
  1114. if(eaAction == FORWARD)
  1115. {
  1116. if(pInInterface->dwIpIndex != UNKNOWN_IP_INDEX)
  1117. {
  1118. if(pInInterface->CountSpoof.lInUse)
  1119. {
  1120. IPAddr SrcAddr = puliSrcDstAddr->LowPart;
  1121. //
  1122. // we need to check these addresses
  1123. //
  1124. if(!CheckAddress(SrcAddr, pInInterface->dwIpIndex))
  1125. {
  1126. eaAction = DROP;
  1127. }
  1128. }
  1129. if(pInInterface->CountStrongHost.lInUse)
  1130. {
  1131. IPAddr DstAddr = puliSrcDstAddr->HighPart;
  1132. if(!MatchLocalLook(DstAddr, pInInterface->dwIpIndex))
  1133. {
  1134. eaAction = DROP;
  1135. }
  1136. }
  1137. }
  1138. if(eaAction == DROP)
  1139. {
  1140. //
  1141. // Spoofed address. Log it and drop this
  1142. //
  1143. //
  1144. RegisterSpoof(pInInterface,
  1145. pIpHeader,
  1146. pbRestOfPacket,
  1147. uiPacketLength);
  1148. ReleaseCache(pInCache);
  1149. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1150. eaAction = DROP;
  1151. if (bFirstFrag)
  1152. {
  1153. FragCacheUpdate(*puliSrcDstAddr,
  1154. pInInterface,
  1155. pOutInterface,
  1156. dwId,
  1157. eaAction);
  1158. }
  1159. return(eaAction);
  1160. }
  1161. if( (PROTOCOLPART(uliProtoSrcDstPort.LowPart) == 6)
  1162. &&
  1163. (dwGlobals & GLOBS_TCPGood)
  1164. &&
  1165. ((((PTCPHeader)pbRest)->tcp_flags &
  1166. (TCP_FLAG_SYN | TCP_FLAG_ACK)) == TCP_FLAG_SYN) )
  1167. {
  1168. pInInterface->liSYNCount.QuadPart++;
  1169. }
  1170. }
  1171. TRACE(CACHE,("IPFLTDRV: Matched InCache entry\n"));
  1172. FiltHit(pInCache->pInFilter,
  1173. pInCache->pInContext,
  1174. eaAction,
  1175. pIpHeader,
  1176. pbRestOfPacket,
  1177. uiPacketLength,
  1178. TRUE);
  1179. // InterlockedIncrement(pInCache->pdwInHitCounter);
  1180. if((eaAction == DROP) || (pOutInterface == NULL))
  1181. {
  1182. //
  1183. // In case the packet is destined for this machine or if the action is
  1184. // to drop the packet, we dont need to look at the out interface at all
  1185. //
  1186. TRACE(ACTION,(
  1187. "IPFLTDRV: Action is %s and context is %x so finished\n",
  1188. (pInCache->eaInAction is DROP)?"DROP":"FORWARD",
  1189. pOutInterface
  1190. ));
  1191. ReleaseCache(pInCache);
  1192. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1193. if (bFirstFrag)
  1194. {
  1195. FragCacheUpdate(*puliSrcDstAddr,
  1196. pInInterface,
  1197. pOutInterface,
  1198. dwId,
  1199. eaAction);
  1200. }
  1201. TRACE(ACTION,(
  1202. "IPFLTDRV: Packet is being %s\n",
  1203. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1204. ));
  1205. RecordTimeOut();
  1206. IncrementCache1();
  1207. return eaAction;
  1208. }
  1209. //
  1210. // This is the case where we have to apply out filters
  1211. //
  1212. if(pOutInterface->CountFullDeny.lInUse)
  1213. {
  1214. //
  1215. // full deny is in force. Just drop it
  1216. //
  1217. RegisterFullDeny(
  1218. pOutInterface,
  1219. pIpHeader,
  1220. pbRestOfPacket,
  1221. uiPacketLength);
  1222. ReleaseCache(pInCache);
  1223. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1224. eaAction = DROP;
  1225. if (bFirstFrag)
  1226. {
  1227. FragCacheUpdate(*puliSrcDstAddr,
  1228. pInInterface,
  1229. pOutInterface,
  1230. dwId,
  1231. eaAction);
  1232. }
  1233. return eaAction;
  1234. }
  1235. TRACE(CACHE,(
  1236. "IPFLTDRV: Have to apply out filters out context is %x\n",
  1237. pOutInterface
  1238. ));
  1239. if((pInCache->pOutContext is pOutInterface)
  1240. &&
  1241. (pInCache->lOutEpoch == pOutInterface->lEpoch))
  1242. {
  1243. //
  1244. // So we matched the out context. if there is an
  1245. // out filter, check if SYN is restricted.
  1246. //
  1247. eaAction = pInCache->eaOutAction;
  1248. TRACE(CACHE,("IPFLTDRV: Paydirt - out context match in InCache entry\n"));
  1249. ReleaseCache(pInCache);
  1250. FiltHit(pInCache->pOutFilter,
  1251. pInCache->pOutContext,
  1252. eaAction,
  1253. pIpHeader,
  1254. pbRestOfPacket,
  1255. uiPacketLength,
  1256. FALSE);
  1257. // InterlockedIncrement(pInCache->pdwOutHitCounter);
  1258. if (bFirstFrag)
  1259. {
  1260. FragCacheUpdate(*puliSrcDstAddr,
  1261. pInInterface,
  1262. pOutInterface,
  1263. dwId,
  1264. eaAction);
  1265. }
  1266. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1267. TRACE(ACTION,(
  1268. "IPFLTDRV: Packet is being %s\n",
  1269. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1270. ));
  1271. RecordTimeOut();
  1272. IncrementForward();
  1273. return eaAction;
  1274. }
  1275. //
  1276. // We need to walk the out interface filters. We dont let go of the in cache though.
  1277. // This doesnt block any reader, only stops the cache entry from being reused
  1278. //
  1279. pOutCache = g_filters.ppOutCache[dwIndex];
  1280. LockCache(pOutCache);
  1281. if(OutCacheMatch(*puliSrcDstAddr,uliProtoSrcDstPort,pOutInterface,pOutCache))
  1282. {
  1283. TRACE(CACHE,("IPFLTDRV: Matched OutCache entry\n"));
  1284. eaAction = pOutCache->eaOutAction;
  1285. FiltHit(pOutCache->pOutFilter,
  1286. pOutCache->pOutContext,
  1287. eaAction,
  1288. pIpHeader,
  1289. pbRestOfPacket,
  1290. uiPacketLength,
  1291. FALSE);
  1292. // InterlockedIncrement(pOutCache->pdwOutHitCounter);
  1293. if(!(dwGlobals & GLOBS_SYNDrop))
  1294. {
  1295. InCacheOutUpdate(pOutInterface,
  1296. eaAction,
  1297. dwIndex,
  1298. pInCache,
  1299. pOutCache->pOutFilter);
  1300. }
  1301. ReleaseCache(pInCache);
  1302. ReleaseCache(pOutCache);
  1303. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1304. if (bFirstFrag)
  1305. {
  1306. FragCacheUpdate(*puliSrcDstAddr,
  1307. pInInterface,
  1308. pOutInterface,
  1309. dwId,
  1310. eaAction);
  1311. }
  1312. TRACE(ACTION,(
  1313. "IPFLTDRV: Packet is being %s\n",
  1314. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1315. ));
  1316. RecordTimeOut();
  1317. IncrementCache2();
  1318. return eaAction;
  1319. }
  1320. ReleaseCache(pOutCache);
  1321. //
  1322. // Didnt match out cache entry, still holding incache, walk out filters
  1323. //
  1324. TRACE(CACHE,("IPFLTDRV: Didnt match OutCache entry\n"));
  1325. TRACE(CACHE,("IPFLTDRV: Walking out filters\n"));
  1326. pf = LookForFilter(pOutInterface,
  1327. puliSrcDstAddr,
  1328. &uliProtoSrcDstPort,
  1329. dwSum,
  1330. 0);
  1331. if(pf)
  1332. {
  1333. //
  1334. // Update the out cache
  1335. //
  1336. eaAction = pOutInterface->eaOutAction ^ 0x00000001;
  1337. FiltHit(pf,
  1338. pOutInterface,
  1339. eaAction,
  1340. pIpHeader,
  1341. pbRestOfPacket,
  1342. uiPacketLength,
  1343. FALSE);
  1344. // InterlockedIncrement(&(pf->dwNumHits));
  1345. if(!(dwGlobals & GLOBS_SYNDrop))
  1346. {
  1347. InCacheOutUpdate(pOutInterface,
  1348. eaAction,
  1349. dwIndex,
  1350. pInCache,
  1351. pf);
  1352. OutCacheUpdate(*puliSrcDstAddr,
  1353. uliProtoSrcDstPort,
  1354. pOutInterface,
  1355. eaAction,
  1356. dwIndex,
  1357. pf);
  1358. }
  1359. ReleaseCache(pInCache);
  1360. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1361. if (bFirstFrag)
  1362. {
  1363. FragCacheUpdate(*puliSrcDstAddr,
  1364. pInInterface,
  1365. pOutInterface,
  1366. dwId,
  1367. eaAction);
  1368. }
  1369. TRACE(ACTION,(
  1370. "IPFLTDRV: Packet is being %s\n",
  1371. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1372. ));
  1373. RecordTimeOut();
  1374. IncrementWalkCache();
  1375. return eaAction;
  1376. }
  1377. TRACE(CACHE,("IPFLTDRV: Didnt match any filters\n"));
  1378. // InterlockedIncrement(&g_dwNumHitsDefaultOut);
  1379. InCacheOutUpdate(pOutInterface,
  1380. pOutInterface->eaOutAction,
  1381. dwIndex,
  1382. pInCache,
  1383. NULL);
  1384. OutCacheUpdate(*puliSrcDstAddr,
  1385. uliProtoSrcDstPort,
  1386. pOutInterface,
  1387. pOutInterface->eaOutAction,
  1388. dwIndex,
  1389. NULL);
  1390. eaAction = pOutInterface->eaOutAction;
  1391. ReleaseCache(pInCache);
  1392. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1393. if (bFirstFrag)
  1394. {
  1395. FragCacheUpdate(*puliSrcDstAddr,
  1396. pInInterface,
  1397. pOutInterface,
  1398. dwId,
  1399. eaAction);
  1400. }
  1401. TRACE(ACTION,(
  1402. "IPFLTDRV: Packet is being %s\n",
  1403. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1404. ));
  1405. RecordTimeOut();
  1406. IncrementWalkCache();
  1407. return eaAction;
  1408. }
  1409. //
  1410. // We couldnt get into the in cache, so we walk in filters, try outcache
  1411. // probe, walk out filters, update out cache, update in cache, return
  1412. // This is the worst case scenario
  1413. //
  1414. ReleaseCache(pInCache);
  1415. TRACE(CACHE,("IPFLTDRV: Didnt match cache entry\n"));
  1416. pfHit = NULL;
  1417. //
  1418. // eaAction is the default action. If we match a filter, we flip the action
  1419. // so that at the end of the loop, eaAction describes the action to be taken on the
  1420. // packet
  1421. //
  1422. eaAction = pInInterface->eaInAction;
  1423. TRACE(CACHE,("IPFLTDRV: Walking in filters\n"));
  1424. pf = LookForFilter(pInInterface,
  1425. puliSrcDstAddr,
  1426. &uliProtoSrcDstPort,
  1427. dwSum,
  1428. FILTER_FLAGS_INFILTER);
  1429. if(pf)
  1430. {
  1431. eaAction = pInInterface->eaInAction ^ 0x00000001;
  1432. pfHit = pf;
  1433. }
  1434. if(eaAction == DROP)
  1435. {
  1436. if(pInInterface->CountCtl.lInUse)
  1437. {
  1438. //
  1439. // it's a drop and this interface is allowing all
  1440. // TCP control frames. See if this is a TCP control
  1441. // frame.
  1442. if(CheckForTcpCtl(pInInterface,
  1443. PROTOCOLPART(uliProtoSrcDstPort.LowPart),
  1444. pIpHeader,
  1445. pbRestOfPacket,
  1446. uiPacketLength))
  1447. {
  1448. pf = 0;
  1449. eaAction = FORWARD;
  1450. dwGlobals |= GLOBS_SYNDrop;
  1451. }
  1452. }
  1453. }
  1454. //
  1455. // if not DROP check for spoofing.
  1456. //
  1457. if(eaAction == FORWARD)
  1458. {
  1459. if(pInInterface->dwIpIndex != UNKNOWN_IP_INDEX)
  1460. {
  1461. if(pInInterface->CountSpoof.lInUse)
  1462. {
  1463. IPAddr SrcAddr = puliSrcDstAddr->LowPart;
  1464. //
  1465. // we need to check these addresses
  1466. //
  1467. if(!CheckAddress(SrcAddr, pInInterface->dwIpIndex))
  1468. {
  1469. eaAction = DROP;
  1470. }
  1471. }
  1472. if(pInInterface->CountStrongHost.lInUse)
  1473. {
  1474. IPAddr DstAddr = puliSrcDstAddr->HighPart;
  1475. if(!MatchLocalLook(DstAddr, pInInterface->dwIpIndex))
  1476. {
  1477. eaAction = DROP;
  1478. }
  1479. }
  1480. }
  1481. if(eaAction == DROP)
  1482. {
  1483. //
  1484. // Spoofed address. Log it and drop this
  1485. //
  1486. //
  1487. RegisterSpoof(pInInterface,
  1488. pIpHeader,
  1489. pbRestOfPacket,
  1490. uiPacketLength);
  1491. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1492. eaAction = DROP;
  1493. if (bFirstFrag)
  1494. {
  1495. FragCacheUpdate(*puliSrcDstAddr,
  1496. pInInterface,
  1497. pOutInterface,
  1498. dwId,
  1499. eaAction);
  1500. }
  1501. return(eaAction);
  1502. }
  1503. //
  1504. // finally, if not DROP, check for SYN and count it
  1505. //
  1506. if((PROTOCOLPART(uliProtoSrcDstPort.LowPart) == 6)
  1507. &&
  1508. (dwGlobals & GLOBS_TCPGood)
  1509. &&
  1510. ((((PTCPHeader)pbRest)->tcp_flags &
  1511. (TCP_FLAG_SYN | TCP_FLAG_ACK)) == TCP_FLAG_SYN) )
  1512. {
  1513. pInInterface->liSYNCount.QuadPart++;
  1514. }
  1515. }
  1516. FiltHit(pfHit,
  1517. pInInterface,
  1518. eaAction,
  1519. pIpHeader,
  1520. pbRestOfPacket,
  1521. uiPacketLength,
  1522. TRUE);
  1523. // InterlockedIncrement(pdwHit);
  1524. if((eaAction is DROP) or
  1525. (pOutInterface is NULL))
  1526. {
  1527. //
  1528. // We dont need to go any further if:
  1529. // (i) If the action says we drop
  1530. // (ii) If the out interface is NULL - because then this is the final action
  1531. //
  1532. if(!(dwGlobals & GLOBS_SYNDrop))
  1533. {
  1534. //
  1535. // if this was dropped because of a SYN rejection
  1536. // don't cache the entry. This means other SYNs
  1537. // from this guy will cause a walk, but it also
  1538. // means legitimate traffic from him will be
  1539. // allowed. This also applies if it was forwarded
  1540. // because of an "allow control messages" filter.
  1541. //
  1542. InCacheUpdate(*puliSrcDstAddr,
  1543. uliProtoSrcDstPort,
  1544. pInInterface,
  1545. eaAction, // Dont need full update? BUG?
  1546. dwIndex,
  1547. pfHit);
  1548. }
  1549. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1550. if (bFirstFrag)
  1551. {
  1552. FragCacheUpdate(*puliSrcDstAddr,
  1553. pInInterface,
  1554. pOutInterface,
  1555. dwId,
  1556. eaAction);
  1557. }
  1558. TRACE(ACTION,(
  1559. "IPFLTDRV: Packet is being %s\n",
  1560. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1561. ));
  1562. RecordTimeOut();
  1563. IncrementWalk1();
  1564. return eaAction;
  1565. }
  1566. //
  1567. // If we have come till here, means we passed the in filter stage
  1568. //
  1569. TRACE(CACHE,("IPFLTDRV: Passed the in filter stage\n"));
  1570. pOutCache = g_filters.ppOutCache[dwIndex];
  1571. LockCache(pOutCache);
  1572. if(OutCacheMatch(*puliSrcDstAddr,uliProtoSrcDstPort,pOutInterface,pOutCache))
  1573. {
  1574. TRACE(CACHE,("IPFLTDRV: nMatched OutCache entry\n"));
  1575. eaAction = pOutCache->eaOutAction;
  1576. FiltHit(pOutCache->pOutFilter,
  1577. pOutCache->pOutContext,
  1578. eaAction,
  1579. pIpHeader,
  1580. pbRestOfPacket,
  1581. uiPacketLength,
  1582. FALSE);
  1583. // InterlockedIncrement(pOutCache->pdwOutHitCounter);
  1584. if(!(dwGlobals & GLOBS_SYNDrop))
  1585. {
  1586. InCacheFullUpdate(*puliSrcDstAddr,
  1587. uliProtoSrcDstPort,
  1588. pInInterface,
  1589. FORWARD, // If we are here, then the in action was forward
  1590. pOutInterface,
  1591. eaAction,
  1592. dwIndex,
  1593. pf,
  1594. pOutCache->pOutFilter);
  1595. }
  1596. ReleaseCache(pOutCache);
  1597. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1598. if (bFirstFrag)
  1599. {
  1600. FragCacheUpdate(*puliSrcDstAddr,
  1601. pInInterface,
  1602. pOutInterface,
  1603. dwId,
  1604. eaAction);
  1605. }
  1606. TRACE(ACTION,(
  1607. "IPFLTDRV: Packet is being %s\n",
  1608. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1609. ));
  1610. RecordTimeOut();
  1611. IncrementWalkCache();
  1612. return eaAction;
  1613. }
  1614. ReleaseCache(pOutCache);
  1615. TRACE(CACHE,("IPFLTDRV: Didnt match OutCache entry\n"));
  1616. TRACE(CACHE,("IPFLTDRV: Walking out filters\n"));
  1617. pf1 = LookForFilter(pOutInterface,
  1618. puliSrcDstAddr,
  1619. &uliProtoSrcDstPort,
  1620. dwSum,
  1621. 0);
  1622. if(pf1)
  1623. {
  1624. //
  1625. // Update the out cache
  1626. //
  1627. eaAction = pOutInterface->eaOutAction ^ 0x00000001;
  1628. FiltHit(pf1,
  1629. pOutInterface,
  1630. eaAction,
  1631. pIpHeader,
  1632. pbRestOfPacket,
  1633. uiPacketLength,
  1634. FALSE);
  1635. // InterlockedIncrement(&(pf->dwNumHits));
  1636. if(!(dwGlobals & GLOBS_SYNDrop))
  1637. {
  1638. InCacheFullUpdate(*puliSrcDstAddr,
  1639. uliProtoSrcDstPort,
  1640. pInInterface,
  1641. FORWARD,
  1642. pOutInterface,
  1643. eaAction,
  1644. dwIndex,
  1645. pf,
  1646. pf1);
  1647. OutCacheUpdate(*puliSrcDstAddr,
  1648. uliProtoSrcDstPort,
  1649. pOutInterface,
  1650. eaAction,
  1651. dwIndex,
  1652. pf1);
  1653. }
  1654. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1655. if (bFirstFrag)
  1656. {
  1657. FragCacheUpdate(*puliSrcDstAddr,
  1658. pInInterface,
  1659. pOutInterface,
  1660. dwId,
  1661. eaAction);
  1662. }
  1663. TRACE(ACTION,(
  1664. "IPFLTDRV: Packet is being %s\n",
  1665. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1666. ));
  1667. RecordTimeOut();
  1668. IncrementWalk2();
  1669. return eaAction;
  1670. }
  1671. TRACE(CACHE,("IPFLTDRV: Didnt match any filters\n"));
  1672. // InterlockedIncrement(&g_dwNumHitsDefaultOut);
  1673. InCacheFullUpdate(*puliSrcDstAddr,
  1674. uliProtoSrcDstPort,
  1675. pInInterface,
  1676. FORWARD,
  1677. pOutInterface,
  1678. pOutInterface->eaOutAction,
  1679. dwIndex,
  1680. pf,
  1681. NULL);
  1682. OutCacheUpdate(*puliSrcDstAddr,
  1683. uliProtoSrcDstPort,
  1684. pOutInterface,
  1685. pOutInterface->eaOutAction,
  1686. dwIndex,
  1687. NULL);
  1688. eaAction = pOutInterface->eaOutAction;
  1689. ReleaseReadLock(&g_filters.ifListLock,&LockState);
  1690. if (bFirstFrag)
  1691. {
  1692. FragCacheUpdate(*puliSrcDstAddr,
  1693. pInInterface,
  1694. pOutInterface,
  1695. dwId,
  1696. eaAction);
  1697. }
  1698. TRACE(ACTION,(
  1699. "Packet is being %s\n",
  1700. (eaAction is DROP)?"DROPPED":"FORWARDED"
  1701. ));
  1702. RecordTimeOut();
  1703. IncrementWalk2();
  1704. return eaAction;
  1705. }
  1706. #endif // BASE_PERF
  1707. }
  1708. //__inline
  1709. VOID
  1710. FiltHit(PFILTER pf,
  1711. PFILTER_INTERFACE pIf,
  1712. FORWARD_ACTION Action,
  1713. UNALIGNED IPHeader *pIpHeader,
  1714. BYTE *pbRestOfPacket,
  1715. UINT uiPacketLength,
  1716. BOOL fIn)
  1717. /*++
  1718. Routine Description:
  1719. Called whenever a filter action happens. If pf is NULL, then the
  1720. action is the default interface action. If pf is non-NULL, then
  1721. the action is the reverse of the interface action.
  1722. pf the filter or NULL
  1723. pIf the filter interface
  1724. Action The computed action
  1725. fIn TRUE if this is an in action, FALSE if an out action
  1726. --*/
  1727. {
  1728. DWORD dwFilterRule;
  1729. BOOL fLogAll;
  1730. if(pf)
  1731. {
  1732. InterlockedIncrement(&pf->Count.lCount);
  1733. dwFilterRule = pf->dwFilterRule;
  1734. fLogAll = (pf->dwFlags & FILTER_FLAGS_LOGALL) != 0;
  1735. }
  1736. else
  1737. {
  1738. dwFilterRule = 0;
  1739. fLogAll = FALSE;
  1740. }
  1741. if(fLogAll || (Action == DROP))
  1742. {
  1743. LogFiltHit(Action,
  1744. fIn,
  1745. dwFilterRule,
  1746. pIf,
  1747. pIpHeader,
  1748. pbRestOfPacket,
  1749. uiPacketLength);
  1750. }
  1751. return;
  1752. }
  1753. VOID
  1754. LogFiltHit(
  1755. FORWARD_ACTION Action,
  1756. BOOL fIn,
  1757. DWORD dwFilterRule,
  1758. PFILTER_INTERFACE pIf,
  1759. UNALIGNED IPHeader *pIpHeader,
  1760. BYTE *pbRestOfPacket,
  1761. UINT uiPacketLength)
  1762. /*++
  1763. Routine Description:
  1764. Worker to do the logging on a filter hit. This is a separate
  1765. routine so that FiltHit and be an inline for performance reasons.
  1766. --*/
  1767. {
  1768. BOOL fHit = FALSE;
  1769. if(fIn)
  1770. {
  1771. InterlockedIncrement(&pIf->lTotalInDrops);
  1772. }
  1773. else
  1774. {
  1775. InterlockedIncrement(&pIf->lTotalOutDrops);
  1776. }
  1777. if((pIf->lTotalInDrops + pIf->lTotalOutDrops) ==
  1778. (LONG)pIf->dwDropThreshold)
  1779. {
  1780. fHit = TRUE;
  1781. }
  1782. //
  1783. // If a log exists, do logging and event handling
  1784. //
  1785. if(pIf->pLog
  1786. &&
  1787. pIf->pLog->pUserAddress)
  1788. {
  1789. //
  1790. // Try to log this data
  1791. //
  1792. LogData(
  1793. PFE_FILTER,
  1794. pIf,
  1795. dwFilterRule,
  1796. pIpHeader,
  1797. pbRestOfPacket,
  1798. uiPacketLength);
  1799. if(fHit)
  1800. {
  1801. SignalLogThreshold(pIf->pLog);
  1802. }
  1803. }
  1804. if(Action == DROP)
  1805. {
  1806. //
  1807. // it's a dropped frame. See if we need to produce
  1808. // a response. If this is an IPSEC frame we
  1809. // don't do the right thing since we really need
  1810. // to be looking at the upper layer protocol.
  1811. //
  1812. switch(pIpHeader->iph_protocol)
  1813. {
  1814. case 6: // TCP
  1815. SendTCPReset(pIpHeader, pbRestOfPacket, uiPacketLength);
  1816. break;
  1817. case PROT_IPSECAH:
  1818. case PROT_IPSECESP:
  1819. case 17: // UDP
  1820. SendUDPUnreachable(pIpHeader, pbRestOfPacket, uiPacketLength);
  1821. break;
  1822. }
  1823. }
  1824. }
  1825. VOID
  1826. RegisterFragAttack(
  1827. PFILTER_INTERFACE pIf,
  1828. UNALIGNED IPHeader *pIpHeader,
  1829. BYTE *pbRestOfPacket,
  1830. UINT uiSize)
  1831. {
  1832. if(pIf->CountNoFrag.lInUse == 0)
  1833. {
  1834. InterlockedIncrement(&pIf->CountSynOrFrag.lCount);
  1835. }
  1836. else
  1837. {
  1838. InterlockedIncrement(&pIf->CountNoFrag.lCount);
  1839. }
  1840. if(pIf->pLog
  1841. &&
  1842. pIf->pLog->pUserAddress)
  1843. {
  1844. //
  1845. // logging is enabled.
  1846. //
  1847. LogData(
  1848. PFE_SYNORFRAG,
  1849. pIf,
  1850. 0,
  1851. pIpHeader,
  1852. pbRestOfPacket,
  1853. uiSize);
  1854. }
  1855. }
  1856. VOID
  1857. RegisterFullDeny(
  1858. PFILTER_INTERFACE pIf,
  1859. UNALIGNED IPHeader *pIpHeader,
  1860. BYTE *pbRestOfPacket,
  1861. UINT uiSize)
  1862. {
  1863. InterlockedIncrement(&pIf->CountFullDeny.lCount);
  1864. if(pIf->pLog
  1865. &&
  1866. pIf->pLog->pUserAddress)
  1867. {
  1868. //
  1869. // logging is enabled.
  1870. //
  1871. LogData(
  1872. PFE_FULLDENY,
  1873. pIf,
  1874. 0,
  1875. pIpHeader,
  1876. pbRestOfPacket,
  1877. uiSize);
  1878. }
  1879. }
  1880. VOID
  1881. RegisterSpoof( PFILTER_INTERFACE pIf,
  1882. UNALIGNED IPHeader *pIpHeader,
  1883. BYTE *pbRestOfPacket,
  1884. UINT uiSize)
  1885. /*++
  1886. Routine Description:
  1887. Called when a spoofed address is encountered.
  1888. --*/
  1889. {
  1890. InterlockedIncrement(&pIf->CountSpoof.lCount);
  1891. //
  1892. // See if logging is enabled. If so, log some of this frame.
  1893. //
  1894. //
  1895. if(pIf->pLog
  1896. &&
  1897. pIf->pLog->pUserAddress)
  1898. {
  1899. //
  1900. // logging is enabled.
  1901. //
  1902. LogData(
  1903. PFE_SPOOF,
  1904. pIf,
  1905. 0,
  1906. pIpHeader,
  1907. pbRestOfPacket,
  1908. uiSize);
  1909. }
  1910. }
  1911. VOID
  1912. RegisterUnusedICMP(PFILTER_INTERFACE pIf,
  1913. UNALIGNED IPHeader *pIpHeader,
  1914. BYTE *pbRestOfPacket,
  1915. UINT uiSize)
  1916. /*++
  1917. Routine Description:
  1918. Called whenever an ICMP "unreachable" is sent from this machine
  1919. on an interface listening for such things. It increments use
  1920. counts and if any threshold is exceeded, signals the log event
  1921. --*/
  1922. {
  1923. InterlockedIncrement(&pIf->CountUnused.lCount);
  1924. //
  1925. // See if logging is enabled. If so, log some of this frame.
  1926. //
  1927. //
  1928. if(pIf->pLog
  1929. &&
  1930. pIf->pLog->pUserAddress)
  1931. {
  1932. //
  1933. // logging is enabled.
  1934. //
  1935. LogData(
  1936. PFE_UNUSEDPORT,
  1937. pIf,
  1938. 0,
  1939. pIpHeader,
  1940. pbRestOfPacket,
  1941. uiSize);
  1942. }
  1943. }
  1944. VOID
  1945. LogData(
  1946. PFETYPE pfeType,
  1947. PFILTER_INTERFACE pIf,
  1948. DWORD dwFilterRule,
  1949. UNALIGNED IPHeader *pIpHeader,
  1950. BYTE *pbRestOfPacket,
  1951. UINT uiPacketLength)
  1952. /*++
  1953. Routine Description:
  1954. Log the error. Copy the header and as much of the other data
  1955. into the log as makes sense. If the log threshold is exceeded,
  1956. or if the available space is running low, hit the event.
  1957. The caller should not call this is no log is in force for the
  1958. interface. The filter write lock is held.
  1959. --*/
  1960. {
  1961. DWORD dwSpaceLeft, dwSpaceToUse, dwExtra;
  1962. PPFLOGINTERFACE pLog = pIf->pLog;
  1963. PPFLOGGEDFRAME pFrame;
  1964. KIRQL kIrql;
  1965. LONG lIpLen = (LONG)((DWORD)(pIpHeader->iph_verlen & IPHDRLEN) << IPHDRSFT);
  1966. ASSERT(pLog);
  1967. //
  1968. // compute options length
  1969. //
  1970. lIpLen -= (LONG)sizeof(IPHeader);
  1971. if(lIpLen < 0)
  1972. {
  1973. lIpLen = 0;
  1974. }
  1975. //
  1976. // if can't do any logging, no need to proceed with
  1977. // the computation
  1978. //
  1979. kIrql = LockLog(pLog);
  1980. pIf->liLoggedFrames.QuadPart++;
  1981. if(pLog->dwFlags & (LOG_OUTMEM | LOG_BADMEM))
  1982. {
  1983. pLog->dwLostEntries++;
  1984. pIf->dwLostFrames++;
  1985. UnLockLogDpc(pLog);
  1986. return;
  1987. }
  1988. dwSpaceToUse = sizeof(PFLOGGEDFRAME) - 1;
  1989. dwSpaceToUse += (DWORD)lIpLen;
  1990. switch(pfeType)
  1991. {
  1992. default:
  1993. case PFE_FILTER:
  1994. dwExtra = (uiPacketLength < LOG_DATA_SIZE ?
  1995. uiPacketLength : LOG_DATA_SIZE);
  1996. break;
  1997. case PFE_UNUSEDPORT:
  1998. dwExtra = uiPacketLength;
  1999. break;
  2000. }
  2001. dwSpaceToUse += dwExtra;
  2002. //
  2003. // align on a quadword boundary
  2004. //
  2005. dwSpaceToUse = ROUND_UP_COUNT(dwSpaceToUse, ALIGN_WORST);
  2006. dwSpaceLeft = pLog->dwMapCount - pLog->dwMapOffset;
  2007. if(dwSpaceLeft < dwSpaceToUse)
  2008. {
  2009. pLog->dwLostEntries++;
  2010. AdvanceLog(pLog);
  2011. UnLockLogDpc(pLog);
  2012. if(!(pLog->dwFlags & (LOG_OUTMEM | LOG_BADMEM | LOG_CANTMAP)))
  2013. {
  2014. TRACE(LOGGER,("IPFLTDRV: Could not log data\n"));
  2015. }
  2016. return;
  2017. }
  2018. //
  2019. // there's room. So log it.
  2020. //
  2021. pLog->dwLoggedEntries++;
  2022. if(pLog->dwLoggedEntries == pLog->dwEntriesThreshold)
  2023. {
  2024. SignalLogThreshold(pLog);
  2025. }
  2026. pFrame = (PPFLOGGEDFRAME)pLog->pCurrentMapPointer;
  2027. KeQuerySystemTime(&pFrame->Timestamp);
  2028. pFrame->pfeTypeOfFrame = pfeType;
  2029. pFrame->wSizeOfAdditionalData = (WORD)dwExtra;
  2030. pFrame->wSizeOfIpHeader = (WORD)(sizeof(IPHeader) + lIpLen);
  2031. pFrame->dwRtrMgrIndex = pIf->dwRtrMgrIndex;
  2032. pFrame->dwFilterRule = dwFilterRule;
  2033. pFrame->dwIPIndex = pIf->dwIpIndex;
  2034. RtlCopyMemory(&pFrame->IpHeader, pIpHeader, sizeof(IPHeader) + lIpLen);
  2035. RtlCopyMemory(&pFrame->bData + lIpLen,
  2036. pbRestOfPacket,
  2037. dwExtra);
  2038. pFrame->dwTotalSizeUsed = dwSpaceToUse;
  2039. pLog->pCurrentMapPointer += dwSpaceToUse;
  2040. pLog->dwMapOffset += dwSpaceToUse;
  2041. dwSpaceLeft -= dwSpaceToUse;
  2042. if(dwSpaceLeft < pLog->dwMapWindowSizeFloor)
  2043. {
  2044. //
  2045. // running low
  2046. //
  2047. AdvanceLog(pLog);
  2048. }
  2049. if(dwSpaceLeft < pLog->dwSignalThreshold)
  2050. {
  2051. SignalLogThreshold(pLog);
  2052. }
  2053. UnLockLogDpc(pLog);
  2054. }
  2055. VOID
  2056. ClearCacheEntry(PFILTER pFilt, PFILTER_INTERFACE pIf)
  2057. /*++
  2058. Routine Description:
  2059. Called when a filter is deleted. Compute where the matching
  2060. packet would go and clear that cache entry.
  2061. --*/
  2062. {
  2063. DWORD dwIndex;
  2064. dwIndex = pFilt->SRC_ADDR +
  2065. pFilt->DEST_ADDR +
  2066. pFilt->DEST_ADDR +
  2067. PROTOCOLPART(pFilt->uliProtoSrcDstPort.LowPart) +
  2068. pFilt->uliProtoSrcDstPort.HighPart;
  2069. dwIndex %= g_dwCacheSize;
  2070. ClearInCacheEntry(g_filters.ppInCache[dwIndex]);
  2071. ClearOutCacheEntry(g_filters.ppOutCache[dwIndex]);
  2072. }
  2073. VOID
  2074. ClearAnyCacheEntry(PFILTER pFilt, PFILTER_INTERFACE pIf)
  2075. /*++
  2076. Routine Description:
  2077. Called when a wild card filter is deleted. It scans the caches looking
  2078. for any cache entries pointing to this filter. The Write lock should be
  2079. held
  2080. --*/
  2081. {
  2082. DWORD dwX;
  2083. //
  2084. // if an input filter, scan the infilter cache only
  2085. //
  2086. if((pFilt->dwFlags & FILTER_FLAGS_INFILTER))
  2087. {
  2088. for(dwX = 0; dwX < g_dwCacheSize; dwX++)
  2089. {
  2090. if(g_filters.ppInCache[dwX]->pInFilter == pFilt)
  2091. {
  2092. ClearInCacheEntry(g_filters.ppInCache[dwX]);
  2093. }
  2094. }
  2095. }
  2096. else
  2097. {
  2098. //
  2099. // output filters need scan both cachees.
  2100. //
  2101. for(dwX = 0; dwX < g_dwCacheSize; dwX++)
  2102. {
  2103. if(g_filters.ppOutCache[dwX]->pOutFilter == pFilt)
  2104. {
  2105. //
  2106. // found one.
  2107. //
  2108. ClearOutCacheEntry(g_filters.ppOutCache[dwX]);
  2109. }
  2110. //
  2111. // and checkout the cached output filter in the
  2112. // corresponding InCache
  2113. //
  2114. if(g_filters.ppInCache[dwX]->pOutFilter == pFilt)
  2115. {
  2116. ClearInCacheEntry(g_filters.ppInCache[dwX]);
  2117. }
  2118. }
  2119. }
  2120. }
  2121. BOOL
  2122. CheckRedirectAddress(UNALIGNED IPHeader *IPHead, DWORD dwInterface)
  2123. /*++
  2124. Routine Description:
  2125. Called to validate a redirect message.
  2126. Arguments:
  2127. IpHead -- the redirect IP header
  2128. dwInterface -- the interface index this came arrived on
  2129. This routine is disabled for now because we don't know
  2130. how to validate redirect messages.
  2131. --*/
  2132. {
  2133. #if 0
  2134. IPRouteEntry iproute;
  2135. IPRouteLookupData lup;
  2136. PFILTER_INTERFACE pIf;
  2137. PLIST_ENTRY pl;
  2138. lup.DestAdd = ipAddr;
  2139. lup.SrcAdd = 0;
  2140. lup.Version = 0;
  2141. LookupRoute(&lup, &iproute);
  2142. if(iproute.ire_index == dwInterface)
  2143. {
  2144. return(TRUE);
  2145. }
  2146. //
  2147. // not this interface. Look through all of the filtered interfaces
  2148. // for a match. That is, allow the redirect to any other
  2149. // filtered interface but no others.
  2150. //
  2151. for(pl = g_filters.leIfListHead.Flink;
  2152. pl != &g_filters.leIfListHead;
  2153. pl = pl->Flink)
  2154. {
  2155. pIf = CONTAINING_RECORD(pl, FILTER_INTERFACE, leIfLink);
  2156. if(iproute.ire_index == pIf->dwIpIndex)
  2157. {
  2158. return(TRUE);
  2159. }
  2160. }
  2161. return(FALSE);
  2162. #else
  2163. return(TRUE);
  2164. #endif
  2165. }
  2166. BOOL
  2167. CheckAddress(IPAddr ipAddr, DWORD dwInterfaceId)
  2168. /*++
  2169. Routine Description:
  2170. Called to check that the given address belongs to the given interface
  2171. --*/
  2172. {
  2173. #if LOOKUPROUTE
  2174. IPRouteEntry iproute;
  2175. IPRouteLookupData lup;
  2176. lup.DestAdd = ipAddr;
  2177. lup.SrcAdd = 0;
  2178. lup.Version = 0;
  2179. LookupRoute(&lup, &iproute);
  2180. if(iproute.ire_index == dwInterfaceId)
  2181. {
  2182. return(TRUE);
  2183. }
  2184. return(FALSE);
  2185. #else
  2186. return(TRUE);
  2187. #endif
  2188. }
  2189. NTSTATUS
  2190. CheckFilterAddress(DWORD dwAdd, PFILTER_INTERFACE pIf)
  2191. {
  2192. NTSTATUS Status;
  2193. LOCK_STATE LockState;
  2194. AcquireReadLock(&g_filters.ifListLock, &LockState);
  2195. if(dwAdd && (pIf->dwIpIndex != UNKNOWN_IP_INDEX))
  2196. {
  2197. if(!CheckAddress(dwAdd, pIf->dwIpIndex))
  2198. {
  2199. Status = STATUS_INVALID_ADDRESS;
  2200. }
  2201. else
  2202. {
  2203. Status = STATUS_SUCCESS;
  2204. }
  2205. }
  2206. else
  2207. {
  2208. Status = STATUS_SUCCESS;
  2209. }
  2210. ReleaseReadLock(&g_filters.ifListLock, &LockState);
  2211. return(Status);
  2212. }
  2213. #if DOFRAGCHECKING
  2214. PFILTER
  2215. CheckFragAllowed(
  2216. PFILTER_INTERFACE pIf,
  2217. UNALIGNED IPHeader *pIp)
  2218. /*++
  2219. Routine Description:
  2220. Called when a fragment is received. Checks whether the
  2221. filters might allow it. Returns a filter that applies
  2222. --*/
  2223. {
  2224. PFILTER pTemp;
  2225. UNALIGNED PULARGE_INTEGER puliSrcDstAddr;
  2226. ULARGE_INTEGER uliProtoSrcDstPort;
  2227. ULARGE_INTEGER uliAddr;
  2228. ULARGE_INTEGER uliPort;
  2229. ULARGE_INTEGER uliAuxMask;
  2230. PLIST_ENTRY List;
  2231. PLIST_ENTRY pList;
  2232. if(pIf)
  2233. {
  2234. pList = &pIf->FragLists[GetFragIndex((DWORD)pIp->iph_protocol)];
  2235. if(!IsListEmpty(pList))
  2236. {
  2237. puliSrcDstAddr = (UNALIGNED PULARGE_INTEGER)(&(pIp->iph_src));
  2238. uliProtoSrcDstPort.LowPart =
  2239. MAKELONG(MAKEWORD(pIp->iph_protocol,0x00),0x0000);
  2240. //
  2241. // always compare the protocol. Don't compare the must-be-connected.
  2242. //
  2243. uliAuxMask.LowPart = MAKELONG(MAKEWORD(0xff, 0), 0x0000);
  2244. if(pIf->eaInAction == FORWARD)
  2245. {
  2246. uliAuxMask.HighPart = 0xffffffff;
  2247. }
  2248. else
  2249. {
  2250. uliAuxMask.HighPart = 0;
  2251. }
  2252. //
  2253. // scan each input filter looking for a "match". Note that a match
  2254. // in this case might be approximate. What we are looking for
  2255. // is a match on the addresses and the protocol alone. Can't do
  2256. // the ports 'cause we don't have them.
  2257. //
  2258. for(List = pList->Flink;
  2259. List != pList;
  2260. List = List->Flink)
  2261. {
  2262. pTemp = CONTAINING_RECORD(List, FILTER, leFragList);
  2263. //
  2264. // only look at input filters
  2265. //
  2266. if(pTemp->dwFlags & FILTER_FLAGS_INFILTER)
  2267. {
  2268. uliAddr.QuadPart = (*puliSrcDstAddr).QuadPart & pTemp->uliSrcDstMask.QuadPart;
  2269. uliPort.QuadPart = uliProtoSrcDstPort.QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2270. if(uliAddr.QuadPart == pTemp->uliSrcDstAddr.QuadPart)
  2271. {
  2272. ULARGE_INTEGER uliAux;
  2273. //
  2274. // the addresses match. Now for the tricky part. What
  2275. // we do is mask off the parts of the filter description
  2276. // that don't apply. If this is a DROP filter, then
  2277. // mask nothing since only a filter that allows any
  2278. // port can match. If it is a FORWARD filter, then
  2279. // mask off the ports.
  2280. //
  2281. uliAux.QuadPart = pTemp->uliProtoSrcDstPort.QuadPart & uliAuxMask.QuadPart;
  2282. if(uliAux.QuadPart == uliPort.QuadPart)
  2283. {
  2284. return(pTemp);
  2285. }
  2286. }
  2287. }
  2288. }
  2289. }
  2290. }
  2291. return(NULL);
  2292. }
  2293. #endif // DOFRAGCHECKING
  2294. PFILTER
  2295. LookForFilter(PFILTER_INTERFACE pIf,
  2296. ULARGE_INTEGER UNALIGNED * puliSrcDstAddr,
  2297. PULARGE_INTEGER puliProtoSrcDstPort,
  2298. DWORD dwSum,
  2299. DWORD dwFlags)
  2300. /*++
  2301. Routine Description
  2302. Look for a filter on an interface. The type is encoded in the flags
  2303. --*/
  2304. {
  2305. PFILTER pTemp;
  2306. ULARGE_INTEGER uliAddr;
  2307. ULARGE_INTEGER uliPort;
  2308. PLIST_ENTRY List, pList;
  2309. if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
  2310. {
  2311. //
  2312. // an old interface. Do it the hard way.
  2313. //
  2314. if(dwFlags & FILTER_FLAGS_INFILTER)
  2315. {
  2316. pList = &pIf->pleInFilterSet;
  2317. }
  2318. else
  2319. {
  2320. pList = &pIf->pleOutFilterSet;
  2321. }
  2322. for(List = pList->Flink;
  2323. List != pList;
  2324. List = List->Flink)
  2325. {
  2326. pTemp = CONTAINING_RECORD(List, FILTER, pleFilters);
  2327. uliAddr.QuadPart = (*puliSrcDstAddr).QuadPart & pTemp->uliSrcDstMask.QuadPart;
  2328. uliPort.QuadPart = (*puliProtoSrcDstPort).QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2329. if(GenericFilterMatch(uliAddr,uliPort,pTemp))
  2330. {
  2331. return(pTemp);
  2332. }
  2333. }
  2334. return(NULL);
  2335. }
  2336. //
  2337. // a new style interface. First look for a specific filter
  2338. // match.
  2339. //
  2340. {
  2341. dwSum %= g_dwHashLists;
  2342. for(List = pIf->HashList[dwSum].Flink;
  2343. List != &pIf->HashList[dwSum];
  2344. List = List->Flink)
  2345. {
  2346. pTemp = CONTAINING_RECORD(List, FILTER, pleHashList);
  2347. if(dwFlags == (pTemp->dwFlags & FILTER_FLAGS_INFILTER))
  2348. {
  2349. //
  2350. // if any fields are wild, don't bother on this pass.
  2351. //
  2352. if(ANYWILDFILTER(pTemp))
  2353. {
  2354. break;
  2355. }
  2356. uliPort.QuadPart = (*puliProtoSrcDstPort).QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2357. if(OutFilterMatch(*puliSrcDstAddr, uliPort, pTemp))
  2358. {
  2359. return(pTemp);
  2360. }
  2361. }
  2362. }
  2363. }
  2364. //
  2365. // not a specific filter match. Try a wild card with full-specified
  2366. // local information. Such filters are also hashed.
  2367. //
  2368. if(pIf->dwWilds)
  2369. {
  2370. //
  2371. // got some.
  2372. //
  2373. if(dwFlags & FILTER_FLAGS_INFILTER)
  2374. {
  2375. //
  2376. // an input frame. Compute hash on the dest
  2377. // params
  2378. dwSum = puliSrcDstAddr->HighPart +
  2379. puliSrcDstAddr->HighPart +
  2380. PROTOCOLPART(puliProtoSrcDstPort->LowPart) +
  2381. HIWORD(puliProtoSrcDstPort->HighPart);
  2382. }
  2383. else
  2384. {
  2385. //
  2386. // an output frame. Compute the hash on the source
  2387. // parameters
  2388. //
  2389. dwSum = puliSrcDstAddr->LowPart +
  2390. PROTOCOLPART(puliProtoSrcDstPort->LowPart) +
  2391. LOWORD(puliProtoSrcDstPort->HighPart);
  2392. }
  2393. dwSum %= g_dwHashLists;
  2394. for(List = pIf->HashList[dwSum].Flink;
  2395. List != &pIf->HashList[dwSum];
  2396. List = List->Flink)
  2397. {
  2398. pTemp = CONTAINING_RECORD(List, FILTER, pleHashList);
  2399. if(dwFlags == (pTemp->dwFlags & FILTER_FLAGS_INFILTER))
  2400. {
  2401. uliAddr.QuadPart = (*puliSrcDstAddr).QuadPart & pTemp->uliSrcDstMask.QuadPart;
  2402. uliPort.QuadPart = (*puliProtoSrcDstPort).QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2403. if(GenericFilterMatch(uliAddr,uliPort,pTemp))
  2404. {
  2405. return(pTemp);
  2406. }
  2407. }
  2408. }
  2409. }
  2410. //
  2411. // didn't find it on the hash list. Search the default list for
  2412. // really bizarre filters
  2413. //
  2414. if(dwFlags & FILTER_FLAGS_INFILTER)
  2415. {
  2416. dwSum = g_dwHashLists;
  2417. }
  2418. else
  2419. {
  2420. dwSum = g_dwHashLists + 1;
  2421. }
  2422. for(List = pIf->HashList[dwSum].Flink;
  2423. List != &pIf->HashList[dwSum];
  2424. List = List->Flink)
  2425. {
  2426. pTemp = CONTAINING_RECORD(List, FILTER, pleHashList);
  2427. // if(dwFlags == (pTemp->dwFlags & FILTER_FLAGS_INFILTER))
  2428. {
  2429. uliAddr.QuadPart = (*puliSrcDstAddr).QuadPart & pTemp->uliSrcDstMask.QuadPart;
  2430. uliPort.QuadPart = (*puliProtoSrcDstPort).QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2431. if(uliAddr.QuadPart == pTemp->uliSrcDstAddr.QuadPart)
  2432. {
  2433. //
  2434. // addresses match. For the ports it depends
  2435. // on whether this is a port range.
  2436. //
  2437. if(pTemp->dwFlags & FILTER_FLAGS_PORTWILD)
  2438. {
  2439. ULARGE_INTEGER uliPort1;
  2440. //
  2441. // a port range. Have to do some more complicated
  2442. // matching. First mask the filter value.
  2443. //
  2444. uliPort1.QuadPart = pTemp->uliProtoSrcDstPort.QuadPart & pTemp->uliProtoSrcDstMask.QuadPart;
  2445. if(uliPort.QuadPart == uliPort1.QuadPart)
  2446. {
  2447. //
  2448. // it passes muster so far. So look at the
  2449. // range.
  2450. do
  2451. {
  2452. if(pTemp->wSrcPortHigh)
  2453. {
  2454. DWORD dwPort =
  2455. LOWORD(puliProtoSrcDstPort->HighPart);
  2456. dwPort = net_short((USHORT)dwPort);
  2457. if((LOWORD(pTemp->uliProtoSrcDstPort.HighPart) >
  2458. dwPort)
  2459. ||
  2460. (pTemp->wSrcPortHigh <
  2461. dwPort))
  2462. {
  2463. break;
  2464. }
  2465. }
  2466. if(pTemp->wDstPortHigh)
  2467. {
  2468. DWORD dwPort =
  2469. HIWORD(puliProtoSrcDstPort->HighPart);
  2470. dwPort = net_short((USHORT)dwPort);
  2471. if((HIWORD(pTemp->uliProtoSrcDstPort.HighPart) >
  2472. dwPort)
  2473. ||
  2474. (pTemp->wDstPortHigh <
  2475. dwPort))
  2476. {
  2477. break;
  2478. }
  2479. }
  2480. return(pTemp);
  2481. } while(TRUE);
  2482. }
  2483. }
  2484. else
  2485. {
  2486. //
  2487. // not a range. So just do the simple test
  2488. //
  2489. if(uliPort.QuadPart == pTemp->uliProtoSrcDstPort.QuadPart)
  2490. {
  2491. return(pTemp);
  2492. }
  2493. }
  2494. }
  2495. }
  2496. }
  2497. return(NULL);
  2498. }
  2499. #define TCP_OFFSET_MASK 0xf0
  2500. #define TCP_HDR_SIZE(t) (DWORD)(((*(uchar *)&(t)->tcp_flags) & TCP_OFFSET_MASK)>> 2)
  2501. BOOL
  2502. CheckForTcpCtl(
  2503. PFILTER_INTERFACE pIf,
  2504. DWORD Prot,
  2505. UNALIGNED IPHeader *pIp,
  2506. PBYTE pbRest,
  2507. DWORD dwSize)
  2508. /*++
  2509. Routine Description:
  2510. Check for a TCP control packet. This is quite selective allowing
  2511. only ACK, FIN, and RST packets with either no payload or a four-byte
  2512. payload.
  2513. --*/
  2514. {
  2515. if(Prot == MAKELONG(MAKEWORD(6, 0x00), 0x0000))
  2516. {
  2517. PTCPHeader pTcp = (PTCPHeader)pbRest;
  2518. if((dwSize >= sizeof(TCPHeader))
  2519. &&
  2520. (dwSize <= (TCP_HDR_SIZE(pTcp) + 4)))
  2521. {
  2522. if(pTcp->tcp_flags & (TCP_FLAG_FIN | TCP_FLAG_ACK | TCP_FLAG_RST))
  2523. {
  2524. pIf->CountCtl.lCount++;
  2525. return(TRUE);
  2526. }
  2527. }
  2528. }
  2529. return(FALSE);
  2530. }
  2531. VOID
  2532. SendTCPReset(UNALIGNED IPHeader * pIpHeader,
  2533. BYTE * pbRestOfPacket,
  2534. ULONG uiPacketLength)
  2535. /*++
  2536. Routine Description:
  2537. Called when a TCP frame is dropped. Creates and sends a
  2538. TCP reset frame.
  2539. --*/
  2540. {
  2541. return;
  2542. }
  2543. VOID
  2544. SendUDPUnreachable(UNALIGNED IPHeader * pIpHeader,
  2545. BYTE * pbRestOfPacket,
  2546. ULONG uiPacketLength)
  2547. /*++
  2548. Routine Description:
  2549. Called when a UDP frame is dropped. Creates and sends a
  2550. UDP unreachable frame
  2551. --*/
  2552. {
  2553. return;
  2554. }
  2555. VOID __fastcall
  2556. FragCacheUpdate(
  2557. ULARGE_INTEGER uliSrcDstAddr,
  2558. PVOID pInContext,
  2559. PVOID pOutContext,
  2560. DWORD dwId,
  2561. FORWARD_ACTION faAction
  2562. )
  2563. /*++
  2564. Routine Description
  2565. Called whenvert the first fragment of a fragmented packet arrives. The action
  2566. taken on the fragment is cached and is applied to other fragments in fastpath.
  2567. --*/
  2568. {
  2569. DWORD dwFragIndex;
  2570. KIRQL kiCurrIrql;
  2571. PLIST_ENTRY pleNode;
  2572. PFRAG_INFO pfiFragInfo;
  2573. //
  2574. // Look up id in frag table and check for a match
  2575. //
  2576. dwFragIndex = dwId % g_dwFragTableSize;
  2577. TRACE(FRAG,(
  2578. "IPFLTDRV: Updating frag cache with %x.%x %x\n",
  2579. uliSrcDstAddr.HighPart,
  2580. uliSrcDstAddr.LowPart,
  2581. dwId
  2582. ));
  2583. TRACE(FRAG,(
  2584. "IPFLTDRV: In %x Out %x Id %x action %s\n",
  2585. pInContext,
  2586. pOutContext,
  2587. dwId,
  2588. (faAction is DROP)?"DROP":"FORWARD"
  2589. ));
  2590. KeAcquireSpinLock(&g_kslFragLock,
  2591. &kiCurrIrql);
  2592. #if DBG
  2593. for(pleNode = g_pleFragTable[dwFragIndex].Flink;
  2594. pleNode isnot &(g_pleFragTable[dwFragIndex]);
  2595. pleNode = pleNode->Flink)
  2596. {
  2597. pfiFragInfo = CONTAINING_RECORD(pleNode,
  2598. FRAG_INFO,
  2599. leCacheLink);
  2600. if((pfiFragInfo->uliSrcDstAddr.QuadPart is uliSrcDstAddr.QuadPart) and
  2601. (pfiFragInfo->pvInContext is pInContext) and
  2602. (pfiFragInfo->pvOutContext is pOutContext) and
  2603. (pfiFragInfo->dwId is dwId))
  2604. {
  2605. //
  2606. // Very weird, should never happen
  2607. //
  2608. TRACE(FRAG,("IPFLTDRV: FRAG Duplicate Insert\n"));
  2609. DbgBreakPoint();
  2610. KeQueryTickCount((PLARGE_INTEGER)&(pfiFragInfo->llLastAccess));
  2611. KeReleaseSpinLock(&g_kslFragLock,
  2612. kiCurrIrql);
  2613. return;
  2614. }
  2615. }
  2616. #endif
  2617. if(InterlockedIncrement(&g_dwNumFragsAllocs) > MAX_FRAG_ALLOCS)
  2618. {
  2619. TRACE(FRAG,(
  2620. "IPFLTDRV: Fragcounter at %d\n",
  2621. g_dwNumFragsAllocs
  2622. ));
  2623. InterlockedDecrement(&g_dwNumFragsAllocs);
  2624. return;
  2625. }
  2626. pfiFragInfo = ExAllocateFromNPagedLookasideList(&g_llFragCacheBlocks);
  2627. if(pfiFragInfo is NULL)
  2628. {
  2629. ERROR(("IPFLTDRV: No memory for frags\n"));
  2630. KeReleaseSpinLock(&g_kslFragLock,
  2631. kiCurrIrql);
  2632. return;
  2633. }
  2634. InterlockedIncrement(&g_dwNumFragsAllocs);
  2635. pfiFragInfo->dwId = dwId;
  2636. pfiFragInfo->uliSrcDstAddr.QuadPart = uliSrcDstAddr.QuadPart;
  2637. pfiFragInfo->pvInContext = pInContext;
  2638. pfiFragInfo->pvOutContext = pOutContext;
  2639. pfiFragInfo->faAction = faAction;
  2640. KeQueryTickCount((PLARGE_INTEGER)&(pfiFragInfo->llLastAccess));
  2641. TRACE(FRAG,(
  2642. "IPFLTDRV: Inserted %x into index %d\n",
  2643. pfiFragInfo,
  2644. dwFragIndex
  2645. ));
  2646. InsertHeadList(&(g_pleFragTable[dwFragIndex]),
  2647. &(pfiFragInfo->leCacheLink));
  2648. KeReleaseSpinLock(&g_kslFragLock,
  2649. kiCurrIrql);
  2650. }
  2651. VOID
  2652. FragCacheTimerRoutine(
  2653. PKDPC Dpc,
  2654. PVOID DeferredContext,
  2655. PVOID SystemArgument1,
  2656. PVOID SystemArgument2
  2657. )
  2658. /*++
  2659. Routine Description
  2660. A DPC timer routine which fires up at a fixed interval to cleanup the fragment cache.
  2661. Specifically the enetries unused for a predfined timer interval are freed.
  2662. --*/
  2663. {
  2664. ULONG i;
  2665. LONGLONG llCurrentTime;
  2666. ULONGLONG ullTime;
  2667. KeQueryTickCount((PLARGE_INTEGER)&llCurrentTime);
  2668. KeAcquireSpinLockAtDpcLevel(&g_kslFragLock);
  2669. TRACE(FRAG,("IPFLTDRV: Timer called...\n"));
  2670. for(i = 0; i < g_dwFragTableSize; i++)
  2671. {
  2672. PLIST_ENTRY pleNode;
  2673. pleNode = g_pleFragTable[i].Flink;
  2674. while(pleNode isnot &(g_pleFragTable[i]))
  2675. {
  2676. PFRAG_INFO pfiFragInfo;
  2677. pfiFragInfo = CONTAINING_RECORD(pleNode,
  2678. FRAG_INFO,
  2679. leCacheLink);
  2680. pleNode = pleNode->Flink;
  2681. ullTime = (ULONGLONG)(llCurrentTime - pfiFragInfo->llLastAccess);
  2682. if(ullTime < (ULONGLONG)g_llInactivityTime)
  2683. {
  2684. continue;
  2685. }
  2686. TRACE(FRAG,(
  2687. "IPFLTDRV: FragTimer removing %x from %d\n",
  2688. pfiFragInfo,
  2689. i
  2690. ));
  2691. RemoveEntryList(&(pfiFragInfo->leCacheLink));
  2692. ExFreeToNPagedLookasideList(&g_llFragCacheBlocks,
  2693. pfiFragInfo);
  2694. InterlockedDecrement(&g_dwNumFragsAllocs);
  2695. }
  2696. }
  2697. KeReleaseSpinLockFromDpcLevel(&g_kslFragLock);
  2698. return;
  2699. }