Leaked source code of windows server 2003
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.

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