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.

4343 lines
118 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. Author:
  7. Revision History:
  8. --*/
  9. /*----------------------------------------------------------------------------
  10. A note on the interlocking, as of 24-Feb-1997.
  11. There are two important locks: the FilterListResourceLock which is
  12. a resource and the g_filter.ifListLock, which is a spin lock but acts
  13. like a resource. The former is used to serialize API access to interface state
  14. and filters. The latter is used to serialize DPC access.
  15. ----------------------------------------------------------------------------*/
  16. #include "globals.h"
  17. ERESOURCE FilterListResourceLock;
  18. BOOL fCheckDups = FALSE;
  19. extern NPAGED_LOOKASIDE_LIST filter_slist;
  20. extern PAGED_LOOKASIDE_LIST paged_slist;
  21. NTSTATUS
  22. UpdateMatchBindingInformation(
  23. PFILTER_DRIVER_BINDING_INFO pBindInfo,
  24. PVOID pvContext
  25. );
  26. NTSTATUS
  27. CreateCommonInterface(PPAGED_FILTER_INTERFACE pPage,
  28. DWORD dwBind,
  29. DWORD dwName,
  30. DWORD dwFlags);
  31. VOID
  32. FreePagedFilterList(PPFFCB Fcb,
  33. PPAGED_FILTER pIn,
  34. PPAGED_FILTER_INTERFACE pPage,
  35. PDWORD pdwRemoved);
  36. VOID
  37. DeleteFilterList(PLIST_ENTRY pList);
  38. BOOL
  39. IsOnSpecialFilterList(PPAGED_FILTER pPageFilter,
  40. PLIST_ENTRY List,
  41. PPAGED_FILTER * pPageHit);
  42. PPAGED_FILTER
  43. IsOnPagedInterface(PPAGED_FILTER pPageFilter,
  44. PPAGED_FILTER_INTERFACE pPage);
  45. PPAGED_FILTER
  46. MakePagedFilter(
  47. IN PPFFCB Fcb,
  48. IN PFILTER_INFOEX pInfo,
  49. IN DWORD dwEpoch,
  50. DWORD dwFlags
  51. );
  52. VOID
  53. NotifyFastPath( PFILTER_INTERFACE pIf, DWORD dwIndex, DWORD dwCode);
  54. VOID
  55. NotifyFastPathIf( PFILTER_INTERFACE pIf);
  56. NTSTATUS
  57. DeleteByHandle(
  58. IN PPFFCB Fcb,
  59. IN PPAGED_FILTER_INTERFACE pPage,
  60. IN PVOID * ppHandles,
  61. IN DWORD dwLength);
  62. NTSTATUS
  63. CheckFilterAddress(DWORD dwAdd, PFILTER_INTERFACE pIf);
  64. VOID
  65. AddFilterToInterface(
  66. PFILTER pMatch,
  67. PFILTER_INTERFACE pIf,
  68. BOOL fInFilter,
  69. PFILTER * ppFilter);
  70. VOID
  71. RemoveFilterWorker(
  72. PPFFCB Fcb,
  73. PFILTER_INFOEX pFilt,
  74. DWORD dwCount,
  75. PPAGED_FILTER_INTERFACE pPage,
  76. PDWORD pdwRemoved,
  77. BOOL fInFilter);
  78. NTSTATUS
  79. AllocateAndAddFilterToMatchInterface(
  80. PPFFCB Fcb,
  81. PFILTER_INFOEX pInfo,
  82. BOOL fInFilter,
  83. PPAGED_FILTER_INTERFACE pPage,
  84. PBOOL pbAdded,
  85. PPAGED_FILTER * ppFilter);
  86. #pragma alloc_text(PAGED, SetFiltersEx)
  87. #pragma alloc_text(PAGED, NewInterface)
  88. #pragma alloc_text(PAGED, MakeNewFilters)
  89. #pragma alloc_text(PAGED, GetPointerToTocEntry)
  90. //#pragma alloc_text(PAGED, AddNewInterface)
  91. #pragma alloc_text(PAGED, MakePagedFilter)
  92. #pragma alloc_text(PAGED, AllocateAndAddFilterToMatchInterface)
  93. #pragma alloc_text(PAGED, IsOnSpecialFilterList)
  94. #pragma alloc_text(PAGED, IsOnPagedInterface)
  95. #pragma alloc_text(PAGED, UnSetFiltersEx)
  96. #pragma alloc_text(PAGED, DeleteByHandle)
  97. #pragma alloc_text(PAGED, DeletePagedInterface)
  98. #define HandleHash(x) HashList[(x) + g_dwHashLists]
  99. #define IsValidInterface(pIf) (pIf != 0)
  100. #define NOT_RESTRICTION 1
  101. #define NOT_UNBIND 2
  102. #if DOFRAGCHECKING
  103. DWORD
  104. GetFragIndex(DWORD dwProt)
  105. {
  106. switch(dwProt)
  107. {
  108. case FILTER_PROTO_ICMP:
  109. return FRAG_ICMP;
  110. case FILTER_PROTO_UDP:
  111. return FRAG_UDP;
  112. case FILTER_PROTO_TCP:
  113. return FRAG_TCP;
  114. }
  115. return FRAG_OTHER;
  116. }
  117. #endif
  118. BOOL CheckDescriptorSize(PFILTER_DESCRIPTOR2 pdsc, PBYTE pbEnd)
  119. {
  120. PFILTER_INFOEX pFilt = &pdsc->fiFilter[0];
  121. //
  122. // Check that there is a full header structure and that
  123. // the claimed number of filters is present.
  124. //
  125. if(((PBYTE)pFilt > pbEnd)
  126. ||
  127. ((PBYTE)(&pFilt[pdsc->dwNumFilters]) > pbEnd) )
  128. {
  129. return(FALSE);
  130. }
  131. return(TRUE);
  132. }
  133. BOOL
  134. WildFilter(PFILTER pf)
  135. {
  136. #if WILDHASH
  137. if(pf->dwFlags & FILTER_FLAGS_INFILTER)
  138. {
  139. if(pf->dwFlags & FILTER_FLAGS_DSTWILD)
  140. {
  141. return(TRUE);
  142. }
  143. }
  144. else
  145. {
  146. if(pf->dwFlags & FILTER_FLAGS_SRCWILD)
  147. {
  148. return(TRUE);
  149. }
  150. }
  151. return(FALSE);
  152. #else
  153. return(ANYWILDFILTER(pf))
  154. #endif
  155. }
  156. //
  157. // N.B. If WILDHASH is on, then there is code in match.c that
  158. // does a similar computation. Hence if this changes, then that
  159. // must also.
  160. //
  161. #if WILDHASH
  162. DWORD
  163. ComputeMatchHashIndex(PFILTER pf, PBOOL pfWild)
  164. {
  165. DWORD dwX;
  166. *pfWild = TRUE;
  167. if(!ANYWILDFILTER(pf))
  168. {
  169. *pfWild = FALSE;
  170. dwX = (pf->SRC_ADDR +
  171. pf->DEST_ADDR +
  172. pf->DEST_ADDR +
  173. PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
  174. pf->uliProtoSrcDstPort.HighPart);
  175. }
  176. else if(WildFilter(pf))
  177. {
  178. if(pf->dwFlags & FILTER_FLAGS_INFILTER)
  179. {
  180. dwX = g_dwHashLists;
  181. }
  182. else
  183. {
  184. dwX = g_dwHashLists + 1;
  185. }
  186. *pfWild = FALSE;
  187. return(dwX);
  188. }
  189. else if(pf->dwFlags & FILTER_FLAGS_INFILTER)
  190. {
  191. dwX = pf->DEST_ADDR +
  192. pf->DEST_ADDR +
  193. PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
  194. HIWORD(pf->uliProtoSrcDstPort.HighPart);
  195. }
  196. else
  197. {
  198. dwX = pf->SRC_ADDR +
  199. PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
  200. LOWORD(pf->uliProtoSrcDstPort.HighPart);
  201. }
  202. return(dwX % g_dwHashLists);
  203. }
  204. #else // WILDHASH
  205. __inline
  206. DWORD
  207. ComputeMatchHashIndex(PFILTER pf, PBOOL pfWild)
  208. {
  209. DWORD dwX;
  210. if(WildFilter(pf))
  211. {
  212. if(pf->dwFlags & FILTER_FLAGS_SRCWILD)
  213. {
  214. dwX = g_dwHashLists;
  215. }
  216. else
  217. {
  218. dwX = g_dwHashLists + 1;
  219. }
  220. return(dwIndex);
  221. }
  222. dwX = (pf->SRC_ADDR +
  223. pf->DEST_ADDR +
  224. pf->DEST_ADDR +
  225. PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
  226. pf->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
  227. return(dwX);
  228. }
  229. #endif // WILDHASH
  230. PFILTER_INTERFACE
  231. FindMatchName(DWORD dwName, DWORD dwBind)
  232. /*++
  233. Routine Description:
  234. Find an interface with the same name or with the
  235. same binding. The calller must have locked the
  236. resource
  237. --*/
  238. {
  239. PFILTER_INTERFACE pIf1;
  240. PLIST_ENTRY pList;
  241. for(pList = g_filters.leIfListHead.Flink;
  242. pList != &g_filters.leIfListHead;
  243. pList = pList->Flink)
  244. {
  245. pIf1 = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
  246. if((pIf1->dwName && (dwName == pIf1->dwName))
  247. ||
  248. ((pIf1->dwIpIndex != UNKNOWN_IP_INDEX)
  249. &&
  250. (pIf1->dwIpIndex == dwBind)) )
  251. {
  252. return(pIf1);
  253. }
  254. }
  255. return(NULL);
  256. }
  257. VOID
  258. RemoveGlobalFilterFromInterface(PFILTER_INTERFACE pIf,
  259. DWORD dwType)
  260. {
  261. LOCK_STATE LockState;
  262. //
  263. // lock up the filters
  264. //
  265. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  266. switch(dwType)
  267. {
  268. case PFE_SYNORFRAG:
  269. pIf->CountSynOrFrag.lInUse--;
  270. if(pIf->CountSynOrFrag.lInUse == 0)
  271. {
  272. pIf->CountSynOrFrag.lCount = 0;
  273. }
  274. break;
  275. case PFE_SPOOF:
  276. pIf->CountSpoof.lInUse--;
  277. if(pIf->CountSpoof.lInUse == 0)
  278. {
  279. pIf->CountSpoof.lCount = 0;
  280. }
  281. break;
  282. case PFE_UNUSEDPORT:
  283. pIf->CountUnused.lInUse--;
  284. if(pIf->CountUnused.lInUse == 0)
  285. {
  286. pIf->CountUnused.lCount = 0;
  287. }
  288. break;
  289. case PFE_STRONGHOST:
  290. pIf->CountStrongHost.lInUse--;
  291. if(pIf->CountStrongHost.lInUse == 0)
  292. {
  293. pIf->CountStrongHost.lCount = 0;
  294. }
  295. break;
  296. case PFE_ALLOWCTL:
  297. pIf->CountCtl.lInUse--;
  298. if(pIf->CountCtl.lInUse == 0)
  299. {
  300. pIf->CountCtl.lCount = 0;
  301. }
  302. break;
  303. case PFE_FULLDENY:
  304. pIf->CountFullDeny.lInUse--;
  305. if(pIf->CountFullDeny.lInUse == 0)
  306. {
  307. pIf->CountFullDeny.lCount = 0;
  308. }
  309. break;
  310. case PFE_NOFRAG:
  311. pIf->CountNoFrag.lInUse--;
  312. if(pIf->CountNoFrag.lInUse == 0)
  313. {
  314. pIf->CountNoFrag.lCount = 0;
  315. }
  316. break;
  317. case PFE_FRAGCACHE:
  318. pIf->CountFragCache.lInUse--;
  319. if(pIf->CountFragCache.lInUse == 0)
  320. {
  321. pIf->CountFragCache.lCount = 0;
  322. }
  323. break;
  324. }
  325. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  326. }
  327. VOID
  328. AddGlobalFilterToInterface(PPAGED_FILTER_INTERFACE pPage,
  329. PFILTER_INFOEX pfilt)
  330. {
  331. PFILTER_INTERFACE pIf = pPage->pFilter;
  332. LOCK_STATE LockState;
  333. //
  334. // lock up the filters
  335. //
  336. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  337. switch(pfilt->type)
  338. {
  339. case PFE_SYNORFRAG:
  340. pIf->CountSynOrFrag.lInUse++;
  341. break;
  342. case PFE_SPOOF:
  343. pIf->CountSpoof.lInUse++;
  344. break;
  345. case PFE_UNUSEDPORT:
  346. pIf->CountUnused.lInUse++;
  347. break;
  348. case PFE_STRONGHOST:
  349. pIf->CountStrongHost.lInUse++;
  350. break;
  351. case PFE_ALLOWCTL:
  352. pIf->CountCtl.lInUse++;
  353. break;
  354. case PFE_FULLDENY:
  355. pIf->CountFullDeny.lInUse++;
  356. break;
  357. case PFE_NOFRAG:
  358. pIf->CountNoFrag.lInUse++;
  359. break;
  360. case PFE_FRAGCACHE:
  361. pIf->CountFragCache.lInUse++;
  362. break;
  363. }
  364. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  365. }
  366. /*++
  367. Start of old STEELHEAD APIS routines.
  368. --*/
  369. #if STEELHEAD
  370. NTSTATUS
  371. AddInterface(
  372. IN PVOID pvRtrMgrCtxt,
  373. IN DWORD dwRtrMgrIndex,
  374. IN DWORD dwAdapterId,
  375. IN PPFFCB Fcb,
  376. OUT PVOID *ppvFltrDrvrCtxt
  377. )
  378. /*++
  379. Routine Description
  380. Adds an interface to the filter driver and makes an association between context
  381. passed in and interface created
  382. Arguments
  383. pvRtrMgrCtxt - Context passed in
  384. pvFltrDrvrCtxt - Handle to interface created
  385. Return Value
  386. --*/
  387. {
  388. PFILTER_INTERFACE pIf;
  389. LOCK_STATE LockState;
  390. NTSTATUS Status;
  391. if(Fcb->dwFlags & PF_FCB_NEW)
  392. {
  393. return(STATUS_INVALID_DEVICE_REQUEST);
  394. }
  395. Fcb->dwFlags |= PF_FCB_OLD;
  396. pIf = NewInterface(pvRtrMgrCtxt,
  397. dwRtrMgrIndex,
  398. FORWARD,
  399. FORWARD,
  400. (PVOID)Fcb,
  401. dwAdapterId,
  402. 0);
  403. if(pIf is NULL)
  404. {
  405. return STATUS_NO_MEMORY;
  406. }
  407. //
  408. // lock the resource that protects adding new interfaces. This
  409. // is needed to hold off others until everything is properly
  410. // verified. The spin lock is insufficient for this.
  411. //
  412. KeEnterCriticalRegion();
  413. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  414. //
  415. // Check for a name conflict
  416. //
  417. if(FindMatchName(0, dwAdapterId))
  418. {
  419. ExFreePool(pIf);
  420. Status = STATUS_DEVICE_BUSY;
  421. }
  422. else
  423. {
  424. pIf->dwGlobalEnables |= FI_ENABLE_OLD;
  425. *ppvFltrDrvrCtxt = (PVOID)pIf;
  426. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  427. InsertTailList(&g_filters.leIfListHead,&pIf->leIfLink);
  428. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  429. Status = STATUS_SUCCESS;
  430. }
  431. ExReleaseResourceLite(&FilterListResourceLock);
  432. KeLeaveCriticalRegion();
  433. return(Status);
  434. }
  435. NTSTATUS
  436. DeleteInterface(
  437. IN PVOID pvIfContext
  438. )
  439. /*++
  440. Routine Description
  441. Deletes an interface and all the filters associated with it
  442. Clears the cache
  443. Arguments
  444. pvRtrMgrCtxt - Context passed in
  445. pvFltrDrvrCtxt - Handle to interface created
  446. Return Value
  447. --*/
  448. {
  449. PFILTER_INTERFACE pIf;
  450. LOCK_STATE LockState;
  451. pIf = (PFILTER_INTERFACE)pvIfContext;
  452. if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
  453. {
  454. return(STATUS_INVALID_DEVICE_REQUEST);
  455. }
  456. KeEnterCriticalRegion();
  457. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  458. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  459. DeleteFilters(pIf,
  460. IN_FILTER_SET);
  461. DeleteFilters(pIf,
  462. OUT_FILTER_SET);
  463. RemoveEntryList(&pIf->leIfLink);
  464. ClearCache();
  465. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  466. ExReleaseResourceLite(&FilterListResourceLock);
  467. KeLeaveCriticalRegion();
  468. return STATUS_SUCCESS;
  469. }
  470. NTSTATUS
  471. SetFilters(
  472. IN PFILTER_DRIVER_SET_FILTERS pRtrMgrInfo
  473. )
  474. /*++
  475. Routine Description
  476. Adds the set of in and out filters passed to the interface (identified by the
  477. context). Also sets the default actions.
  478. Clears the cache
  479. Arguments
  480. pInfo Pointer to info passed by the router manager
  481. Return Value
  482. --*/
  483. {
  484. PFILTER_INTERFACE pIf;
  485. LOCK_STATE LockState;
  486. NTSTATUS ntStatus;
  487. DWORD dwNumInFilters,dwNumOutFilters;
  488. FORWARD_ACTION faInAction,faOutAction;
  489. PFILTER_DESCRIPTOR pFilterDesc;
  490. PRTR_TOC_ENTRY pInToc,pOutToc;
  491. LIST_ENTRY InList, OutList;
  492. //
  493. // Sensible defaults
  494. //
  495. dwNumInFilters = dwNumOutFilters = 0;
  496. faInAction = faOutAction = FORWARD;
  497. pIf = (PFILTER_INTERFACE)pRtrMgrInfo->pvDriverContext;
  498. if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
  499. {
  500. return(STATUS_INVALID_DEVICE_REQUEST);
  501. }
  502. pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
  503. &pRtrMgrInfo->ribhInfoBlock);
  504. pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
  505. &pRtrMgrInfo->ribhInfoBlock);
  506. if(!pInToc && !pOutToc)
  507. {
  508. //
  509. // Nothing to change
  510. //
  511. TRACE(CONFIG,(
  512. "IPFLTDRV: Both filter set TOCs were null so nothing to change"
  513. ));
  514. return STATUS_SUCCESS;
  515. }
  516. if(pInToc)
  517. {
  518. //
  519. // If the infosize is 0, the filters will get deleted and default action
  520. // set to FORWARD. If infosize isnot 0 but the number of filters in the
  521. // descriptor is zero, the old filters will get deleted, no new filters
  522. // will be added, but the default action will be the one specified in the
  523. // descriptor. If Infosize is not 0 and number od filters is also not zero
  524. // then old filters will get deleted, new filters created and default
  525. // action set to what is specified in the
  526. //
  527. if(pInToc->InfoSize)
  528. {
  529. pFilterDesc = GetInfoFromTocEntry(&pRtrMgrInfo->ribhInfoBlock,
  530. pInToc);
  531. if(pFilterDesc->dwVersion != 1)
  532. {
  533. return(STATUS_INVALID_PARAMETER);
  534. }
  535. if(!NT_SUCCESS( ntStatus = MakeNewFilters(pFilterDesc->dwNumFilters,
  536. pFilterDesc->fiFilter,
  537. TRUE,
  538. &InList)))
  539. {
  540. ERROR(("IPFLTDRV: MakeNewFilters failed\n"));
  541. return ntStatus;
  542. }
  543. dwNumInFilters = pFilterDesc->dwNumFilters;
  544. faInAction = pFilterDesc->faDefaultAction;
  545. }
  546. }
  547. if(pOutToc)
  548. {
  549. if(pOutToc->InfoSize isnot 0)
  550. {
  551. pFilterDesc = GetInfoFromTocEntry(&pRtrMgrInfo->ribhInfoBlock,
  552. pOutToc);
  553. if(pFilterDesc->dwVersion != 1)
  554. {
  555. ntStatus = STATUS_INVALID_PARAMETER;
  556. DeleteFilterList(&InList);
  557. return ntStatus;
  558. }
  559. if(!NT_SUCCESS( ntStatus = MakeNewFilters(pFilterDesc->dwNumFilters,
  560. pFilterDesc->fiFilter,
  561. FALSE,
  562. &OutList)))
  563. {
  564. ERROR(("IPFLTDRV: MakeNewFilters failed - %x\n", ntStatus));
  565. DeleteFilterList(&InList);
  566. return ntStatus;
  567. }
  568. dwNumOutFilters = pFilterDesc->dwNumFilters;
  569. faOutAction = pFilterDesc->faDefaultAction;
  570. }
  571. }
  572. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  573. //
  574. // If new info was given, then blow away the old filters
  575. // If new filters were also given, then add them
  576. //
  577. if(pInToc)
  578. {
  579. DeleteFilters(pIf, IN_FILTER_SET);
  580. if(dwNumInFilters)
  581. {
  582. InList.Flink->Blink = &pIf->pleInFilterSet;
  583. InList.Blink->Flink = &pIf->pleInFilterSet;
  584. pIf->pleInFilterSet = InList;
  585. }
  586. pIf->dwNumInFilters = dwNumInFilters;
  587. pIf->eaInAction = faInAction;
  588. }
  589. if(pOutToc)
  590. {
  591. DeleteFilters(pIf, OUT_FILTER_SET);
  592. if(dwNumOutFilters)
  593. {
  594. OutList.Flink->Blink = &pIf->pleOutFilterSet;
  595. OutList.Blink->Flink = &pIf->pleOutFilterSet;
  596. pIf->pleOutFilterSet = OutList;
  597. }
  598. pIf->dwNumOutFilters = dwNumOutFilters;
  599. pIf->eaOutAction = faOutAction;
  600. }
  601. ClearCache();
  602. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  603. return(STATUS_SUCCESS);
  604. }
  605. NTSTATUS
  606. UpdateBindingInformation(
  607. PFILTER_DRIVER_BINDING_INFO pBindInfo,
  608. PVOID pvContext
  609. )
  610. /*++
  611. Routine Description
  612. Gets filters and statistics associated with an interface
  613. It is called with the Spin Lock held as reader
  614. Arguments
  615. pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
  616. to router manager as a context for the interface
  617. pInfo FILTER_IF structure filled in by driver
  618. Return Value
  619. --*/
  620. {
  621. PFILTER_INTERFACE pIf;
  622. LOCK_STATE LockState;
  623. PFILTER pf;
  624. DWORD i;
  625. PLIST_ENTRY List;
  626. pIf = (PFILTER_INTERFACE)pvContext;
  627. if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
  628. {
  629. return(STATUS_INVALID_DEVICE_REQUEST);
  630. }
  631. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  632. for(List = pIf->pleInFilterSet.Flink;
  633. List != &pIf->pleInFilterSet;
  634. List = List->Flink)
  635. {
  636. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  637. if(AreAllFieldsUnchanged(pf))
  638. {
  639. continue;
  640. }
  641. if(DoesSrcAddrUseLocalAddr(pf))
  642. {
  643. pf->SRC_ADDR = pBindInfo->dwLocalAddr;
  644. }
  645. else if(DoesSrcAddrUseRemoteAddr(pf))
  646. {
  647. pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
  648. }
  649. if(DoesDstAddrUseLocalAddr(pf))
  650. {
  651. pf->DEST_ADDR = pBindInfo->dwLocalAddr;
  652. }
  653. else if(DoesDstAddrUseRemoteAddr(pf))
  654. {
  655. pf->DEST_ADDR = pBindInfo->dwRemoteAddr;
  656. }
  657. if(IsSrcMaskLateBound(pf))
  658. {
  659. pf->SRC_MASK = pBindInfo->dwMask;
  660. }
  661. if(IsDstMaskLateBound(pf))
  662. {
  663. pf->DEST_MASK = pBindInfo->dwMask;
  664. }
  665. }
  666. for(List = pIf->pleOutFilterSet.Flink;
  667. List != &pIf->pleOutFilterSet;
  668. List = List->Flink)
  669. {
  670. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  671. if(AreAllFieldsUnchanged(pf))
  672. {
  673. continue;
  674. }
  675. if(DoesSrcAddrUseLocalAddr(pf))
  676. {
  677. pf->SRC_ADDR = pBindInfo->dwLocalAddr;
  678. }
  679. if(DoesSrcAddrUseRemoteAddr(pf))
  680. {
  681. pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
  682. }
  683. if(DoesDstAddrUseLocalAddr(pf))
  684. {
  685. pf->SRC_ADDR = pBindInfo->dwLocalAddr;
  686. }
  687. if(DoesDstAddrUseRemoteAddr(pf))
  688. {
  689. pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
  690. }
  691. if(IsSrcMaskLateBound(pf))
  692. {
  693. pf->SRC_MASK = pBindInfo->dwMask;
  694. }
  695. if(IsDstMaskLateBound(pf))
  696. {
  697. pf->DEST_MASK = pBindInfo->dwMask;
  698. }
  699. }
  700. ClearCache();
  701. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  702. return STATUS_SUCCESS;
  703. }
  704. NTSTATUS
  705. GetFilters(
  706. IN PFILTER_INTERFACE pIf,
  707. IN BOOL fClear,
  708. OUT PFILTER_IF pInfo
  709. )
  710. /*++
  711. Routine Description
  712. Gets filters and statistics associated with an interface
  713. It is called with the Spin Lock held as reader
  714. Arguments
  715. pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
  716. to router manager as a context for the interface
  717. pInfo FILTER_IF structure filled in by driver
  718. Return Value
  719. --*/
  720. {
  721. DWORD i,dwNumInFilters,dwNumOutFilters;
  722. PFILTER pf;
  723. PLIST_ENTRY List;
  724. if(!IsValidInterface(pIf) || !(pIf->dwGlobalEnables & FI_ENABLE_OLD))
  725. {
  726. return(STATUS_INVALID_DEVICE_REQUEST);
  727. }
  728. dwNumInFilters = pIf->dwNumInFilters;
  729. dwNumOutFilters = pIf->dwNumOutFilters;
  730. i = 0;
  731. for(List = pIf->pleInFilterSet.Flink;
  732. List != &pIf->pleInFilterSet;
  733. i++, List = List->Flink)
  734. {
  735. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  736. pInfo->filters[i].dwNumPacketsFiltered = (DWORD)pf->Count.lCount;
  737. if(fClear)
  738. {
  739. pf->Count.lCount = 0;
  740. }
  741. pInfo->filters[i].info.dwSrcAddr = pf->SRC_ADDR;
  742. pInfo->filters[i].info.dwSrcMask = pf->SRC_MASK;
  743. pInfo->filters[i].info.dwDstAddr = pf->DEST_ADDR;
  744. pInfo->filters[i].info.dwDstMask = pf->DEST_MASK;
  745. pInfo->filters[i].info.dwProtocol = pf->PROTO;
  746. pInfo->filters[i].info.fLateBound = pf->fLateBound;
  747. if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_ICMP)
  748. {
  749. if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  750. {
  751. pInfo->filters[i].info.wSrcPort = FILTER_ICMP_TYPE_ANY;
  752. }
  753. else
  754. {
  755. pInfo->filters[i].info.wSrcPort =
  756. MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  757. }
  758. if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  759. {
  760. pInfo->filters[i].info.wDstPort = FILTER_ICMP_CODE_ANY;
  761. }
  762. else
  763. {
  764. pInfo->filters[i].info.wDstPort =
  765. MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  766. }
  767. }
  768. else
  769. {
  770. pInfo->filters[i].info.wSrcPort =
  771. LOWORD(pf->uliProtoSrcDstPort.HighPart);
  772. pInfo->filters[i].info.wDstPort =
  773. HIWORD(pf->uliProtoSrcDstPort.HighPart);
  774. if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_TCP)
  775. {
  776. if(HIBYTE(LOWORD(pf->PROTO)))
  777. {
  778. pInfo->filters[i].info.dwProtocol = FILTER_PROTO_TCP_ESTAB;
  779. }
  780. }
  781. }
  782. }
  783. i = 0;
  784. for(List = pIf->pleOutFilterSet.Flink;
  785. List != &pIf->pleOutFilterSet;
  786. i++, List = List->Flink)
  787. {
  788. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  789. pInfo->filters[i+dwNumInFilters].dwNumPacketsFiltered =
  790. (DWORD)pf->Count.lCount;
  791. if(fClear)
  792. {
  793. pf->Count.lCount = 0;
  794. }
  795. pInfo->filters[i+dwNumInFilters].info.dwSrcAddr = pf->SRC_ADDR;
  796. pInfo->filters[i+dwNumInFilters].info.dwSrcMask = pf->SRC_MASK;
  797. pInfo->filters[i+dwNumInFilters].info.dwDstAddr = pf->DEST_ADDR;
  798. pInfo->filters[i+dwNumInFilters].info.dwDstMask = pf->DEST_MASK;
  799. pInfo->filters[i+dwNumInFilters].info.dwProtocol = pf->PROTO;
  800. pInfo->filters[i+dwNumInFilters].info.fLateBound = pf->fLateBound;
  801. if(pInfo->filters[i+dwNumInFilters].info.dwProtocol is FILTER_PROTO_ICMP)
  802. {
  803. if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  804. {
  805. pInfo->filters[i+dwNumInFilters].info.wSrcPort = FILTER_ICMP_TYPE_ANY;
  806. }
  807. else
  808. {
  809. pInfo->filters[i+dwNumInFilters].info.wSrcPort =
  810. MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  811. }
  812. if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  813. {
  814. pInfo->filters[i+dwNumInFilters].info.wDstPort = FILTER_ICMP_CODE_ANY;
  815. }
  816. else
  817. {
  818. pInfo->filters[i+dwNumInFilters].info.wDstPort =
  819. MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  820. }
  821. }
  822. else
  823. {
  824. pInfo->filters[i+dwNumInFilters].info.wSrcPort =
  825. LOWORD(pf->uliProtoSrcDstPort.HighPart);
  826. pInfo->filters[i+dwNumInFilters].info.wDstPort =
  827. HIWORD(pf->uliProtoSrcDstPort.HighPart);
  828. if(pInfo->filters[i].info.dwProtocol is FILTER_PROTO_TCP)
  829. {
  830. if(HIBYTE(LOWORD(pf->PROTO)))
  831. {
  832. pInfo->filters[i].info.dwProtocol = FILTER_PROTO_TCP_ESTAB;
  833. }
  834. }
  835. }
  836. }
  837. return(STATUS_SUCCESS);
  838. }
  839. NTSTATUS
  840. MakeNewFilters(
  841. IN DWORD dwNumFilters,
  842. IN PFILTER_INFO pFilterInfo,
  843. IN BOOL fInFilter,
  844. OUT PLIST_ENTRY pList
  845. )
  846. /*++
  847. Routine Description
  848. Arguments
  849. Return Value
  850. --*/
  851. {
  852. DWORD i;
  853. PFILTER pCurrent;
  854. DWORD dwFlags = (fInFilter ? FILTER_FLAGS_INFILTER : 0) |
  855. FILTER_FLAGS_OLDFILTER;
  856. PAGED_CODE();
  857. InitializeListHead(pList);
  858. //
  859. // Allocate memory for the filters
  860. //
  861. if(!dwNumFilters)
  862. {
  863. return STATUS_SUCCESS;
  864. }
  865. for(i = 0; i < dwNumFilters; i++)
  866. {
  867. pCurrent = ExAllocatePoolWithTag(
  868. NonPagedPool,
  869. dwNumFilters * sizeof(FILTER),
  870. '2liF');
  871. if(!pCurrent)
  872. {
  873. ERROR((
  874. "IPFLTDRV: MakeNewFilters: Couldnt allocate memory for in filter set\n"
  875. ));
  876. DeleteFilterList(pList);
  877. return STATUS_NO_MEMORY;
  878. }
  879. InsertTailList(pList, &pCurrent->pleFilters);
  880. pCurrent->SRC_ADDR = pFilterInfo[i].dwSrcAddr;
  881. pCurrent->DEST_ADDR = pFilterInfo[i].dwDstAddr;
  882. pCurrent->SRC_MASK = pFilterInfo[i].dwSrcMask;
  883. pCurrent->DEST_MASK = pFilterInfo[i].dwDstMask;
  884. pCurrent->fLateBound = pFilterInfo[i].fLateBound;
  885. pCurrent->dwFlags = dwFlags;
  886. //
  887. // Now the network ordering stuff - tricky part
  888. // LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
  889. // Proto 00 00 00 SrcPort DstPort
  890. //
  891. // If we have proto == TCP_ESTAB, LP1 is the flags
  892. //
  893. // LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
  894. // Proto TCPFlags 00 00 SrcPort DstPort
  895. //
  896. //
  897. // For addresses, ANY_ADDR is given by 0.0.0.0 and the MASK must be 0.0.0.0
  898. // For proto and ports 0 means any and the mask is generated as follows
  899. // If the proto is O then LP0 for Mask is 0xff else its 0x00
  900. // If a port is 0, the corresponding XP0XP1 is 0x0000 else its 0xffff
  901. //
  902. //
  903. // ICMP:
  904. // LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
  905. // 0x1 00 00 00 Typ Cod 00 00
  906. // ICMP is different since 0 is a valid code and type, so 0xff is used by the
  907. // user to signify that ANY code or type is to be matched. However to do this
  908. // we need to have the field set to zero and the the mask set to 00 (for any).
  909. // But if the filter is specifically for Type/Code = 0 then the field is zero
  910. // with the mask as 0xff
  911. //
  912. //
  913. // The protocol is in the low byte of the dwProtocol, so we take that out and
  914. // make a dword out of it
  915. //
  916. pCurrent->uliProtoSrcDstPort.LowPart =
  917. MAKELONG(MAKEWORD(LOBYTE(LOWORD(pFilterInfo[i].dwProtocol)),0x00),0x0000);
  918. pCurrent->uliProtoSrcDstMask.LowPart = MAKELONG(MAKEWORD(0xff,0x00),0x0000);
  919. switch(pFilterInfo[i].dwProtocol)
  920. {
  921. case FILTER_PROTO_ANY:
  922. {
  923. pCurrent->uliProtoSrcDstPort.HighPart = 0x00000000;
  924. pCurrent->uliProtoSrcDstMask.LowPart = 0x00000000;
  925. pCurrent->uliProtoSrcDstMask.HighPart = 0x00000000;
  926. break;
  927. }
  928. case FILTER_PROTO_ICMP:
  929. {
  930. WORD wTypeCode = 0x0000;
  931. WORD wTypeCodeMask = 0x0000;
  932. if((BYTE)(pFilterInfo[i].wSrcPort) isnot FILTER_ICMP_TYPE_ANY)
  933. {
  934. wTypeCode |= MAKEWORD((BYTE)(pFilterInfo[i].wSrcPort),0x00);
  935. wTypeCodeMask |= MAKEWORD(0xff,0x00);
  936. }
  937. if((BYTE)(pFilterInfo[i].wDstPort) isnot FILTER_ICMP_CODE_ANY)
  938. {
  939. wTypeCode |= MAKEWORD(0x00,(BYTE)(pFilterInfo[i].wDstPort));
  940. wTypeCodeMask |= MAKEWORD(0x00,0xff);
  941. }
  942. pCurrent->uliProtoSrcDstPort.HighPart =
  943. MAKELONG(wTypeCode,0x0000);
  944. pCurrent->uliProtoSrcDstMask.HighPart =
  945. MAKELONG(wTypeCodeMask,0x0000);
  946. break;
  947. }
  948. case FILTER_PROTO_TCP:
  949. case FILTER_PROTO_UDP:
  950. {
  951. DWORD dwSrcDstPort = 0x00000000;
  952. DWORD dwSrcDstMask = 0x00000000;
  953. if(pFilterInfo[i].wSrcPort isnot FILTER_TCPUDP_PORT_ANY)
  954. {
  955. dwSrcDstPort |= MAKELONG(pFilterInfo[i].wSrcPort,0x0000);
  956. dwSrcDstMask |= MAKELONG(0xffff,0x0000);
  957. }
  958. if(pFilterInfo[i].wDstPort isnot FILTER_TCPUDP_PORT_ANY)
  959. {
  960. dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo[i].wDstPort);
  961. dwSrcDstMask |= MAKELONG(0x0000,0xffff);
  962. }
  963. pCurrent->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
  964. pCurrent->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
  965. break;
  966. }
  967. case FILTER_PROTO_TCP_ESTAB:
  968. {
  969. DWORD dwSrcDstPort = 0x00000000;
  970. DWORD dwSrcDstMask = 0x00000000;
  971. //
  972. // The actual protocol is FILTER_PROTO_TCP
  973. //
  974. pCurrent->uliProtoSrcDstPort.LowPart =
  975. MAKELONG(MAKEWORD(FILTER_PROTO_TCP,ESTAB_FLAGS),0x0000);
  976. pCurrent->uliProtoSrcDstMask.LowPart =
  977. MAKELONG(MAKEWORD(0xff,ESTAB_MASK),0x0000);
  978. if(pFilterInfo[i].wSrcPort isnot FILTER_TCPUDP_PORT_ANY)
  979. {
  980. dwSrcDstPort |= MAKELONG(pFilterInfo[i].wSrcPort,0x0000);
  981. dwSrcDstMask |= MAKELONG(0xffff,0x0000);
  982. }
  983. if(pFilterInfo[i].wDstPort isnot FILTER_TCPUDP_PORT_ANY)
  984. {
  985. dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo[i].wDstPort);
  986. dwSrcDstMask |= MAKELONG(0x0000,0xffff);
  987. }
  988. pCurrent->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
  989. pCurrent->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
  990. break;
  991. }
  992. default:
  993. {
  994. //
  995. // All other protocols have no use for the port field
  996. //
  997. pCurrent->uliProtoSrcDstPort.HighPart = 0x00000000;
  998. pCurrent->uliProtoSrcDstMask.HighPart = 0x00000000;
  999. }
  1000. }
  1001. }
  1002. return STATUS_SUCCESS;
  1003. }
  1004. #endif // STEELHEAD
  1005. VOID
  1006. DeleteFilters(
  1007. IN PFILTER_INTERFACE pIf,
  1008. DWORD dwInOrOut
  1009. )
  1010. /*++
  1011. Routine Description
  1012. Deletes all filters associated with an interface
  1013. Assumes that the write lock for this interface is held
  1014. Arguments
  1015. pIf Pointer to interface
  1016. Return Value
  1017. --*/
  1018. {
  1019. if(dwInOrOut == IN_FILTER_SET)
  1020. {
  1021. pIf->dwNumInFilters = 0;
  1022. DeleteFilterList(&pIf->pleInFilterSet);
  1023. }
  1024. else
  1025. {
  1026. pIf->dwNumOutFilters = 0;
  1027. DeleteFilterList(&pIf->pleOutFilterSet);
  1028. }
  1029. }
  1030. NTSTATUS
  1031. SetFiltersEx(
  1032. IN PPFFCB Fcb,
  1033. IN PPAGED_FILTER_INTERFACE pPage,
  1034. IN DWORD dwLength,
  1035. IN PFILTER_DRIVER_SET_FILTERS pInfo)
  1036. /*++
  1037. Routine Description:
  1038. Set filters use the new interface definitions.
  1039. --*/
  1040. {
  1041. PRTR_TOC_ENTRY pInToc,pOutToc;
  1042. PFILTER_INTERFACE pIf = pPage->pFilter;
  1043. PFILTER_DESCRIPTOR2 pFilterDescIn, pFilterDescOut;
  1044. DWORD dwInCount, dwOutCount;
  1045. DWORD i;
  1046. PPAGED_FILTER pPFilter;
  1047. NTSTATUS Status = STATUS_SUCCESS;
  1048. PBYTE pbEnd = (PBYTE)pInfo + dwLength;
  1049. DWORD dwFiltersAdded = 0;
  1050. PAGED_CODE();
  1051. if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
  1052. {
  1053. return(STATUS_INVALID_DEVICE_REQUEST);
  1054. }
  1055. pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
  1056. &pInfo->ribhInfoBlock);
  1057. pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
  1058. &pInfo->ribhInfoBlock);
  1059. if(pInToc && pInToc->InfoSize)
  1060. {
  1061. //
  1062. // filters are defined.
  1063. //
  1064. pFilterDescIn = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
  1065. pInToc);
  1066. if((pFilterDescIn != NULL) && (pFilterDescIn->dwVersion != 2))
  1067. {
  1068. ERROR(("IPFLTDRV: SetFiltersEx: Invalid version for FiltersEx\n"));
  1069. return(STATUS_INVALID_PARAMETER);
  1070. }
  1071. }
  1072. else
  1073. {
  1074. pFilterDescIn = NULL;
  1075. }
  1076. if(pOutToc && pOutToc->InfoSize)
  1077. {
  1078. //
  1079. // filters are defined.
  1080. //
  1081. pFilterDescOut = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
  1082. pOutToc);
  1083. if((pFilterDescOut != NULL) && (pFilterDescOut->dwVersion != 2))
  1084. {
  1085. ERROR(("IPFLTDRV: SetFiltersEx: Invalid version for FiltersEx\n"));
  1086. return(STATUS_INVALID_PARAMETER);
  1087. }
  1088. }
  1089. else
  1090. {
  1091. pFilterDescOut = NULL;
  1092. }
  1093. //
  1094. // For each set of filters, add the filters to the paged, FCB
  1095. // interface and therefore to the match interface.
  1096. //
  1097. if((pFilterDescIn && !CheckDescriptorSize(pFilterDescIn, pbEnd))
  1098. ||
  1099. (pFilterDescOut && !CheckDescriptorSize(pFilterDescOut, pbEnd)) )
  1100. {
  1101. return(STATUS_BUFFER_TOO_SMALL);
  1102. }
  1103. if(pFilterDescIn)
  1104. {
  1105. // Adding in filters. For each filter, process as
  1106. // needed. Input filters include the global checks
  1107. /// such as spoofing.
  1108. //
  1109. for(dwInCount = 0;
  1110. (dwInCount < pFilterDescIn->dwNumFilters);
  1111. dwInCount++)
  1112. {
  1113. PFILTER_INFOEX pFilt = &pFilterDescIn->fiFilter[dwInCount];
  1114. BOOL bAdded;
  1115. //
  1116. // If a regular filter, add it. If a special, global
  1117. // filter, handle it specially.
  1118. //
  1119. if(pFilt->type == PFE_FILTER)
  1120. {
  1121. Status = AllocateAndAddFilterToMatchInterface(
  1122. Fcb,
  1123. pFilt,
  1124. TRUE,
  1125. pPage,
  1126. &bAdded,
  1127. &pPFilter);
  1128. if(!NT_SUCCESS(Status))
  1129. {
  1130. if((Status == STATUS_OBJECT_NAME_COLLISION)
  1131. &&
  1132. pPFilter)
  1133. {
  1134. if(!fCheckDups
  1135. ||
  1136. (pPFilter->dwFlags & FLAGS_INFOEX_ALLOWDUPS))
  1137. {
  1138. pPFilter->dwInUse++;
  1139. Status = STATUS_SUCCESS;
  1140. }
  1141. else
  1142. {
  1143. ERROR((
  1144. "IPFLTDRV: Adding in filter failed %x\n",
  1145. Status
  1146. ));
  1147. break;
  1148. }
  1149. }
  1150. else
  1151. {
  1152. break;
  1153. }
  1154. }
  1155. else if(bAdded && (pIf->eaInAction == FORWARD))
  1156. {
  1157. dwFiltersAdded++;
  1158. }
  1159. }
  1160. else
  1161. {
  1162. //
  1163. // a special filter of some sort.
  1164. //
  1165. pPFilter = MakePagedFilter(Fcb, pFilt, pPage->dwUpdateEpoch, 0);
  1166. if(!pPFilter)
  1167. {
  1168. Status = STATUS_NO_MEMORY;
  1169. }
  1170. else
  1171. {
  1172. PPAGED_FILTER pWhoCares;
  1173. if(IsOnSpecialFilterList(pPFilter,
  1174. &pPage->leSpecialFilterList,
  1175. &pWhoCares))
  1176. {
  1177. pWhoCares->dwInUse++;
  1178. ExFreePool(pPFilter);
  1179. pPFilter = 0;
  1180. }
  1181. else
  1182. {
  1183. switch(pFilt->type)
  1184. {
  1185. case PFE_SYNORFRAG:
  1186. case PFE_SPOOF:
  1187. case PFE_UNUSEDPORT:
  1188. case PFE_ALLOWCTL:
  1189. case PFE_STRONGHOST:
  1190. case PFE_FULLDENY:
  1191. case PFE_NOFRAG:
  1192. case PFE_FRAGCACHE:
  1193. AddGlobalFilterToInterface(pPage, pFilt);
  1194. break;
  1195. default:
  1196. ERROR(("IPFLTDRV: Unknown filter type\n"));
  1197. ExFreePool(pPFilter);
  1198. pPFilter = 0;
  1199. Status = STATUS_INVALID_PARAMETER;
  1200. break;
  1201. }
  1202. }
  1203. if(pPFilter)
  1204. {
  1205. InsertTailList(&pPage->leSpecialFilterList,
  1206. &pPFilter->leSpecialList);
  1207. }
  1208. else if(!NT_SUCCESS(Status))
  1209. {
  1210. break;
  1211. }
  1212. }
  1213. }
  1214. }
  1215. }
  1216. else
  1217. {
  1218. dwInCount = 0;
  1219. }
  1220. if(!NT_SUCCESS(Status))
  1221. {
  1222. RemoveFilterWorker(
  1223. Fcb,
  1224. &pFilterDescIn->fiFilter[0],
  1225. dwInCount,
  1226. pPage,
  1227. &dwFiltersAdded,
  1228. TRUE);
  1229. return(Status);
  1230. }
  1231. //
  1232. // now the output filters. This is a bit simpler since there
  1233. // are no global settings.
  1234. //
  1235. if(pFilterDescOut)
  1236. {
  1237. //
  1238. // Adding in filters. For each filter, process as
  1239. // needed. Input filters include the global checks
  1240. /// such as spoofing.
  1241. //
  1242. for(dwOutCount = 0;
  1243. dwOutCount < pFilterDescOut->dwNumFilters;
  1244. dwOutCount++)
  1245. {
  1246. PFILTER_INFOEX pFilt = &pFilterDescOut->fiFilter[dwOutCount];
  1247. BOOL bAdded;
  1248. //
  1249. // If a regular filter, add it. If a special, global
  1250. // filter, handle it specially.
  1251. //
  1252. if(pFilt->type == PFE_FILTER)
  1253. {
  1254. Status = AllocateAndAddFilterToMatchInterface(
  1255. Fcb,
  1256. pFilt,
  1257. FALSE,
  1258. pPage,
  1259. &bAdded,
  1260. &pPFilter);
  1261. if(!NT_SUCCESS(Status))
  1262. {
  1263. if((Status == STATUS_OBJECT_NAME_COLLISION)
  1264. &&
  1265. pPFilter)
  1266. {
  1267. if(!fCheckDups
  1268. ||
  1269. (pPFilter->dwFlags & FLAGS_INFOEX_ALLOWDUPS))
  1270. {
  1271. pPFilter->dwInUse++;
  1272. Status = STATUS_SUCCESS;
  1273. }
  1274. else
  1275. {
  1276. ERROR((
  1277. "IPFLTDRV: Adding out filter failed %x\n",
  1278. Status
  1279. ));
  1280. break;
  1281. }
  1282. }
  1283. else
  1284. {
  1285. break;
  1286. }
  1287. }
  1288. else if(bAdded && (pIf->eaOutAction == FORWARD))
  1289. {
  1290. dwFiltersAdded++;
  1291. }
  1292. }
  1293. else
  1294. {
  1295. ERROR(("IPFLTDRV: Ignoring global out filter\n"));
  1296. }
  1297. }
  1298. }
  1299. if(!NT_SUCCESS(Status))
  1300. {
  1301. RemoveFilterWorker(
  1302. Fcb,
  1303. &pFilterDescIn->fiFilter[0],
  1304. dwInCount,
  1305. pPage,
  1306. &dwFiltersAdded,
  1307. TRUE);
  1308. RemoveFilterWorker(
  1309. Fcb,
  1310. &pFilterDescOut->fiFilter[0],
  1311. dwOutCount,
  1312. pPage,
  1313. &dwFiltersAdded,
  1314. FALSE);
  1315. }
  1316. else if(dwFiltersAdded)
  1317. {
  1318. NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
  1319. }
  1320. return(Status);
  1321. }
  1322. NTSTATUS
  1323. UpdateBindingInformationEx(
  1324. PFILTER_DRIVER_BINDING_INFO pBindInfo,
  1325. PPAGED_FILTER_INTERFACE pPage)
  1326. /*++
  1327. Routine Description:
  1328. Just like the routine below. But this fixes up the
  1329. paged filters only
  1330. --*/
  1331. {
  1332. PPAGED_FILTER pf;
  1333. DWORD i;
  1334. if((pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD))
  1335. {
  1336. return(STATUS_INVALID_DEVICE_REQUEST);
  1337. }
  1338. pPage->dwUpdateEpoch++;
  1339. //
  1340. // update all filters on this paged interface
  1341. //
  1342. for(i = 0; i < g_dwHashLists; i++)
  1343. {
  1344. PLIST_ENTRY List = &pPage->HashList[i];
  1345. PLIST_ENTRY pList, NextListItem;
  1346. for(pList = List->Flink;
  1347. pList != List;
  1348. pList = NextListItem)
  1349. {
  1350. NextListItem = pList->Flink;
  1351. pf = CONTAINING_RECORD(pList, PAGED_FILTER, leHash);
  1352. if(pf->dwEpoch == pPage->dwUpdateEpoch)
  1353. {
  1354. break;
  1355. }
  1356. if(AreAllFieldsUnchanged(pf))
  1357. {
  1358. continue;
  1359. }
  1360. //
  1361. // it's to be changed. Take it off of its hash list
  1362. // so it can be rehashed when we are done
  1363. //
  1364. RemoveEntryList(&pf->leHash);
  1365. if(DoesSrcAddrUseLocalAddr(pf))
  1366. {
  1367. pf->SRC_ADDR = pBindInfo->dwLocalAddr;
  1368. }
  1369. else if(DoesSrcAddrUseRemoteAddr(pf))
  1370. {
  1371. pf->SRC_ADDR = pBindInfo->dwRemoteAddr;
  1372. }
  1373. if(DoesDstAddrUseLocalAddr(pf))
  1374. {
  1375. pf->DEST_ADDR = pBindInfo->dwLocalAddr;
  1376. }
  1377. else if(DoesDstAddrUseRemoteAddr(pf))
  1378. {
  1379. pf->DEST_ADDR = pBindInfo->dwRemoteAddr;
  1380. }
  1381. if(IsSrcMaskLateBound(pf))
  1382. {
  1383. pf->SRC_MASK = pBindInfo->dwMask;
  1384. }
  1385. if(IsDstMaskLateBound(pf))
  1386. {
  1387. pf->DEST_MASK = pBindInfo->dwMask;
  1388. }
  1389. pf->dwEpoch = pPage->dwUpdateEpoch;
  1390. //
  1391. // compute new hash index
  1392. //
  1393. pf->dwHashIndex = (
  1394. pf->SRC_ADDR +
  1395. pf->DEST_ADDR +
  1396. pf->DEST_ADDR +
  1397. PROTOCOLPART(pf->uliProtoSrcDstPort.LowPart) +
  1398. pf->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
  1399. InsertTailList(&pPage->HashList[pf->dwHashIndex],
  1400. &pf->leHash);
  1401. }
  1402. }
  1403. return(UpdateMatchBindingInformation(pBindInfo, (PVOID)pPage->pFilter));
  1404. }
  1405. VOID
  1406. UpdateLateBoundFilter(PFILTER pf,
  1407. DWORD dwLocalAddr,
  1408. DWORD dwRemoteAddr,
  1409. DWORD dwMask)
  1410. {
  1411. if(DoesSrcAddrUseLocalAddr(pf))
  1412. {
  1413. pf->SRC_ADDR = dwLocalAddr;
  1414. }
  1415. else if(DoesSrcAddrUseRemoteAddr(pf))
  1416. {
  1417. pf->SRC_ADDR = dwRemoteAddr;
  1418. }
  1419. if(DoesDstAddrUseLocalAddr(pf))
  1420. {
  1421. pf->DEST_ADDR = dwLocalAddr;
  1422. }
  1423. else if(DoesDstAddrUseRemoteAddr(pf))
  1424. {
  1425. pf->DEST_ADDR = dwRemoteAddr;
  1426. }
  1427. if(IsSrcMaskLateBound(pf))
  1428. {
  1429. pf->SRC_MASK = dwMask;
  1430. }
  1431. if(IsDstMaskLateBound(pf))
  1432. {
  1433. pf->DEST_MASK = dwMask;
  1434. }
  1435. }
  1436. NTSTATUS
  1437. UpdateMatchBindingInformation(
  1438. PFILTER_DRIVER_BINDING_INFO pBindInfo,
  1439. PVOID pvContext
  1440. )
  1441. /*++
  1442. Routine Description
  1443. Update the bindings for a new style interface
  1444. Arguments
  1445. pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
  1446. to router manager as a context for the interface
  1447. pInfo FILTER_IF structure filled in by driver
  1448. Return Value
  1449. --*/
  1450. {
  1451. PFILTER_INTERFACE pIf;
  1452. LOCK_STATE LockState;
  1453. PFILTER pf;
  1454. DWORD i;
  1455. DWORD dwX;
  1456. PLIST_ENTRY List, NextList;
  1457. pIf = (PFILTER_INTERFACE)pvContext;
  1458. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  1459. pIf->dwUpdateEpoch++;
  1460. for(i = 0; i < g_dwHashLists; i++)
  1461. {
  1462. for(List = pIf->HashList[i].Flink;
  1463. List != &pIf->HashList[i];
  1464. List = NextList)
  1465. {
  1466. pf = CONTAINING_RECORD(List, FILTER, pleHashList);
  1467. NextList = List->Flink;
  1468. if(pf->dwEpoch == pIf->dwUpdateEpoch)
  1469. {
  1470. break;
  1471. }
  1472. pf->dwEpoch = pIf->dwUpdateEpoch;
  1473. if(!AreAllFieldsUnchanged(pf))
  1474. {
  1475. BOOL fWild;
  1476. UpdateLateBoundFilter(pf,
  1477. pBindInfo->dwLocalAddr,
  1478. pBindInfo->dwRemoteAddr,
  1479. pBindInfo->dwMask);
  1480. dwX = ComputeMatchHashIndex(pf, &fWild);
  1481. RemoveEntryList(&pf->pleHashList);
  1482. InsertTailList(&pIf->HashList[dwX], &pf->pleHashList);
  1483. }
  1484. }
  1485. }
  1486. //
  1487. // finally the wild card filters
  1488. //
  1489. for(i = g_dwHashLists; i <= g_dwHashLists + 1; i++)
  1490. {
  1491. for(List = pIf->HashList[i].Flink;
  1492. List != &pIf->HashList[i];
  1493. List = List->Flink)
  1494. {
  1495. pf = CONTAINING_RECORD(List, FILTER, pleHashList);
  1496. if(pf->dwEpoch == pIf->dwUpdateEpoch)
  1497. {
  1498. break;
  1499. }
  1500. pf->dwEpoch = pIf->dwUpdateEpoch;
  1501. if(!AreAllFieldsUnchanged(pf))
  1502. {
  1503. UpdateLateBoundFilter(pf,
  1504. pBindInfo->dwLocalAddr,
  1505. pBindInfo->dwRemoteAddr,
  1506. pBindInfo->dwMask);
  1507. }
  1508. }
  1509. }
  1510. ClearCache();
  1511. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  1512. NotifyFastPathIf(pIf);
  1513. return STATUS_SUCCESS;
  1514. }
  1515. PFILTER_INTERFACE
  1516. NewInterface(
  1517. IN PVOID pvContext,
  1518. IN DWORD dwIndex,
  1519. IN FORWARD_ACTION inAction,
  1520. IN FORWARD_ACTION outAction,
  1521. IN PVOID pvOldInterfaceContext,
  1522. IN DWORD dwIpIndex,
  1523. IN DWORD dwName
  1524. )
  1525. /*++
  1526. Routine Description
  1527. Interface constructor
  1528. Arguments
  1529. pIf Pointer to interface
  1530. Return Value
  1531. --*/
  1532. {
  1533. PFILTER_INTERFACE pIf;
  1534. PAGED_CODE();
  1535. pIf = (PFILTER_INTERFACE)ExAllocatePoolWithTag(NonPagedPool,
  1536. FILTER_INTERFACE_SIZE,
  1537. '1liF');
  1538. if(pIf != NULL)
  1539. {
  1540. DWORD i;
  1541. RtlZeroMemory(pIf, sizeof(*pIf));
  1542. pIf->dwNumOutFilters = pIf->dwNumInFilters = 0;
  1543. pIf->pvRtrMgrContext = pvContext;
  1544. pIf->dwRtrMgrIndex = dwIndex;
  1545. pIf->eaInAction = inAction;
  1546. pIf->eaOutAction = outAction;
  1547. pIf->dwIpIndex = dwIpIndex;
  1548. pIf->dwLinkIpAddress = 0;
  1549. pIf->lInUse = 1;
  1550. pIf->lTotalInDrops = pIf->lTotalOutDrops = 0;
  1551. pIf->dwName = dwName;
  1552. pIf->dwUpdateEpoch = 0;
  1553. pIf->pvHandleContext = pvOldInterfaceContext;
  1554. InitializeListHead(&pIf->pleInFilterSet);
  1555. InitializeListHead(&pIf->pleOutFilterSet);
  1556. for(i = 0; i < FRAG_NUMBEROFENTRIES; i++)
  1557. {
  1558. InitializeListHead(&pIf->FragLists[i]);
  1559. }
  1560. for(i = 0; i <= (g_dwHashLists + 1); i++)
  1561. {
  1562. InitializeListHead(&pIf->HashList[i]);
  1563. }
  1564. }
  1565. return pIf;
  1566. }
  1567. VOID
  1568. DeleteFilterList(PLIST_ENTRY pList)
  1569. /*++
  1570. Routine Description
  1571. Free the list of filters given
  1572. --*/
  1573. {
  1574. while(!IsListEmpty(pList))
  1575. {
  1576. PLIST_ENTRY pEntry = RemoveHeadList(pList);
  1577. ExFreePool(pEntry);
  1578. }
  1579. }
  1580. VOID
  1581. ClearFragCache()
  1582. /*++
  1583. Routine Description
  1584. Clears the fragments cache
  1585. Arguments
  1586. None
  1587. Return Value
  1588. None
  1589. --*/
  1590. {
  1591. DWORD i;
  1592. KIRQL kiCurrIrql;
  1593. if (g_pleFragTable)
  1594. {
  1595. KeAcquireSpinLock(&g_kslFragLock, &kiCurrIrql);
  1596. for(i = 0; i < g_dwFragTableSize; i++)
  1597. {
  1598. PLIST_ENTRY pleNode;
  1599. pleNode = g_pleFragTable[i].Flink;
  1600. while(pleNode != &(g_pleFragTable[i]))
  1601. {
  1602. PFRAG_INFO pfiFragInfo;
  1603. pfiFragInfo = CONTAINING_RECORD(pleNode, FRAG_INFO, leCacheLink);
  1604. pleNode = pleNode->Flink;
  1605. RemoveEntryList(&(pfiFragInfo->leCacheLink));
  1606. ExFreeToNPagedLookasideList(
  1607. &g_llFragCacheBlocks,
  1608. pfiFragInfo);
  1609. }
  1610. }
  1611. KeReleaseSpinLock(&g_kslFragLock,
  1612. kiCurrIrql);
  1613. }
  1614. TRACE(FRAG,("IPFLTDRV: Frag cache cleanup Done\n"));
  1615. }
  1616. VOID
  1617. ClearCache()
  1618. /*++
  1619. Routine Description
  1620. Clears the input and output caches
  1621. Assumes that the write lock has been acquired (for the system)
  1622. Arguments
  1623. None
  1624. Return Value
  1625. None
  1626. --*/
  1627. {
  1628. DWORD i;
  1629. PLIST_ENTRY pleNode;
  1630. //
  1631. // This code assumes that the g_filter.pIn/OutCache is valid and that each of the
  1632. // pointers in the array are valid. If they are not, there is something seriously
  1633. // wrong and you would end up blue screening in someother part of the code anyways
  1634. //
  1635. TRACE(CACHE,("IPFLTDRV: Clearing in and out cache..."));
  1636. for(i = 0; i < g_dwCacheSize; i ++)
  1637. {
  1638. ClearInCacheEntry(g_filters.ppInCache[i]);
  1639. ClearOutCacheEntry(g_filters.ppOutCache[i]);
  1640. }
  1641. TRACE(CACHE,("IPFLTDRV: Done Clearing in and out cache\n"));
  1642. pleNode = g_freeInFilters.Flink;
  1643. TRACE(CACHE,("IPFLTDRV: Clearing in free list...\n"));
  1644. while(pleNode isnot &g_freeInFilters)
  1645. {
  1646. PFILTER_INCACHE pInCache;
  1647. pInCache = CONTAINING_RECORD(pleNode,FILTER_INCACHE,leFreeLink);
  1648. ClearInFreeEntry(pInCache);
  1649. pleNode = pleNode->Flink;
  1650. }
  1651. TRACE(CACHE,("IPFLTDRV: Done Clearing in free list\n"));
  1652. pleNode = g_freeOutFilters.Flink;
  1653. TRACE(CACHE,("IPFLTDRV: Clearing out free list...\n"));
  1654. while(pleNode isnot &g_freeOutFilters)
  1655. {
  1656. PFILTER_OUTCACHE pOutCache;
  1657. pOutCache = CONTAINING_RECORD(pleNode,FILTER_OUTCACHE,leFreeLink);
  1658. ClearOutFreeEntry(pOutCache);
  1659. pleNode = pleNode->Flink;
  1660. }
  1661. TRACE(CACHE,("IPFLTDRV: Done Clearing out free list\n"));
  1662. ClearFragCache();
  1663. CALLTRACE(("IPFLTDRV: ClearCache Done\n"));
  1664. return;
  1665. }
  1666. PRTR_TOC_ENTRY
  1667. GetPointerToTocEntry(
  1668. DWORD dwType,
  1669. PRTR_INFO_BLOCK_HEADER pInfoHdr
  1670. )
  1671. {
  1672. DWORD i;
  1673. PAGED_CODE();
  1674. if(!pInfoHdr)
  1675. {
  1676. return NULL;
  1677. }
  1678. for(i = 0; i < pInfoHdr->TocEntriesCount; i++)
  1679. {
  1680. if(pInfoHdr->TocEntry[i].InfoType is dwType)
  1681. {
  1682. return &(pInfoHdr->TocEntry[i]);
  1683. }
  1684. }
  1685. return NULL;
  1686. }
  1687. NTSTATUS
  1688. AddNewInterface(PPFINTERFACEPARAMETERS pInfo,
  1689. PPFFCB Fcb)
  1690. /*++
  1691. Routine Description:
  1692. Create a new interface for this handle. Also create or
  1693. merge with a common underlying interface.
  1694. --*/
  1695. {
  1696. PPAGED_FILTER_INTERFACE pgIf;
  1697. PPAGED_FILTER_INTERFACE pPaged;
  1698. DWORD dwBind = pInfo->dwBindingData;
  1699. NTSTATUS Status;
  1700. KPROCESSOR_MODE Mode;
  1701. DWORD i, dwName = 0;
  1702. PAGED_CODE();
  1703. if(Fcb->dwFlags & PF_FCB_OLD)
  1704. {
  1705. return(STATUS_INVALID_DEVICE_REQUEST);
  1706. }
  1707. Fcb->dwFlags |= PF_FCB_NEW;
  1708. Mode = ExGetPreviousMode();
  1709. //
  1710. // verify that this interface is unique on this handle.
  1711. //
  1712. switch(pInfo->pfbType)
  1713. {
  1714. default:
  1715. Status = STATUS_NO_SUCH_DEVICE;
  1716. break;
  1717. case PF_BIND_NONE:
  1718. dwBind = UNKNOWN_IP_INDEX;
  1719. Status = STATUS_SUCCESS;
  1720. break;
  1721. case PF_BIND_NAME:
  1722. dwName = dwBind;
  1723. dwBind = UNKNOWN_IP_INDEX;
  1724. Status = STATUS_SUCCESS;
  1725. break;
  1726. }
  1727. if(NT_SUCCESS(Status))
  1728. {
  1729. //
  1730. // it's not in use on this handle. So create an PAGED
  1731. // FCB to remember this and to link into a non-paged interface.
  1732. //
  1733. pPaged = ExAllocatePoolWithTag(PagedPool,
  1734. PAGED_INTERFACE_SIZE,
  1735. 'pfpI');
  1736. if(!pPaged)
  1737. {
  1738. return(STATUS_NO_MEMORY);
  1739. }
  1740. //
  1741. // fill in the paged filter definition and allocate
  1742. // a non-paged filter. The non-paged filter could already
  1743. // exist, in which case simply link this to the existing
  1744. // one.
  1745. if(pInfo->pfLogId)
  1746. {
  1747. //
  1748. // If a Log ID is given, reference the log to
  1749. // prevent it from going away
  1750. //
  1751. Status = ReferenceLogByHandleId(pInfo->pfLogId,
  1752. Fcb,
  1753. &pPaged->pLog);
  1754. if(!NT_SUCCESS(Status))
  1755. {
  1756. ExFreePool(pPaged);
  1757. return(Status);
  1758. }
  1759. }
  1760. else
  1761. {
  1762. pPaged->pLog = NULL;
  1763. }
  1764. pPaged->dwNumInFilters = pPaged->dwNumOutFilters = 0;
  1765. pPaged->eaInAction = pInfo->eaIn;
  1766. pPaged->eaOutAction = pInfo->eaOut;
  1767. pPaged->dwGlobalEnables = 0;
  1768. pPaged->pvRtrMgrContext = pInfo->fdInterface.pvRtrMgrContext;
  1769. pPaged->dwRtrMgrIndex = pInfo->fdInterface.dwIfIndex;
  1770. pPaged->dwUpdateEpoch = 0;
  1771. Status = CreateCommonInterface(pPaged,
  1772. dwBind,
  1773. dwName,
  1774. pInfo->dwInterfaceFlags);
  1775. if(!NT_SUCCESS(Status))
  1776. {
  1777. if(pPaged->pLog)
  1778. {
  1779. ERROR(("IPFLTDRV: CreateCommonInterface failed: DereferenceLog being called\n"));
  1780. DereferenceLog(pPaged->pLog);
  1781. }
  1782. ExFreePool(pPaged);
  1783. return(Status);
  1784. }
  1785. pPaged->pvDriverContext =
  1786. pInfo->fdInterface.pvDriverContext = (PVOID)pPaged;
  1787. InitializeListHead(&pPaged->leSpecialFilterList);
  1788. for(i = 0; i < 2 * g_dwHashLists; i++)
  1789. {
  1790. PLIST_ENTRY List = &pPaged->HashList[i];
  1791. InitializeListHead(List);
  1792. }
  1793. InsertTailList(&Fcb->leInterfaces, &pPaged->leIfLink);
  1794. }
  1795. return(Status);
  1796. }
  1797. BOOL
  1798. DereferenceFilterInterface(PFILTER_INTERFACE pIf, PPFLOGINTERFACE pLog)
  1799. /*++
  1800. Routine Description:
  1801. Nonpaged routine to dereference a match interface. If the
  1802. reference count goes to zero, free the interface
  1803. --*/
  1804. {
  1805. LOCK_STATE LockState, LockState2;
  1806. BOOL fRel = FALSE;
  1807. //
  1808. // lock the resource that protects adding new interfaces. This
  1809. // is needed to hold off others until everything is properly
  1810. // verified. The spin lock is insufficient for this.
  1811. //
  1812. KeEnterCriticalRegion();
  1813. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  1814. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  1815. if(--pIf->lInUse == 0)
  1816. {
  1817. RemoveEntryList(&pIf->leIfLink);
  1818. if(pIf->dwIpIndex != UNKNOWN_IP_INDEX)
  1819. {
  1820. InterlockedCleanCache(g_filters.pInterfaceCache, pIf->dwIpIndex, pIf->dwLinkIpAddress);
  1821. InterlockedDecrement(&g_ulBoundInterfaceCount);
  1822. TRACE(CONFIG,(
  1823. "IPFLTDRV: UnBound Interface Index=%d, Link=%d, TotalCnt=%d\n",
  1824. pIf->dwIpIndex,
  1825. pIf->dwLinkIpAddress,
  1826. g_ulBoundInterfaceCount
  1827. ));
  1828. }
  1829. fRel = TRUE;
  1830. }
  1831. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  1832. if(fRel)
  1833. {
  1834. //
  1835. // Getting rid of it
  1836. //
  1837. if(pIf->dwIpIndex != UNKNOWN_IP_INDEX)
  1838. {
  1839. DWORD dwIndex = pIf->dwIpIndex;
  1840. pIf->dwIpIndex = UNKNOWN_IP_INDEX;
  1841. NotifyFastPath(pIf, dwIndex, NOT_UNBIND);
  1842. }
  1843. AcquireWriteLock(&g_filters.ifListLock,&LockState2);
  1844. ClearCache();
  1845. ReleaseWriteLock(&g_filters.ifListLock,&LockState2);
  1846. if(pIf->pLog)
  1847. {
  1848. DereferenceLog(pIf->pLog);
  1849. }
  1850. ExFreePool(pIf);
  1851. }
  1852. else if(pLog)
  1853. {
  1854. //
  1855. // this deref owns the log. So take the log off of the
  1856. // the interface. Note it may be true that the match interface
  1857. // has a different log than the paged interface. This will
  1858. // happen if the log is closed while it exists on the interface.
  1859. // In such a case, the log is removed from the match interface
  1860. // but not the paged interface. And when the paged interface
  1861. // is closed, as is happening now, the log it has is incorrect.
  1862. // So this check is required.
  1863. // The FilterListResourceLock serializes all of this ...
  1864. //
  1865. if(pLog == pIf->pLog)
  1866. {
  1867. AcquireWriteLock(&g_filters.ifListLock,&LockState2);
  1868. pIf->pLog = 0;
  1869. ReleaseWriteLock(&g_filters.ifListLock,&LockState2);
  1870. DereferenceLog(pLog);
  1871. }
  1872. }
  1873. ExReleaseResourceLite(&FilterListResourceLock);
  1874. KeLeaveCriticalRegion();
  1875. return(fRel);
  1876. }
  1877. NTSTATUS
  1878. CreateCommonInterface(PPAGED_FILTER_INTERFACE pPage,
  1879. DWORD dwBind,
  1880. DWORD dwName,
  1881. DWORD dwFlags)
  1882. /*++
  1883. Routine Description:
  1884. Non-paged routine called by AddNewInterface to bind the
  1885. paged interface to an underlying interface, and to bind
  1886. that to a stack interface. The caller should have
  1887. verified that dwBind is a valid stack interface.
  1888. --*/
  1889. {
  1890. PFILTER_INTERFACE pIf, pIf1;
  1891. LOCK_STATE LockState;
  1892. NTSTATUS Status = STATUS_SUCCESS;
  1893. PPFLOGINTERFACE pLog = pPage->pLog;
  1894. pIf = NewInterface(pPage->pvRtrMgrContext,
  1895. pPage->dwRtrMgrIndex,
  1896. pPage->eaInAction,
  1897. pPage->eaOutAction,
  1898. 0,
  1899. dwBind,
  1900. dwName);
  1901. if(pIf == NULL)
  1902. {
  1903. return STATUS_NO_MEMORY;
  1904. }
  1905. if(dwFlags & PFSET_FLAGS_UNIQUE)
  1906. {
  1907. pIf->dwGlobalEnables |= FI_ENABLE_UNIQUE;
  1908. }
  1909. //
  1910. // lock the resource that protects adding new interfaces. This
  1911. // is needed to hold off others until everything is properly
  1912. // verified. The spin lock is insufficient for this.
  1913. //
  1914. KeEnterCriticalRegion();
  1915. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  1916. //
  1917. // Now reconcile the binding. Note that we had to make the interface
  1918. // first in order to prevent a race with another process trying
  1919. // to bind to the same stack interface.
  1920. //
  1921. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  1922. if((dwBind != UNKNOWN_IP_INDEX)
  1923. ||
  1924. dwName)
  1925. {
  1926. pIf1 = FindMatchName(dwName, dwBind);
  1927. if(pIf1)
  1928. {
  1929. // found it. Make sure it agrees. If so,
  1930. // refcount it and use it
  1931. //
  1932. if(!(pIf->dwGlobalEnables & FI_ENABLE_OLD)
  1933. &&
  1934. (pIf->eaInAction == pIf1->eaInAction)
  1935. &&
  1936. (pIf->eaOutAction == pIf1->eaOutAction)
  1937. &&
  1938. !(pIf->dwGlobalEnables & FI_ENABLE_UNIQUE)
  1939. &&
  1940. !(pIf1->dwGlobalEnables & FI_ENABLE_UNIQUE)
  1941. )
  1942. {
  1943. pIf1->lInUse++;
  1944. }
  1945. else
  1946. {
  1947. //
  1948. // mismatch. Can't do it
  1949. //
  1950. Status = STATUS_INVALID_PARAMETER;
  1951. }
  1952. }
  1953. }
  1954. else
  1955. {
  1956. pIf1 = 0;
  1957. }
  1958. if(!pIf1)
  1959. {
  1960. InsertTailList(&g_filters.leIfListHead,&pIf->leIfLink);
  1961. }
  1962. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  1963. if(pIf1)
  1964. {
  1965. //
  1966. // If log is specifed but log alreadye exists, error.
  1967. //
  1968. ExFreePool(pIf);
  1969. if(NT_SUCCESS(Status))
  1970. {
  1971. pPage->pFilter = pIf1;
  1972. if(pIf1->pLog)
  1973. {
  1974. if(pPage->pLog)
  1975. {
  1976. //
  1977. // the interface already has a log. In prinicple
  1978. // this should call DereferenceFilterInterface but
  1979. // this will do and it's faster.
  1980. //
  1981. Status = STATUS_DEVICE_BUSY;
  1982. pIf1->lInUse--;
  1983. }
  1984. }
  1985. else if(pPage->pLog)
  1986. {
  1987. //
  1988. // see comment below about log referencing
  1989. //
  1990. AddRefToLog(pIf1->pLog = pPage->pLog);
  1991. }
  1992. }
  1993. ExReleaseResourceLite(&FilterListResourceLock);
  1994. KeLeaveCriticalRegion();
  1995. return(Status);
  1996. }
  1997. NotifyFastPathIf(pIf);
  1998. pPage->pFilter = pIf;
  1999. if(pPage->pLog)
  2000. {
  2001. //
  2002. // Reference the log. Need this since the
  2003. // paged interface can be deleted before the
  2004. // match interface, so each must apply a reference.
  2005. // Actually, only the match needs to do it, but
  2006. // the way the log works, the paged interface already
  2007. // got a reference, so just do it this way.
  2008. // N.B. The single = is intentional
  2009. //
  2010. AddRefToLog(pIf->pLog = pPage->pLog);
  2011. }
  2012. ExReleaseResourceLite(&FilterListResourceLock);
  2013. KeLeaveCriticalRegion();
  2014. return(Status);
  2015. }
  2016. VOID
  2017. MakeFilterInfo(IN PPAGED_FILTER pPage,
  2018. IN PFILTER_INFOEX pInfo,
  2019. IN DWORD dwFlags)
  2020. {
  2021. PFILTER_INFO2 pFilterInfo = &pInfo->info;
  2022. if(pInfo->type != PFE_FILTER)
  2023. {
  2024. //
  2025. // a special filter.
  2026. //
  2027. memset(pPage, 0, sizeof(*pPage));
  2028. pPage->type = pInfo->type;
  2029. pPage->fLateBound = pInfo->dwFlags;
  2030. pPage->dwInUse = 1;
  2031. return;
  2032. }
  2033. pPage->type = pInfo->type;
  2034. pPage->SRC_ADDR = pFilterInfo->dwaSrcAddr[0];
  2035. pPage->DEST_ADDR = pFilterInfo->dwaDstAddr[0];
  2036. pPage->SRC_MASK = pFilterInfo->dwaSrcMask[0];
  2037. pPage->DEST_MASK = pFilterInfo->dwaDstMask[0];
  2038. pPage->fLateBound = pFilterInfo->fLateBound;
  2039. pPage->wSrcPortHigh = pPage->wDstPortHigh = 0;
  2040. pPage->dwFlags = dwFlags;
  2041. pPage->dwInUse = 1;
  2042. if(pPage->SRC_MASK != INADDR_SPECIFIC)
  2043. {
  2044. pPage->dwFlags |= FILTER_FLAGS_SRCWILD;
  2045. }
  2046. if(pPage->DEST_MASK != INADDR_SPECIFIC)
  2047. {
  2048. pPage->dwFlags |= FILTER_FLAGS_DSTWILD;
  2049. }
  2050. //
  2051. // Now the network ordering stuff - tricky part
  2052. // LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
  2053. // Proto 00 00 00 SrcPort DstPort
  2054. //
  2055. //
  2056. // For addresses, ANY_ADDR is given by 0.0.0.0 and the MASK must be 0.0.0.0
  2057. // For proto and ports 0 means any and the mask is generated as follows
  2058. // If the proto is O then LP0 for Mask is 0xff else its 0x00
  2059. // If a port is 0, the corresponding XP0XP1 is 0x0000 else its 0xffff
  2060. //
  2061. //
  2062. // ICMP:
  2063. // LP0 LP1 LP2 LP3 HP0 HP1 HP2 HP3
  2064. // 0x1 00 00 00 Typ Cod 00 00
  2065. // ICMP is different since 0 is a valid code and type, so 0xff is used by the
  2066. // user to signify that ANY code or type is to be matched. However to do this
  2067. // we need to have the field set to zero and the the mask set to 00 (for any).
  2068. // But if the filter is specifically for Type/Code = 0 then the field is zero
  2069. // with the mask as 0xff
  2070. //
  2071. //
  2072. // The protocol is in the low byte of the dwProtocol, so we take that out and
  2073. // make a dword out of it
  2074. //
  2075. pPage->uliProtoSrcDstPort.LowPart =
  2076. MAKELONG(MAKEWORD(LOBYTE(LOWORD(pFilterInfo->dwProtocol)),0x00),0x0000);
  2077. pPage->uliProtoSrcDstMask.LowPart = MAKELONG(MAKEWORD(0xff,0x00),0x0000);
  2078. switch(pFilterInfo->dwProtocol)
  2079. {
  2080. case FILTER_PROTO_ANY:
  2081. {
  2082. pPage->uliProtoSrcDstPort.HighPart = 0x00000000;
  2083. pPage->uliProtoSrcDstMask.LowPart = 0x00000000;
  2084. pPage->uliProtoSrcDstMask.HighPart = 0x00000000;
  2085. pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
  2086. break;
  2087. }
  2088. case FILTER_PROTO_ICMP:
  2089. {
  2090. WORD wTypeCode = 0x0000;
  2091. WORD wTypeCodeMask = 0x0000;
  2092. //
  2093. // For ICMP, the "ports" occupy the same place as the
  2094. // source port for TCP/UDP. So a wild card in here
  2095. // can never produce a FILTER_FLAGS_DSTWILD but we assume
  2096. // it does. This will put all wild ICMP filters into
  2097. // the default bucket. This seems OK since the performance
  2098. // for matching these is not critical.
  2099. //
  2100. if((BYTE)(pFilterInfo->wSrcPort) != FILTER_ICMP_TYPE_ANY)
  2101. {
  2102. wTypeCode |= MAKEWORD((BYTE)(pFilterInfo->wSrcPort),0x00);
  2103. wTypeCodeMask |= MAKEWORD(0xff,0x00);
  2104. }
  2105. else
  2106. {
  2107. pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
  2108. }
  2109. if((BYTE)(pFilterInfo->wDstPort) != FILTER_ICMP_CODE_ANY)
  2110. {
  2111. wTypeCode |= MAKEWORD(0x00,(BYTE)(pFilterInfo->wDstPort));
  2112. wTypeCodeMask |= MAKEWORD(0x00,0xff);
  2113. }
  2114. else
  2115. {
  2116. pPage->dwFlags |= FILTER_FLAGS_SRCWILD | FILTER_FLAGS_DSTWILD;
  2117. }
  2118. pPage->uliProtoSrcDstPort.HighPart =
  2119. MAKELONG(wTypeCode,0x0000);
  2120. pPage->uliProtoSrcDstMask.HighPart =
  2121. MAKELONG(wTypeCodeMask,0x0000);
  2122. break;
  2123. }
  2124. case FILTER_PROTO_TCP:
  2125. //
  2126. // if no connections allowed, set the ESTAB_MASK
  2127. // value in the comparison mask
  2128. //
  2129. if(pInfo->dwFlags & FLAGS_INFOEX_NOSYN)
  2130. {
  2131. pPage->uliProtoSrcDstMask.LowPart |=
  2132. MAKELONG(MAKEWORD(0,ESTAB_MASK),0x0000);
  2133. pPage->uliProtoSrcDstPort.LowPart |=
  2134. MAKELONG(MAKEWORD(0,ESTAB_MASK),0x0000);
  2135. }
  2136. //
  2137. // fall through
  2138. //
  2139. case FILTER_PROTO_UDP:
  2140. {
  2141. DWORD dwSrcDstPort = 0x00000000;
  2142. DWORD dwSrcDstMask = 0x00000000;
  2143. if(pFilterInfo->wSrcPort != FILTER_TCPUDP_PORT_ANY)
  2144. {
  2145. dwSrcDstPort |= MAKELONG(pFilterInfo->wSrcPort,0x0000);
  2146. if(pFilterInfo->wSrcPortHigh)
  2147. {
  2148. pPage->wSrcPortHigh = pFilterInfo->wSrcPortHigh;
  2149. pPage->dwFlags |=
  2150. (FILTER_FLAGS_PORTWILD | FILTER_FLAGS_SRCWILD);
  2151. }
  2152. else
  2153. {
  2154. dwSrcDstMask |= MAKELONG(0xffff,0x0000);
  2155. }
  2156. }
  2157. else
  2158. {
  2159. pPage->dwFlags |= FILTER_FLAGS_SRCWILD;
  2160. }
  2161. if(pFilterInfo->wDstPort != FILTER_TCPUDP_PORT_ANY)
  2162. {
  2163. dwSrcDstPort |= MAKELONG(0x0000,pFilterInfo->wDstPort);
  2164. if(pFilterInfo->wDstPortHigh)
  2165. {
  2166. pPage->wDstPortHigh = pFilterInfo->wDstPortHigh;
  2167. pPage->dwFlags |=
  2168. (FILTER_FLAGS_PORTWILD | FILTER_FLAGS_DSTWILD);
  2169. }
  2170. else
  2171. {
  2172. dwSrcDstMask |= MAKELONG(0x0000,0xffff);
  2173. }
  2174. }
  2175. else
  2176. {
  2177. pPage->dwFlags |= FILTER_FLAGS_DSTWILD;
  2178. }
  2179. pPage->uliProtoSrcDstPort.HighPart = dwSrcDstPort;
  2180. pPage->uliProtoSrcDstMask.HighPart = dwSrcDstMask;
  2181. break;
  2182. }
  2183. default:
  2184. {
  2185. //
  2186. // All other protocols have no use for the port field
  2187. //
  2188. pPage->uliProtoSrcDstPort.HighPart = 0x00000000;
  2189. pPage->uliProtoSrcDstMask.HighPart = 0x00000000;
  2190. }
  2191. }
  2192. //
  2193. // compute the hash index
  2194. //
  2195. pPage->dwHashIndex = (
  2196. pPage->SRC_ADDR +
  2197. pPage->DEST_ADDR +
  2198. pPage->DEST_ADDR +
  2199. PROTOCOLPART(pPage->uliProtoSrcDstPort.LowPart) +
  2200. pPage->uliProtoSrcDstPort.HighPart) % g_dwHashLists;
  2201. }
  2202. PPAGED_FILTER
  2203. MakePagedFilter(
  2204. IN PPFFCB Fcb,
  2205. IN PFILTER_INFOEX pInfo,
  2206. IN DWORD dwEpoch,
  2207. IN DWORD dwFlags
  2208. )
  2209. /*++
  2210. Routine Description
  2211. Arguments
  2212. Return Value
  2213. --*/
  2214. {
  2215. PPAGED_FILTER pPage;
  2216. PFILTER_INFO2 pFilterInfo = &pInfo->info;
  2217. PAGED_CODE();
  2218. //
  2219. // Allocate memory for the filters
  2220. //
  2221. pPage = (PPAGED_FILTER)ExAllocateFromPagedLookasideList(&paged_slist);
  2222. if(!pPage)
  2223. {
  2224. ERROR(("IPFLTDRV: Couldnt allocate memory for paged filter set\n"));
  2225. return NULL;
  2226. }
  2227. pPage->pFilters = NULL;
  2228. MakeFilterInfo(pPage, pInfo, dwFlags);
  2229. pPage->dwEpoch = dwEpoch;
  2230. return pPage;
  2231. }
  2232. NTSTATUS
  2233. AllocateAndAddFilterToMatchInterface(
  2234. PPFFCB Fcb,
  2235. PFILTER_INFOEX pInfo,
  2236. BOOL fInFilter,
  2237. PPAGED_FILTER_INTERFACE pPage,
  2238. PBOOL pbAdded,
  2239. PPAGED_FILTER * ppFilter)
  2240. /*++
  2241. Routine Description:
  2242. Check if this filter is already on the handle. If not
  2243. allocate a handle fitler and add it to the match
  2244. interface. Note the handle filter is not added to
  2245. the handle. This is so the caller can easily back out
  2246. if something fails.
  2247. Returns: STATUS_SUCCESS if all is well. ppFilter is either NULL
  2248. or contains the new filter.
  2249. --*/
  2250. {
  2251. PPAGED_FILTER pPageFilter, pPage1;
  2252. PFILTER pMatch, pMatch1;
  2253. DWORD dwFlags = (fInFilter ? FILTER_FLAGS_INFILTER : 0);
  2254. DWORD dwAdd;
  2255. PAGED_CODE();
  2256. //
  2257. // Make a paged filter so we can figure out whether
  2258. // it exists yet.
  2259. //
  2260. pPageFilter = MakePagedFilter(
  2261. Fcb,
  2262. pInfo,
  2263. pPage->dwUpdateEpoch,
  2264. dwFlags);
  2265. if(!pPageFilter)
  2266. {
  2267. return STATUS_NO_MEMORY;
  2268. }
  2269. if(pPage1 = IsOnPagedInterface(pPageFilter, pPage))
  2270. {
  2271. {
  2272. //
  2273. // it already exists. So return the existing one
  2274. // and also the handle
  2275. //
  2276. ExFreeToPagedLookasideList(&paged_slist,
  2277. (PVOID)pPageFilter);
  2278. *ppFilter = pPage1;
  2279. pInfo->pvFilterHandle = (PVOID)pPage1;
  2280. return(STATUS_OBJECT_NAME_COLLISION);
  2281. }
  2282. }
  2283. //
  2284. // See if we should check out the address.
  2285. //
  2286. if(!(pInfo->dwFlags & FLAGS_INFOEX_ALLOWANYREMOTEADDRESS))
  2287. {
  2288. if(pPageFilter->dwFlags & FILTER_FLAGS_INFILTER)
  2289. {
  2290. if(pPageFilter->SRC_MASK != INADDR_SPECIFIC)
  2291. {
  2292. dwAdd = 0;
  2293. }
  2294. else
  2295. {
  2296. dwAdd = pPageFilter->SRC_ADDR;
  2297. }
  2298. }
  2299. else if(pPageFilter->DEST_MASK != INADDR_SPECIFIC)
  2300. {
  2301. dwAdd = 0;
  2302. }
  2303. else
  2304. {
  2305. dwAdd = pPageFilter->DEST_ADDR;
  2306. }
  2307. //
  2308. // see if address checking should be done. It is done if an
  2309. // address is specified and the filter does not indicate the
  2310. // address is late bound. If it is late bound, just allow it
  2311. // since it may change
  2312. //
  2313. if(dwAdd)
  2314. {
  2315. NTSTATUS Status;
  2316. if(!BMAddress(dwAdd))
  2317. {
  2318. Status = CheckFilterAddress(dwAdd, pPage->pFilter);
  2319. if(!NT_SUCCESS(Status))
  2320. {
  2321. ExFreeToPagedLookasideList(&paged_slist,
  2322. (PVOID)pPageFilter);
  2323. return(Status);
  2324. }
  2325. }
  2326. }
  2327. }
  2328. else
  2329. {
  2330. TRACE(CONFIG,("IPFLTDRV: Allow any address is filter\n"));
  2331. }
  2332. if(!(pInfo->dwFlags & FLAGS_INFOEX_ALLOWANYLOCALADDRESS))
  2333. {
  2334. if(pPageFilter->dwFlags & FILTER_FLAGS_INFILTER)
  2335. {
  2336. if(pPageFilter->DEST_MASK != INADDR_SPECIFIC)
  2337. {
  2338. dwAdd = 0;
  2339. }
  2340. else
  2341. {
  2342. dwAdd = pPageFilter->DEST_ADDR;
  2343. }
  2344. }
  2345. else if(pPageFilter->SRC_MASK != INADDR_SPECIFIC)
  2346. {
  2347. dwAdd = 0;
  2348. }
  2349. else
  2350. {
  2351. dwAdd = pPageFilter->SRC_ADDR;
  2352. }
  2353. if(dwAdd)
  2354. {
  2355. if(pPage->pFilter->dwIpIndex != UNKNOWN_IP_INDEX)
  2356. {
  2357. if(!BMAddress(dwAdd) &&
  2358. (GetIpStackIndex(dwAdd, FALSE) != pPage->pFilter->dwIpIndex))
  2359. {
  2360. ExFreeToPagedLookasideList(&paged_slist,
  2361. (PVOID)pPageFilter);
  2362. return(STATUS_INVALID_ADDRESS);
  2363. }
  2364. }
  2365. }
  2366. }
  2367. //
  2368. // Not on the handle. Assume we need to add a new filter
  2369. // to the match interface. Allocate memory for this filter if
  2370. // necessary
  2371. //
  2372. pMatch = (PFILTER)ExAllocateFromNPagedLookasideList(
  2373. &filter_slist);
  2374. if(!pMatch)
  2375. {
  2376. ExFreePool(pPageFilter);
  2377. return(STATUS_NO_MEMORY);
  2378. }
  2379. pInfo->pvFilterHandle = (PVOID)pPageFilter;
  2380. //
  2381. // We will keep this filter so add it to the hash list
  2382. //
  2383. InsertTailList(&(pPage->HashList[pPageFilter->dwHashIndex]),
  2384. &pPageFilter->leHash);
  2385. //
  2386. // Now add it to the handle hash list
  2387. //
  2388. InsertTailList(&(pPage->HandleHash((UINT_PTR)pPageFilter & HANDLE_HASH_SIZE)),
  2389. &pPageFilter->leHandleHash);
  2390. //
  2391. // fix up the match interface
  2392. //
  2393. pMatch->uliSrcDstAddr = pPageFilter->uliSrcDstAddr;
  2394. pMatch->uliSrcDstMask = pPageFilter->uliSrcDstMask;
  2395. pMatch->uliProtoSrcDstPort = pPageFilter->uliProtoSrcDstPort;
  2396. pMatch->uliProtoSrcDstMask = pPageFilter->uliProtoSrcDstMask;
  2397. pMatch->fLateBound = pPageFilter->fLateBound;
  2398. pMatch->wSrcPortHigh = pPageFilter->wSrcPortHigh;
  2399. pMatch->wDstPortHigh = pPageFilter->wDstPortHigh;
  2400. pMatch->Count.lCount = 0;
  2401. pMatch->dwFlags = pPageFilter->dwFlags;
  2402. pMatch->dwFlags |= (pInfo->dwFlags & FLAGS_INFOEX_ALLFLAGS);
  2403. pMatch->dwFilterRule = pInfo->dwFilterRule;
  2404. pMatch->Count.lInUse = 0;
  2405. AddFilterToInterface(
  2406. pMatch,
  2407. pPage->pFilter,
  2408. fInFilter,
  2409. &pMatch1);
  2410. if(pMatch1)
  2411. {
  2412. //
  2413. // the filter already exists. Don't need the one we built
  2414. //
  2415. ExFreePool(pMatch);
  2416. pMatch = pMatch1;
  2417. *pbAdded = FALSE;
  2418. }
  2419. else
  2420. {
  2421. *pbAdded = TRUE;
  2422. }
  2423. pPageFilter->pMatchFilter = pMatch;
  2424. *ppFilter = pPageFilter;
  2425. return(STATUS_SUCCESS);
  2426. }
  2427. VOID
  2428. AddFilterToInterface(
  2429. PFILTER pFilter,
  2430. PFILTER_INTERFACE pIf,
  2431. BOOL fInFilter,
  2432. PFILTER * ppFilter)
  2433. /*++
  2434. Routine Description:
  2435. Add pFilter to the interface. If it already exists,
  2436. just refcount it and return the address of the
  2437. existing filter.
  2438. --*/
  2439. {
  2440. PFILTER pTemp;
  2441. LOCK_STATE LockState;
  2442. PLIST_ENTRY List, pList;
  2443. PDWORD pdwCount;
  2444. DWORD dwIndex;
  2445. DWORD dwType = pFilter->dwFlags & FILTER_FLAGS_INFILTER;
  2446. BOOL fWild;
  2447. *ppFilter = NULL;
  2448. dwIndex = ComputeMatchHashIndex(pFilter, &fWild);
  2449. if(fInFilter)
  2450. {
  2451. pList = &pIf->pleInFilterSet;
  2452. pdwCount = &pIf->dwNumInFilters;
  2453. }
  2454. else
  2455. {
  2456. pList = &pIf->pleOutFilterSet;
  2457. pdwCount = &pIf->dwNumOutFilters;
  2458. }
  2459. //
  2460. // lock up the filters
  2461. //
  2462. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  2463. for(List = pIf->HashList[dwIndex].Flink;
  2464. List != &pIf->HashList[dwIndex];
  2465. List = List->Flink)
  2466. {
  2467. pTemp = CONTAINING_RECORD(List, FILTER, pleHashList);
  2468. if((dwType == (pTemp->dwFlags & FILTER_FLAGS_INFILTER))
  2469. &&
  2470. (pTemp->uliSrcDstAddr.QuadPart == pFilter->uliSrcDstAddr.QuadPart)
  2471. &&
  2472. (pTemp->uliSrcDstMask.QuadPart == pFilter->uliSrcDstMask.QuadPart)
  2473. &&
  2474. (pTemp->uliProtoSrcDstPort.QuadPart == pFilter->uliProtoSrcDstPort.QuadPart)
  2475. &&
  2476. (pTemp->uliProtoSrcDstMask.QuadPart == pFilter->uliProtoSrcDstMask.QuadPart)
  2477. &&
  2478. (pTemp->wSrcPortHigh == pFilter->wSrcPortHigh)
  2479. &&
  2480. (pTemp->wDstPortHigh == pFilter->wDstPortHigh)
  2481. )
  2482. {
  2483. pFilter = *ppFilter = pTemp;
  2484. break;
  2485. }
  2486. }
  2487. if(!*ppFilter)
  2488. {
  2489. //
  2490. // a new filter. Add it to the interface. First flush incorrect cache
  2491. // entries.
  2492. //
  2493. if(ANYWILDFILTER(pFilter))
  2494. {
  2495. //
  2496. // wild card filters can cause cache entries almost anywhere
  2497. // in the table. Very nasty. So take the draconian step of
  2498. // deleting the entire cache.
  2499. //
  2500. ClearCache();
  2501. }
  2502. else
  2503. {
  2504. ClearCacheEntry(pFilter, pIf);
  2505. }
  2506. pFilter->dwEpoch = pIf->dwUpdateEpoch;
  2507. InsertTailList(pList, &pFilter->pleFilters);
  2508. //
  2509. // and add it to the proper fragment list
  2510. //
  2511. #if DOFRAGCHECKING
  2512. InsertTailList(
  2513. &pIf->FragLists[GetFragIndex(PROTOCOLPART(pFilter->PROTO))],
  2514. &pFilter->leFragList);
  2515. #endif
  2516. *pdwCount+= 1;
  2517. #if WILDHASH
  2518. if(fWild)
  2519. {
  2520. //
  2521. // if a wild filter of some sort, insert at the tail
  2522. // keeping specific filters ahead of wild filters
  2523. //
  2524. InsertTailList((&pIf->HashList[dwIndex]), &pFilter->pleHashList);
  2525. pIf->dwWilds++;
  2526. }
  2527. else
  2528. #endif
  2529. {
  2530. //
  2531. // insert at the head on the assumption this filter will
  2532. // be used soon and existing filters already have been
  2533. // used to produce a valid packet cache entry
  2534. //
  2535. InsertHeadList((&pIf->HashList[dwIndex]), &pFilter->pleHashList);
  2536. }
  2537. }
  2538. pFilter->Count.lInUse++;
  2539. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  2540. }
  2541. BOOL
  2542. DereferenceFilter(PFILTER pFilt, PFILTER_INTERFACE pIf)
  2543. /*++
  2544. Routine Description:
  2545. Dereference a filter and if it has no more referents, free it.
  2546. Returns TRUE if the filter was freed, FALSE otherwise.
  2547. --*/
  2548. {
  2549. LOCK_STATE LockState;
  2550. BOOL fFreed = FALSE;
  2551. //
  2552. // lock up the filters
  2553. //
  2554. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  2555. //
  2556. // Decrement reference count. If new count is 0, remove
  2557. // the entry but defer freeing the memory until the
  2558. // spin lock is released
  2559. //
  2560. if(--pFilt->Count.lInUse == 0)
  2561. {
  2562. TRACE(FLDES, ("IPFLTDRV: Deleting a filter: "));
  2563. TRACE_FILTER_DESCRIPTION(pFilt);
  2564. RemoveEntryList(&pFilt->pleFilters);
  2565. RemoveEntryList(&pFilt->pleHashList);
  2566. #if DOFRAGCHECKING
  2567. RemoveEntryList(&pFilt->leFragList);
  2568. #endif
  2569. if(pFilt->dwFlags & FILTER_FLAGS_INFILTER)
  2570. {
  2571. pIf->dwNumInFilters--;
  2572. }
  2573. else
  2574. {
  2575. pIf->dwNumOutFilters--;
  2576. pIf->lEpoch++;
  2577. }
  2578. if(ANYWILDFILTER(pFilt))
  2579. {
  2580. //
  2581. // wild card filters can cause cache entries almost anywhere
  2582. // in the table. Very nasty.
  2583. //
  2584. #if WILDHASH
  2585. if(!WildFilter(pFilt))
  2586. {
  2587. pIf->dwWilds--;
  2588. }
  2589. #endif
  2590. ClearAnyCacheEntry(pFilt, pIf);
  2591. }
  2592. else
  2593. {
  2594. ClearCacheEntry(pFilt, pIf);
  2595. }
  2596. fFreed = TRUE;
  2597. }
  2598. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  2599. if(fFreed)
  2600. {
  2601. ExFreeToNPagedLookasideList(
  2602. &filter_slist,
  2603. (PVOID)pFilt);
  2604. }
  2605. return(fFreed);
  2606. }
  2607. PPAGED_FILTER
  2608. IsOnPagedInterface(PPAGED_FILTER pPageFilter,
  2609. PPAGED_FILTER_INTERFACE pPage)
  2610. {
  2611. PPAGED_FILTER pPage1;
  2612. PLIST_ENTRY List = &pPage->HashList[pPageFilter->dwHashIndex];
  2613. PLIST_ENTRY pEntry;
  2614. DWORD dwFlags = pPageFilter->dwFlags & FILTER_FLAGS_INFILTER;
  2615. PAGED_CODE();
  2616. for(pEntry = List->Flink;
  2617. pEntry != List;
  2618. pEntry = pEntry->Flink)
  2619. {
  2620. pPage1 = CONTAINING_RECORD(pEntry, PAGED_FILTER, leHash);
  2621. if((dwFlags == (pPage1->dwFlags & FILTER_FLAGS_INFILTER))
  2622. &&
  2623. (pPage1->uliSrcDstAddr.QuadPart == pPageFilter->uliSrcDstAddr.QuadPart)
  2624. &&
  2625. (pPage1->uliSrcDstMask.QuadPart == pPageFilter->uliSrcDstMask.QuadPart)
  2626. &&
  2627. (pPage1->uliProtoSrcDstPort.QuadPart == pPageFilter->uliProtoSrcDstPort.QuadPart)
  2628. &&
  2629. (pPage1->uliProtoSrcDstMask.QuadPart == pPageFilter->uliProtoSrcDstMask.QuadPart)
  2630. &&
  2631. (pPage1->wSrcPortHigh == pPageFilter->wSrcPortHigh)
  2632. &&
  2633. (pPage1->wDstPortHigh == pPageFilter->wDstPortHigh)
  2634. )
  2635. {
  2636. return(pPage1);
  2637. }
  2638. }
  2639. return(NULL);
  2640. }
  2641. BOOL
  2642. IsOnSpecialFilterList(PPAGED_FILTER pPageFilter,
  2643. PLIST_ENTRY List,
  2644. PPAGED_FILTER * pPageHit)
  2645. {
  2646. PPAGED_FILTER pPage1;
  2647. PLIST_ENTRY pList;
  2648. PAGED_CODE();
  2649. for(pList = List->Flink;
  2650. pList != List;
  2651. pList = pList->Flink)
  2652. {
  2653. pPage1 = CONTAINING_RECORD(pList, PAGED_FILTER, leSpecialList);
  2654. //
  2655. // See if this filter matches the new one. If so,
  2656. // we've already got it, so just free the new filter
  2657. // and return success
  2658. if(pPageFilter->type == pPage1->type)
  2659. {
  2660. *pPageHit = pPage1;
  2661. return(TRUE);
  2662. }
  2663. }
  2664. return(FALSE);
  2665. }
  2666. VOID
  2667. FreePagedFilterList(PPFFCB Fcb,
  2668. PPAGED_FILTER pList,
  2669. PPAGED_FILTER_INTERFACE pPage,
  2670. PDWORD pdwRemoved)
  2671. /*++
  2672. Routine Description:
  2673. Release all of the filters in the list. Each such filter
  2674. has to cause a derefernce of the underlying match
  2675. filter. If the paged filter is a global filter, handle
  2676. it specially
  2677. --*/
  2678. {
  2679. PPAGED_FILTER pFilt;
  2680. while(pList)
  2681. {
  2682. if(pList->type == PFE_FILTER)
  2683. {
  2684. if(DereferenceFilter(pList->pMatchFilter, pPage->pFilter))
  2685. {
  2686. //
  2687. // removed a filter. If this added a restriction,
  2688. // note it. A restriction is added only if the
  2689. // default action is DROP
  2690. //
  2691. if(pList->dwFlags & FILTER_FLAGS_INFILTER)
  2692. {
  2693. if(pPage->eaInAction == DROP)
  2694. {
  2695. *pdwRemoved += 1;
  2696. }
  2697. } else if(pPage->eaOutAction == DROP)
  2698. {
  2699. *pdwRemoved += 1;
  2700. }
  2701. }
  2702. RemoveEntryList(&pList->leHash);
  2703. RemoveEntryList(&pList->leHandleHash);
  2704. }
  2705. else
  2706. {
  2707. RemoveGlobalFilterFromInterface(pPage->pFilter,
  2708. pList->type);
  2709. RemoveEntryList(&pList->leSpecialList);
  2710. }
  2711. pFilt = pList->pFilters;
  2712. ExFreeToPagedLookasideList(&paged_slist,
  2713. (PVOID)pList);
  2714. pList = pFilt;
  2715. }
  2716. }
  2717. NTSTATUS
  2718. FindAndRemovePagedFilter(
  2719. PPFFCB Fcb,
  2720. PFILTER_INFOEX pInfo,
  2721. BOOL fInFilter,
  2722. PDWORD pdwRemoved,
  2723. PPAGED_FILTER_INTERFACE pPage)
  2724. /*++
  2725. Routine Description:
  2726. Find if the described filter in on the paged interface,
  2727. and if so, remove it, and derefernce the underlying match
  2728. filter.
  2729. --*/
  2730. {
  2731. PAGED_FILTER Page;
  2732. PPAGED_FILTER pPageHit;
  2733. DWORD dwFlags = fInFilter ? FILTER_FLAGS_INFILTER : 0;
  2734. MakeFilterInfo(&Page, pInfo, dwFlags);
  2735. //
  2736. // search the interface to see if we have this already.
  2737. //
  2738. if(Page.type != PFE_FILTER)
  2739. {
  2740. //
  2741. // it's a special filte. Search the list
  2742. //
  2743. if(!IsOnSpecialFilterList(&Page,
  2744. &pPage->leSpecialFilterList,
  2745. &pPageHit)
  2746. )
  2747. {
  2748. return(STATUS_INVALID_PARAMETER);
  2749. }
  2750. }
  2751. else
  2752. {
  2753. //
  2754. // a regular filter
  2755. //
  2756. pPageHit = IsOnPagedInterface(&Page, pPage);
  2757. if(!pPageHit)
  2758. {
  2759. return(STATUS_INVALID_PARAMETER);
  2760. }
  2761. }
  2762. if(!--pPageHit->dwInUse)
  2763. {
  2764. pPageHit->pFilters = NULL;
  2765. FreePagedFilterList(Fcb, pPageHit, pPage, pdwRemoved);
  2766. }
  2767. return(STATUS_SUCCESS);
  2768. }
  2769. PPAGED_FILTER
  2770. FindFilterByHandle(
  2771. IN PPFFCB Fcb,
  2772. IN PPAGED_FILTER_INTERFACE pPage,
  2773. IN PVOID pvHandle)
  2774. /*++
  2775. Routine Description:
  2776. Find a filter given its filter handle
  2777. --*/
  2778. {
  2779. PPAGED_FILTER pPaged = 0;
  2780. DWORD dwHash = (DWORD)(((UINT_PTR)pvHandle % HANDLE_HASH_SIZE));
  2781. PLIST_ENTRY pList;
  2782. for(pList = pPage->HandleHash(dwHash).Flink;
  2783. pList != &pPage->HandleHash(dwHash);
  2784. pList = pList->Flink)
  2785. {
  2786. PPAGED_FILTER ppf = CONTAINING_RECORD(pList,
  2787. PAGED_FILTER,
  2788. leHandleHash);
  2789. if(ppf == (PPAGED_FILTER)pvHandle)
  2790. {
  2791. pPaged = ppf;
  2792. break;
  2793. }
  2794. }
  2795. return(pPaged);
  2796. }
  2797. NTSTATUS
  2798. DeleteByHandle(
  2799. IN PPFFCB Fcb,
  2800. IN PPAGED_FILTER_INTERFACE pPage,
  2801. IN PVOID * ppHandles,
  2802. IN DWORD dwLength)
  2803. /*++
  2804. Routine Description:
  2805. Delete filters using the assigned filter handles
  2806. Note the FCB is locked, so it won't change
  2807. --*/
  2808. {
  2809. PFILTER_INTERFACE pIf = pPage->pFilter;
  2810. DWORD dwFilters;
  2811. PPAGED_FILTER pPFilter;
  2812. NTSTATUS Status = STATUS_SUCCESS;
  2813. DWORD dwFiltersRemoved = 0;
  2814. PAGED_CODE();
  2815. if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
  2816. {
  2817. return(STATUS_INVALID_DEVICE_REQUEST);
  2818. }
  2819. //
  2820. // compute number of filters
  2821. //
  2822. dwFilters = dwLength / sizeof(PVOID);
  2823. for(; dwFilters; dwFilters--, ppHandles++)
  2824. {
  2825. //
  2826. // for each handle, locate the filter
  2827. //
  2828. pPFilter = FindFilterByHandle(Fcb, pPage, *ppHandles);
  2829. if(!pPFilter)
  2830. {
  2831. TRACE(CONFIG,("IPFLTDRV: Could not translate handle to filter\n"));
  2832. }
  2833. else
  2834. {
  2835. if(!--pPFilter->dwInUse)
  2836. {
  2837. pPFilter->pFilters = NULL;
  2838. FreePagedFilterList(Fcb, pPFilter, pPage, &dwFiltersRemoved);
  2839. }
  2840. }
  2841. }
  2842. if(dwFiltersRemoved)
  2843. {
  2844. NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
  2845. }
  2846. return(STATUS_SUCCESS);
  2847. }
  2848. NTSTATUS
  2849. UnSetFiltersEx(
  2850. IN PPFFCB Fcb,
  2851. IN PPAGED_FILTER_INTERFACE pPage,
  2852. IN DWORD dwLength,
  2853. IN PFILTER_DRIVER_SET_FILTERS pInfo)
  2854. /*++
  2855. Routine Description:
  2856. Unset a list of filters from an interface. This is the
  2857. inverse operation of SetFilterEx
  2858. --*/
  2859. {
  2860. PRTR_TOC_ENTRY pInToc,pOutToc;
  2861. PFILTER_INTERFACE pIf = pPage->pFilter;
  2862. PFILTER_DESCRIPTOR2 pFilterDescIn, pFilterDescOut;
  2863. PPAGED_FILTER pIn = NULL, pOut = NULL;
  2864. DWORD i;
  2865. PPAGED_FILTER pPFilter;
  2866. NTSTATUS Status = STATUS_SUCCESS;
  2867. PBYTE pbEnd = (PBYTE)pInfo + dwLength;
  2868. DWORD dwFiltersRemoved = 0;
  2869. PAGED_CODE();
  2870. if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
  2871. {
  2872. return(STATUS_INVALID_DEVICE_REQUEST);
  2873. }
  2874. pInToc = GetPointerToTocEntry(IP_FILTER_DRIVER_IN_FILTER_INFO,
  2875. &pInfo->ribhInfoBlock);
  2876. pOutToc = GetPointerToTocEntry(IP_FILTER_DRIVER_OUT_FILTER_INFO,
  2877. &pInfo->ribhInfoBlock);
  2878. if(pInToc && pInToc->InfoSize)
  2879. {
  2880. //
  2881. // filters are defined.
  2882. //
  2883. pFilterDescIn = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
  2884. pInToc);
  2885. if((pFilterDescIn != NULL) && (pFilterDescIn->dwVersion != 2))
  2886. {
  2887. TRACE(CONFIG,("IPFLTDRV: Invalid version for FiltersEx\n"));
  2888. return(STATUS_INVALID_PARAMETER);
  2889. }
  2890. }
  2891. else
  2892. {
  2893. pFilterDescIn = NULL;
  2894. }
  2895. if(pOutToc && pOutToc->InfoSize)
  2896. {
  2897. //
  2898. // filters are defined.
  2899. //
  2900. pFilterDescOut = GetInfoFromTocEntry(&pInfo->ribhInfoBlock,
  2901. pOutToc);
  2902. if((pFilterDescOut != NULL) && (pFilterDescOut->dwVersion != 2))
  2903. {
  2904. TRACE(CONFIG,("IPFLTDRV: Invalid version for FiltersEx\n"));
  2905. return(STATUS_INVALID_PARAMETER);
  2906. }
  2907. }
  2908. else
  2909. {
  2910. pFilterDescOut = NULL;
  2911. }
  2912. if((pFilterDescIn && !CheckDescriptorSize(pFilterDescIn, pbEnd))
  2913. ||
  2914. (pFilterDescOut && !CheckDescriptorSize(pFilterDescOut, pbEnd)) )
  2915. {
  2916. return(STATUS_BUFFER_TOO_SMALL);
  2917. }
  2918. //
  2919. // For each set of filters, remove the filters from the
  2920. // paged interface and thence from the match interface
  2921. if(pFilterDescIn)
  2922. {
  2923. //
  2924. // Removing in filters. For each filter, process as
  2925. // needed. Input filters include the global checks
  2926. /// such as spoofing.
  2927. //
  2928. RemoveFilterWorker(Fcb,
  2929. &pFilterDescIn->fiFilter[0],
  2930. pFilterDescIn->dwNumFilters,
  2931. pPage,
  2932. &dwFiltersRemoved,
  2933. TRUE);
  2934. }
  2935. //
  2936. // now the output filters. This is a bit simpler since there
  2937. // are no global settings.
  2938. //
  2939. if(pFilterDescOut)
  2940. {
  2941. //
  2942. // Adding in filters. For each filter, process as
  2943. // needed. Input filters include the global checks
  2944. /// such as spoofing.
  2945. //
  2946. RemoveFilterWorker(Fcb,
  2947. &pFilterDescOut->fiFilter[0],
  2948. pFilterDescOut->dwNumFilters,
  2949. pPage,
  2950. &dwFiltersRemoved,
  2951. FALSE);
  2952. }
  2953. if(dwFiltersRemoved)
  2954. {
  2955. NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
  2956. }
  2957. return(STATUS_SUCCESS);
  2958. }
  2959. VOID
  2960. RemoveFilterWorker(
  2961. PPFFCB Fcb,
  2962. PFILTER_INFOEX pFilt,
  2963. DWORD dwCount,
  2964. PPAGED_FILTER_INTERFACE pPage,
  2965. PDWORD pdwRemoved,
  2966. BOOL fInFilter)
  2967. {
  2968. NTSTATUS Status;
  2969. //
  2970. // If a regular filter, add it. If a special, global
  2971. // filter, handle it specially.
  2972. //
  2973. while(dwCount)
  2974. {
  2975. if(fInFilter || (pFilt->type == PFE_FILTER))
  2976. {
  2977. Status = FindAndRemovePagedFilter(
  2978. Fcb,
  2979. pFilt,
  2980. fInFilter,
  2981. pdwRemoved,
  2982. pPage);
  2983. if(!NT_SUCCESS(Status))
  2984. {
  2985. ERROR(("IPFLTDRV: Removing filter failed %x\n", Status));
  2986. }
  2987. }
  2988. else
  2989. {
  2990. ERROR(("IPFLTDRV: Ignoring global out filter\n"));
  2991. }
  2992. dwCount--;
  2993. pFilt++;
  2994. }
  2995. }
  2996. NTSTATUS
  2997. SetInterfaceBinding(PINTERFACEBINDING pBind,
  2998. PPAGED_FILTER_INTERFACE pPage)
  2999. {
  3000. INTERFACEBINDING2 Bind2;
  3001. NTSTATUS status;
  3002. //
  3003. // Rather than duplicating the code for the new & the old routine
  3004. // call the new routine by transforming old structure to the new
  3005. // structure.
  3006. //
  3007. Bind2.pvDriverContext = pBind->pvDriverContext;
  3008. Bind2.pfType = pBind->pfType;
  3009. Bind2.dwAdd = pBind->dwAdd;
  3010. Bind2.dwEpoch = pBind->dwEpoch;
  3011. Bind2.dwLinkAdd = 0;
  3012. status = SetInterfaceBinding2(&Bind2, pPage);
  3013. pBind->dwEpoch = Bind2.dwEpoch;
  3014. return(status);
  3015. }
  3016. NTSTATUS
  3017. SetInterfaceBinding2(PINTERFACEBINDING2 pBind,
  3018. PPAGED_FILTER_INTERFACE pPage)
  3019. {
  3020. PFILTER_INTERFACE pIf1, pIf = pPage->pFilter;
  3021. NTSTATUS Status;
  3022. LOCK_STATE LockState;
  3023. DWORD dwBind, dwOldBind;
  3024. if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
  3025. {
  3026. return(STATUS_INVALID_DEVICE_REQUEST);
  3027. }
  3028. KeEnterCriticalRegion();
  3029. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  3030. //
  3031. // verify binding type
  3032. //
  3033. switch(pBind->pfType)
  3034. {
  3035. default:
  3036. dwBind = UNKNOWN_IP_INDEX;
  3037. break;
  3038. case PF_BIND_INTERFACEINDEX:
  3039. (VOID)GetIpStackIndex(0, TRUE); // make sure have this list
  3040. dwBind = pBind->dwAdd;
  3041. break;
  3042. case PF_BIND_IPV4ADDRESS:
  3043. dwBind = GetIpStackIndex((IPAddr)pBind->dwAdd, TRUE);
  3044. break;
  3045. }
  3046. //
  3047. // Make sure it is not bound or if it is that it is
  3048. // bound to this interface
  3049. //
  3050. if(((pIf->dwIpIndex != UNKNOWN_IP_INDEX) &&
  3051. (pIf->dwIpIndex != dwBind) &&
  3052. (pIf->dwLinkIpAddress != pBind->dwLinkAdd) )
  3053. ||
  3054. (dwBind == UNKNOWN_IP_INDEX)
  3055. )
  3056. {
  3057. Status = STATUS_INVALID_PARAMETER;
  3058. }
  3059. else
  3060. {
  3061. BOOL fFound = FALSE;
  3062. PLIST_ENTRY pList;
  3063. //
  3064. // verify that this is not already in use by some other
  3065. // interface
  3066. //
  3067. dwOldBind = pIf->dwIpIndex;
  3068. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  3069. for(pList = g_filters.leIfListHead.Flink;
  3070. pList != &g_filters.leIfListHead;
  3071. pList = pList->Flink)
  3072. {
  3073. pIf1 = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
  3074. if((pIf1->dwIpIndex == dwBind) && (pIf1->dwLinkIpAddress == pBind->dwLinkAdd))
  3075. {
  3076. //
  3077. // found it.
  3078. //
  3079. fFound = TRUE;
  3080. break;
  3081. }
  3082. }
  3083. if(!fFound)
  3084. {
  3085. pIf->dwIpIndex = dwBind;
  3086. pIf->dwLinkIpAddress = pBind->dwLinkAdd;
  3087. InterlockedIncrement(&g_ulBoundInterfaceCount);
  3088. TRACE(CONFIG,(
  3089. "IPFLTDRV: Bound Interface Index=%d, Link=%d, TotalCnt=%d\n",
  3090. dwBind,
  3091. pBind->dwLinkAdd,
  3092. g_ulBoundInterfaceCount
  3093. ));
  3094. }
  3095. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  3096. if(fFound)
  3097. {
  3098. if(pIf1 == pIf)
  3099. {
  3100. Status = STATUS_SUCCESS;
  3101. }
  3102. else
  3103. {
  3104. Status = STATUS_INVALID_PARAMETER;
  3105. }
  3106. }
  3107. else
  3108. {
  3109. NotifyFastPathIf(pIf);
  3110. if(!++pIf->dwBindEpoch)
  3111. {
  3112. pIf->dwBindEpoch++;
  3113. }
  3114. Status = STATUS_SUCCESS;
  3115. }
  3116. }
  3117. pBind->dwEpoch = pIf->dwBindEpoch;
  3118. ExReleaseResourceLite(&FilterListResourceLock);
  3119. KeLeaveCriticalRegion();
  3120. return(Status);
  3121. }
  3122. NTSTATUS
  3123. ClearInterfaceBinding(PPAGED_FILTER_INTERFACE pPage,
  3124. PINTERFACEBINDING pBind)
  3125. {
  3126. PFILTER_INTERFACE pIf = pPage->pFilter;
  3127. NTSTATUS Status;
  3128. if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
  3129. {
  3130. return(STATUS_INVALID_DEVICE_REQUEST);
  3131. }
  3132. KeEnterCriticalRegion();
  3133. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  3134. //
  3135. // Make sure it is bound
  3136. //
  3137. if((pIf->dwIpIndex == UNKNOWN_IP_INDEX)
  3138. ||
  3139. ( pBind->dwEpoch
  3140. &&
  3141. (pIf->dwBindEpoch != pBind->dwEpoch)))
  3142. {
  3143. Status = STATUS_SUCCESS;
  3144. }
  3145. else
  3146. {
  3147. LOCK_STATE LockState;
  3148. DWORD dwIndex;
  3149. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  3150. InterlockedCleanCache(g_filters.pInterfaceCache, pIf->dwIpIndex, pIf->dwLinkIpAddress);
  3151. InterlockedDecrement(&g_ulBoundInterfaceCount);
  3152. TRACE(CONFIG,(
  3153. "IPFLTDRV: UnBound Interface Index=%d, Link=%d, TotalCnt=%d\n",
  3154. pIf->dwIpIndex,
  3155. pIf->dwLinkIpAddress,
  3156. g_ulBoundInterfaceCount
  3157. ));
  3158. ClearCache();
  3159. ReleaseWriteLock(&g_filters.ifListLock, &LockState);
  3160. dwIndex = pIf->dwIpIndex;
  3161. pIf->dwIpIndex = UNKNOWN_IP_INDEX;
  3162. NotifyFastPath(pIf, dwIndex, NOT_UNBIND);
  3163. Status = STATUS_SUCCESS;
  3164. }
  3165. ExReleaseResourceLite(&FilterListResourceLock);
  3166. KeLeaveCriticalRegion();
  3167. return(Status);
  3168. }
  3169. NTSTATUS
  3170. DeletePagedInterface(PPFFCB Fcb, PPAGED_FILTER_INTERFACE pPage)
  3171. /*++
  3172. Routine Description:
  3173. Delete the filters and this interface
  3174. --*/
  3175. {
  3176. PLIST_ENTRY pList;
  3177. PPAGED_FILTER pf;
  3178. PPAGED_FILTER pfp = NULL;
  3179. DWORD i;
  3180. DWORD dwDummy;
  3181. PAGED_CODE();
  3182. if(pPage->pFilter->dwGlobalEnables & FI_ENABLE_OLD)
  3183. {
  3184. return(STATUS_INVALID_DEVICE_REQUEST);
  3185. }
  3186. for(pList = pPage->leSpecialFilterList.Flink;
  3187. pList != &pPage->leSpecialFilterList;
  3188. pList = pList->Flink)
  3189. {
  3190. pf = CONTAINING_RECORD(pList, PAGED_FILTER, leSpecialList);
  3191. pf->pFilters = pfp;
  3192. pfp = pf;
  3193. }
  3194. for(i = 0; i < g_dwHashLists; i++)
  3195. {
  3196. for(pList = pPage->HashList[i].Flink;
  3197. pList != &pPage->HashList[i];
  3198. pList = pList->Flink)
  3199. {
  3200. pf = CONTAINING_RECORD(pList, PAGED_FILTER, leHash);
  3201. pf->pFilters = pfp;
  3202. pfp = pf;
  3203. }
  3204. }
  3205. FreePagedFilterList(Fcb, pfp, pPage, &dwDummy);
  3206. DereferenceFilterInterface(pPage->pFilter, pPage->pLog);
  3207. if(pPage->pLog)
  3208. {
  3209. DereferenceLog(pPage->pLog);
  3210. }
  3211. ExFreePool(pPage);
  3212. return(STATUS_SUCCESS);
  3213. }
  3214. NTSTATUS
  3215. GetFiltersEx(
  3216. IN PFILTER_INTERFACE pIf,
  3217. IN BOOL fClear,
  3218. OUT PFILTER_STATS_EX pInfo
  3219. )
  3220. /*++
  3221. Routine Description
  3222. Gets filters and statistics associated with an interface
  3223. It is called with the Spin Lock held as reader
  3224. Arguments
  3225. pvIf Pointer to FILTER_INTERFACE structure which was passed as a PVOID
  3226. to router manager as a context for the interface
  3227. pInfo FILTER_IF structure filled in by driver
  3228. Return Value
  3229. --*/
  3230. {
  3231. DWORD i,dwNumInFilters,dwNumOutFilters;
  3232. PFILTER pf;
  3233. PLIST_ENTRY List;
  3234. dwNumInFilters = pIf->dwNumInFilters;
  3235. dwNumOutFilters = pIf->dwNumOutFilters;
  3236. for(i = 0, List = pIf->pleInFilterSet.Flink;
  3237. List != &pIf->pleInFilterSet;
  3238. i++, List = List->Flink)
  3239. {
  3240. PFILTER_INFOEX pEx = &pInfo->info;
  3241. PFILTER_INFO2 pFilt = &pEx->info;
  3242. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  3243. pInfo->dwNumPacketsFiltered = (DWORD)pf->Count.lCount;;
  3244. if(fClear)
  3245. {
  3246. pf->Count.lCount = 0;
  3247. }
  3248. pEx->dwFilterRule = pf->dwFilterRule;
  3249. pEx->type = PFE_FILTER;
  3250. pEx->dwFlags = pf->dwFlags & FLAGS_INFOEX_ALLFLAGS;
  3251. pFilt->addrType = IPV4;
  3252. pFilt->dwaSrcAddr[0] = pf->SRC_ADDR;
  3253. pFilt->dwaSrcMask[0] = pf->SRC_MASK;
  3254. pFilt->dwaDstAddr[0] = pf->DEST_ADDR;
  3255. pFilt->dwaDstMask[0] = pf->DEST_MASK;
  3256. pFilt->dwProtocol = pf->PROTO;
  3257. pFilt->fLateBound = pf->fLateBound;
  3258. pFilt->wSrcPortHigh = pf->wSrcPortHigh;
  3259. pFilt->wDstPortHigh = pf->wDstPortHigh;
  3260. if(pFilt->dwProtocol == FILTER_PROTO_ICMP)
  3261. {
  3262. if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  3263. {
  3264. pFilt->wSrcPort = FILTER_ICMP_TYPE_ANY;
  3265. }
  3266. else
  3267. {
  3268. pFilt->wSrcPort =
  3269. MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  3270. }
  3271. if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  3272. {
  3273. pFilt->wDstPort = FILTER_ICMP_CODE_ANY;
  3274. }
  3275. else
  3276. {
  3277. pFilt->wDstPort =
  3278. MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  3279. }
  3280. }
  3281. else
  3282. {
  3283. pFilt->wSrcPort =
  3284. LOWORD(pf->uliProtoSrcDstPort.HighPart);
  3285. pFilt->wDstPort =
  3286. HIWORD(pf->uliProtoSrcDstPort.HighPart);
  3287. }
  3288. pInfo++;
  3289. }
  3290. for(i = 0, List = pIf->pleOutFilterSet.Flink;
  3291. List != &pIf->pleOutFilterSet;
  3292. i++, List = List->Flink)
  3293. {
  3294. PFILTER_INFOEX pEx = &pInfo->info;
  3295. PFILTER_INFO2 pFilt = &pEx->info;
  3296. pf = CONTAINING_RECORD(List, FILTER, pleFilters);
  3297. pInfo->dwNumPacketsFiltered =
  3298. (DWORD)pf->Count.lCount;
  3299. if(fClear)
  3300. {
  3301. pf->Count.lCount = 0;
  3302. }
  3303. pEx->dwFilterRule = pf->dwFilterRule;
  3304. pEx->type = PFE_FILTER;
  3305. pEx->dwFlags = pf->dwFlags & FLAGS_INFOEX_ALLFLAGS;
  3306. pFilt->addrType = IPV4;
  3307. pFilt->dwaSrcAddr[0] = pf->SRC_ADDR;
  3308. pFilt->dwaSrcMask[0] = pf->SRC_MASK;
  3309. pFilt->dwaDstAddr[0] = pf->DEST_ADDR;
  3310. pFilt->dwaDstMask[0] = pf->DEST_MASK;
  3311. pFilt->dwProtocol = pf->PROTO;
  3312. pFilt->fLateBound = pf->fLateBound;
  3313. if(pFilt->dwProtocol == FILTER_PROTO_ICMP)
  3314. {
  3315. if(LOBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  3316. {
  3317. pFilt->wSrcPort = FILTER_ICMP_TYPE_ANY;
  3318. }
  3319. else
  3320. {
  3321. pFilt->wSrcPort =
  3322. MAKEWORD(LOBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  3323. }
  3324. if(HIBYTE(LOWORD(pf->uliProtoSrcDstMask.HighPart)) isnot 0xff)
  3325. {
  3326. pFilt->wDstPort = FILTER_ICMP_CODE_ANY;
  3327. }
  3328. else
  3329. {
  3330. pFilt->wDstPort =
  3331. MAKEWORD(HIBYTE(LOWORD(pf->uliProtoSrcDstPort.HighPart)),0x00);
  3332. }
  3333. }
  3334. else
  3335. {
  3336. pFilt->wSrcPort =
  3337. LOWORD(pf->uliProtoSrcDstPort.HighPart);
  3338. pFilt->wDstPort =
  3339. HIWORD(pf->uliProtoSrcDstPort.HighPart);
  3340. }
  3341. pInfo++;
  3342. }
  3343. return(STATUS_SUCCESS);
  3344. }
  3345. NTSTATUS
  3346. GetInterfaceParameters(PPAGED_FILTER_INTERFACE pPage,
  3347. PPFGETINTERFACEPARAMETERS pp,
  3348. PDWORD pdwSize)
  3349. /*++
  3350. Routine Description:
  3351. Read the information about an interface
  3352. pPage -- the paged filter interface
  3353. pp -- the user's args to this
  3354. pdwSize -- the size of the buffer on IN and the bytes used on OUT
  3355. --*/
  3356. {
  3357. PFILTER_INTERFACE pIf;
  3358. DWORD dwFilterSize;
  3359. BOOL fClear = (pp->dwFlags & GET_FLAGS_RESET) != 0;
  3360. LOCK_STATE LockState;
  3361. KeEnterCriticalRegion();
  3362. ExAcquireResourceExclusiveLite(&FilterListResourceLock, TRUE);
  3363. if(!pPage)
  3364. {
  3365. pIf = FindMatchName(0, (DWORD)((DWORD_PTR)pp->pvDriverContext));
  3366. if(!pIf)
  3367. {
  3368. ExReleaseResourceLite(&FilterListResourceLock);
  3369. KeLeaveCriticalRegion();
  3370. return(STATUS_INVALID_PARAMETER);
  3371. }
  3372. }
  3373. else
  3374. {
  3375. pIf = pPage->pFilter;
  3376. }
  3377. if(pIf->dwGlobalEnables & FI_ENABLE_OLD)
  3378. {
  3379. ExReleaseResourceLite(&FilterListResourceLock);
  3380. KeLeaveCriticalRegion();
  3381. return(STATUS_INVALID_DEVICE_REQUEST);
  3382. }
  3383. //
  3384. // fill in what we can fill in. Need to double lock -- the
  3385. // outer to prevent the interface from going away and filters
  3386. // being changed, the inner to protect the counts.
  3387. //
  3388. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  3389. pp->dwInDrops = (DWORD)pIf->lTotalInDrops;
  3390. pp->dwOutDrops = (DWORD)pIf->lTotalOutDrops;
  3391. pp->dwSynOrFrag = (DWORD)pIf->CountSynOrFrag.lCount +
  3392. (DWORD)pIf->CountNoFrag.lCount;
  3393. pp->dwSpoof = (DWORD)pIf->CountSpoof.lCount +
  3394. (DWORD)pIf->CountStrongHost.lCount;
  3395. pp->dwUnused = (DWORD)pIf->CountUnused.lCount;
  3396. pp->dwTcpCtl = (DWORD)pIf->CountCtl.lCount;
  3397. pp->liSYN.QuadPart = pIf->liSYNCount.QuadPart;
  3398. pp->liTotalLogged.QuadPart = pIf->liLoggedFrames.QuadPart;
  3399. pp->dwLostLogEntries = pIf->dwLostFrames;
  3400. pp->eaInAction = pIf->eaInAction;
  3401. pp->eaOutAction = pIf->eaOutAction;
  3402. pp->dwNumInFilters = pIf->dwNumInFilters;
  3403. pp->dwNumOutFilters = pIf->dwNumOutFilters;
  3404. dwFilterSize = (pIf->dwNumInFilters + pIf->dwNumOutFilters) *
  3405. sizeof(FILTER_STATS_EX);
  3406. if((pp->dwFlags & GET_FLAGS_FILTERS) != 0)
  3407. {
  3408. //
  3409. // Make sure all of the filters fit
  3410. //
  3411. if((*pdwSize -
  3412. (sizeof(PFGETINTERFACEPARAMETERS) - sizeof(FILTER_STATS_EX))) <
  3413. dwFilterSize)
  3414. {
  3415. //
  3416. // doesn't fit. Return the required size
  3417. //
  3418. pp->dwReserved =
  3419. dwFilterSize + (sizeof(PFGETINTERFACEPARAMETERS) -
  3420. sizeof(FILTER_STATS_EX));
  3421. ReleaseWriteLock(&g_filters.ifListLock, &LockState);
  3422. ExReleaseResourceLite(&FilterListResourceLock);
  3423. KeLeaveCriticalRegion();
  3424. return(STATUS_SUCCESS);
  3425. }
  3426. (VOID)GetFiltersEx(pIf,
  3427. fClear,
  3428. &pp->FilterInfo[0]);
  3429. }
  3430. //
  3431. // if clear requested, do it now
  3432. //
  3433. if(fClear)
  3434. {
  3435. pIf->lTotalInDrops = 0;
  3436. pIf->lTotalOutDrops = 0;
  3437. pIf->CountSynOrFrag.lCount = 0;
  3438. pIf->CountNoFrag.lCount = 0;
  3439. pIf->CountFragCache.lCount = 0;
  3440. pIf->CountSpoof.lCount = 0;
  3441. pIf->CountUnused.lCount = 0;
  3442. pIf->CountCtl.lCount = 0;
  3443. pIf->CountStrongHost.lCount = 0;
  3444. pIf->liSYNCount.QuadPart = 0;
  3445. pIf->liLoggedFrames.QuadPart = 0;
  3446. pIf->dwLostFrames = 0;
  3447. }
  3448. ReleaseWriteLock(&g_filters.ifListLock, &LockState);
  3449. ExReleaseResourceLite(&FilterListResourceLock);
  3450. KeLeaveCriticalRegion();
  3451. return(STATUS_SUCCESS);
  3452. }
  3453. NTSTATUS
  3454. GetSynCountTotal(PFILTER_DRIVER_GET_SYN_COUNT pscCount)
  3455. /*++
  3456. Routine Description:
  3457. Get sum of SYNs on filter interfaces
  3458. --*/
  3459. {
  3460. PFILTER_INTERFACE pIf;
  3461. PLIST_ENTRY pList;
  3462. LOCK_STATE LockState;
  3463. LONGLONG llCount = 0;
  3464. AcquireWriteLock(&g_filters.ifListLock,&LockState);
  3465. for(pList = g_filters.leIfListHead.Flink;
  3466. pList != &g_filters.leIfListHead;
  3467. pList = pList->Flink)
  3468. {
  3469. pIf = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
  3470. if(!(pIf->dwGlobalEnables & FI_ENABLE_OLD))
  3471. {
  3472. //
  3473. // accumulate it here to avoid page faults.
  3474. //
  3475. llCount += pIf->liSYNCount.QuadPart;
  3476. }
  3477. }
  3478. ReleaseWriteLock(&g_filters.ifListLock,&LockState);
  3479. //
  3480. // Now that no lock is held, store into the pageable
  3481. // value
  3482. //
  3483. pscCount->liCount.QuadPart = llCount;
  3484. return(STATUS_SUCCESS);
  3485. }
  3486. VOID
  3487. NotifyFastPath(PFILTER_INTERFACE pIf, DWORD dwIndex, DWORD dwCode)
  3488. /*++
  3489. Routine Description:
  3490. Called whenever the filter of an interface change so that
  3491. we can tell the fast path code to clear its cache. This
  3492. must be called at base level as it might sleep or yield.
  3493. --*/
  3494. {
  3495. DWORD dwFilterCount = 1;
  3496. if(dwIndex != UNKNOWN_IP_INDEX)
  3497. {
  3498. InterlockedIncrement(&pIf->lNotify);
  3499. if(dwCode == NOT_UNBIND)
  3500. {
  3501. LARGE_INTEGER liInterval;
  3502. //
  3503. // it's an unbind. Wait for all existing callouts to
  3504. // complete.
  3505. //
  3506. liInterval.QuadPart = -1000; // short delay. Start with
  3507. // 100 us;
  3508. while(pIf->lNotify > 1)
  3509. {
  3510. //
  3511. // small delay to allow this to settle
  3512. //
  3513. KeDelayExecutionThread(KernelMode, FALSE, &liInterval);
  3514. liInterval.QuadPart *= 2;
  3515. }
  3516. dwFilterCount = 0;
  3517. }
  3518. //
  3519. // tell the fast path of this
  3520. //
  3521. InterlockedDecrement(&pIf->lNotify);
  3522. }
  3523. }
  3524. VOID
  3525. NotifyFastPathIf(PFILTER_INTERFACE pIf)
  3526. /*++
  3527. Routine Description:
  3528. Same as above, but this is called when an interface is first
  3529. bound. Notify only if it has filters or is a DROP interface
  3530. --*/
  3531. {
  3532. if(
  3533. (pIf->eaInAction == DROP)
  3534. ||
  3535. (pIf->eaOutAction == DROP)
  3536. ||
  3537. pIf->dwNumInFilters
  3538. ||
  3539. pIf->dwNumOutFilters)
  3540. {
  3541. NotifyFastPath(pIf, pIf->dwIpIndex, NOT_RESTRICTION);
  3542. }
  3543. }
  3544. NTSTATUS
  3545. SetExtensionPointer(
  3546. PPF_SET_EXTENSION_HOOK_INFO Info,
  3547. PFILE_OBJECT FileObject
  3548. )
  3549. {
  3550. LOCK_STATE LockState;
  3551. PFILTER_INTERFACE pIf;
  3552. PLIST_ENTRY pList;
  3553. AcquireWriteLock(&g_Extension.ExtLock, &LockState);
  3554. if (Info->ExtensionPointer == NULL)
  3555. {
  3556. //
  3557. // Extension hook is already set to NULL, be strict about it.
  3558. //
  3559. if (g_Extension.ExtPointer == NULL)
  3560. {
  3561. ReleaseWriteLock(&g_Extension.ExtLock, &LockState);
  3562. return(STATUS_INVALID_PARAMETER);
  3563. }
  3564. //
  3565. // File object of the entity hooking and unhooking should match.
  3566. //
  3567. if (g_Extension.ExtFileObject != FileObject)
  3568. {
  3569. ReleaseWriteLock(&g_Extension.ExtLock, &LockState);
  3570. return(STATUS_INVALID_PARAMETER);
  3571. }
  3572. g_Extension.ExtPointer = NULL;
  3573. g_Extension.ExtFileObject = NULL;
  3574. }
  3575. else
  3576. {
  3577. //
  3578. // We are setting the extension pointer to a non NULL value. The extension pointer must
  3579. // be already set to NULL to begin with, otherwise someone else registered it already.
  3580. //
  3581. if (g_Extension.ExtPointer != NULL)
  3582. {
  3583. ReleaseWriteLock(&g_Extension.ExtLock,&LockState);
  3584. return(STATUS_INVALID_PARAMETER);
  3585. }
  3586. //
  3587. // Record the file object here, every other call should be validated against this
  3588. // file object.
  3589. //
  3590. g_Extension.ExtFileObject = FileObject;
  3591. g_Extension.ExtPointer = Info->ExtensionPointer ;
  3592. }
  3593. CALLTRACE(("IPFLTDRV: SetExtensionPointer SUCCESSFUL\n"));
  3594. ReleaseWriteLock(&g_Extension.ExtLock,&LockState);
  3595. return(STATUS_SUCCESS);
  3596. }
  3597. PFILTER_INTERFACE
  3598. FilterDriverLookupInterface(
  3599. IN ULONG Index,
  3600. IN IPAddr LinkNextHop
  3601. )
  3602. /*++
  3603. Routine Description:
  3604. This routine is invoked to search for an interface with the given index
  3605. in our list of interfaces.
  3606. --*/
  3607. {
  3608. PFILTER_INTERFACE pIf;
  3609. PLIST_ENTRY pList;
  3610. for (pList = g_filters.leIfListHead.Flink;
  3611. pList != &g_filters.leIfListHead;
  3612. pList = pList->Flink)
  3613. {
  3614. pIf = CONTAINING_RECORD(pList, FILTER_INTERFACE, leIfLink);
  3615. if ((pIf->dwIpIndex == Index) && (pIf->dwLinkIpAddress == LinkNextHop))
  3616. {
  3617. TRACE(CONFIG,(
  3618. "IPFLTDRV: LookupIF: Found Entry %8x for Index=%d, NextHop=%d\n",
  3619. pIf,
  3620. Index,
  3621. LinkNextHop
  3622. ));
  3623. return pIf;
  3624. }
  3625. }
  3626. return NULL;
  3627. } // FilterDriverLookupInterface