Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - FwHookDrv.jpg

Introduction

Probably, Firewall-Hook driver is one of the most undocumented methods a developer can use to develop packet filtering applications in Windows systems. Microsoft doesn't give any documentation about it, and the only place where you can learn something is in the DDK header files (ipFirewall.h). In fact, when I installed the Windows 2000 DDK, I was very surprised when I found this .h (and its contents!) because no documentation about the existence of Firewall hook could be read. In the next versions of DDK, Microsoft adds a few documentation about it: "this method exists but it is not recommended to implement".

However, because it's an easy method to implement firewall solutions, I think it is interesting to know how Firewall-Hook drivers work.

The Firewall-Hook Driver

I don't understand why Microsoft doesn't recommend the development of Firewall-Hook drivers. It's true that I never recommend it when you want to develop a complete firewall solution, but for small applications, it can be a good alternative. Basically, a Firewall-Hook driver can do the same work that a Filter Hook driver can do (see my article "Developing Firewalls for Windows 2000/XP", to get more information) but with less restrictions.

If you remember, Filter-Hook driver only allows one filter function installed in the system. If one application already uses this functionality, your application doesn't work. With Firewall-Hook driver, you don't have this problem. You can install all filter functions you need. Each filter function has a priority assigned, so the system will call one function after another (in priority order) until a function returns "DROP PACKET". If all functions return "ALLOW PACKET", the packet will be allowed. You can imagine it as a chain of filter functions. This chain is broken when one of them returns "DROP PACKET". The order of each function in the chain is given by its priority value.

Chained function figure

In the figure, I represent the next process:

  1. A packet is received in your host. IP driver has the list of filter functions ordered by priority (the function with more priority is Filter Function 1).
  2. First, IP driver passes the packet to the highest priority filter function and waits for the return value.
  3. Filter function 1 returns "ALLOW PACKET".
  4. Because Filter function 1 allows the packet, IP driver passes the packet to the next filter function: Filter function 2.
  5. In this case, Filter function 2 returns "DROP PACKET". So, IP driver drops the packet and does not continue calling the next filter functions.

Another problem you can find with Filter-Hook drivers is that for sent packets, you can't access packet content data. However, you can access all data with a Firewall-Hook driver. The structure of data received in a Firewall-Hook filter function is more complex than the one received in Filter-Hook driver. It's more similar to the structure of packets you can find in a NDIS driver, where the total packet is composed by a chain of buffers. But be patient, we can learn more about it later.

As Filter-Hook driver, Firewall-Hook driver is only a kernel mode driver used to install a callback function (but Firewall-Hook driver installs a callback in IP driver). In fact, the process to install a Firewall-Hook driver is similar to the one used to install a Filter-Hook driver. Inside ipFirewall.h file, you can find the next lines:

typedef struct _IP_SET_FIREWALL_HOOK_INFO 
{ 
    // Packet filter callout. 

    IPPacketFirewallPtr FirewallPtr;

    // Priority of the hook

    UINT Priority;

       // if TRUE then ADD else DELETE 

       BOOLEAN Add;
} IP_SET_FIREWALL_HOOK_INFO, *PIP_SET_FIREWALL_HOOK_INFO;   
 
#define DD_IP_DEVICE_NAME L\\"file://Ip/">Device\\Ip 
#define _IP_CTL_CODE(function, method, access) \ 
        CTL_CODE(FSCTL_IP_BASE, function, method, access) 
#define IOCTL_IP_SET_FIREWALL_HOOK \ 
        _IP_CTL_CODE(12, METHOD_BUFFERED, FILE_WRITE_ACCESS)

These lines give you an idea about how to install a callback function. You have only to fill a IP_SET_FIREWALL_HOOK_INFO structure with the data of your callback function and install it sending the IOCTL IOCTL_IP_SET_FIREWALL_HOOK to the IP device. Easy, if you have worked with drivers and if you have worked with documented Filter-Hook drivers before. An important parameter about this structure is the field Priority. Each field contains the priority of the filter function, greater as greater is this value.

PDEVICE_OBJECT ipDeviceObject=NULL; 
IP_SET_FIREWALL_HOOK_INFO filterData; 

//..... 


// Init structure filterData.

FirewallPtr = filterFunction; 
filterData.Priority = 1; 
filterData.Add = TRUE; 

//.... 


// Send the commando to ip driver

IoCallDriver(ipDeviceObject, irp);

If you want to uninstall a filter function, you can use the same code but putting FALSE value into filterData.Add.

The Filter Function

The filter function for a Firewall-Hook driver is more complex than that used in Filter-Hook drivers. Therefore, the complexity grows because there isn�t documentation about the function and its parameters. The function has the following signature:

FORWARD_ACTION cbFilterFunction(VOID **pData, 
                                     UINT RecvInterfaceIndex, 
                                     UINT *pSendInterfaceIndex, 
                                     UCHAR *pDestinationType, 
                                     VOID *pContext, 
                                     UINT ContextLength, 
                                     struct IPRcvBuf **pRcvBuf);

With patience and using debugging methods (and interpreting the name of the parameters :)), I get the following information about these parameters:

pData *pData points to a (struct IPRcvBuf *) structure with packet buffer.
RecvInterfaceIndex Interface where the data is received.
pSendInterfaceIndex Pointer to unsigned int containing the value of the index where data is sent. Although it is a pointer, changing this value doesn't get the packet to be rerouted :(.
pDestinationType Pointer to unsigned int with destination type: local network, remote, broadcast, multicast, etc.
pContext Point to a FIREWALL_CONTEXT_T structure where you can find information about the packet as if the packet is incoming or outgoing packet.
ContextLength Size of buffer pointed by pContext. Its value is always sizeof(FIREWALL_CONTEXT_T).
pRcvBuf *pRcvBuf points always to NULL.

This information can be changed in future Windows versions because no official documentation is available. I only guarantee that this is the meaning of these fields that I obtained from my tests in Windows 2000 and Windows XP.

For each packet, our function will be called, and depending on the value it returns, the packet will be dropped or will be passed. The values you can return in the filter function are:

FORWARD The packet is allowed.
DROP The packet is dropped.
ICMP_ON_DROP The packet is dropped and a ICMP packet is sent to remote machine.

Unchaining Buffers

In Firewall-Hook filter function, you don�t receive the buffer directly with packet header and packet content as in Filter-Hook driver. After some tests, I got to know the internal structure of the buffer. As I said before, the sent/received packet is passed in the parameter pData. *pData points to a IPRcvBuf structure:

struct IPRcvBuf 
{
    // Point to the next buffer in the chain

    struct IPRcvBuf *ipr_next;

    // Always 0 

    UINT ipr_owner;

    // Buffer data 

    UCHAR *ipr_buffer;

    // Buffer data size

    UINT ipr_size;

    // In my tests always a pointer to NULL.

    // Maybe the system could use MDLs instead of IPRcvBuf structures (but

    // i never have seen it).

    PMDL ipr_pMdl;

    // Always a pointer to NULL.

    UINT *ipr_pClientCnt;

    // Always a pointer to NULL.

    UCHAR *ipr_RcvContext;

    // Always 0. I suppose this field is a offset into buffer data

    // but because I haven't a value different from 0, I can affirm it.

    UINT ipr_RcvOffset;

    // In Windows 2003 DDK the name of this field have changed to flags.

    // In my tests I always get 0 value for local traffic and 2 for remote.

    // It's the only thing I can tell you about this field.

       ULONG ipr_promiscuous;
};

For our purpose, we only have to know the fields ipr_next, ipr_buffer and ipr_size. The field ipr_buffer contains ipr_size bytes of the packet. However, the entire packet need not be in one buffer and the system can chain several buffers. For this reason, the field ipr_next is used. This field points to the next structure with data of the packet. We have the entire packet when in the data structure the field ipr_next points to NULL. So, we find in Firewall-Hook drivers a chained buffer structure as we can see in NDIS drivers. In my tests, for all received packets, the function receives only one structure with all the data in its buffer, and for sent packets, I find several chained buffers where each one contains information about one protocol. I mean, if I send an ICMP packet, for example, there are three chained buffers: one with IP header, one with ICMP header, and another with data. However, as we must do with NDIS drivers, we must not rely on how the system fills the buffers.

In the next figure, you can see an example of how a packet is built in Firewall-Hook driver:

Chained buffers figure

As a simple, you can see in the next code how get a lineal buffer with packet content from the chained buffers:

char *pPacket = NULL;
int iBufferSize;
struct IPRcvBuf *pBuffer = (struct IPRcvBuf *) *pData;

// First, I calculate the total size of the packet

iBufferSize = buffer->ipr_size;
while(pBuffer->ipr_next != NULL)
{
    pBuffer = pBuffer->ipr_next;
    iBufferSize += pBuffer->ipr_size;
}

// Reserve memory to the lineal buffer.

pPacket = (char *) ExAllocatePool(NonPagedPool, iBufferSize);
if(pPacket != NULL)
{
    unsigned int iOffset = 0;
    pBuffer = (struct IPRcvBuf *) *pData;

    // we are going to copy each buffer of the chain in the lineal buffer.

    memcpy(pPacket, pBuffer->ipr_buffer, pBuffer->ipr_size);
    while(pBuffer->ipr_next != NULL)
    { 
        iOffset += pBuffer->ipr_size;
        pBuffer = pBbuffer->ipr_next;
        memcpy(pPacket + iOffset, pBuffer->ipr_buffer, 
                                  pBbuffer->ipr_size);
    } 
}

And for all curious people (and before you ask me about it :P), you can modify data of the packets, on your own risk. There isn't any tool to do this type of software, for doing something like it, I recommend you to implement a NDIS IM driver or a TDI Filter driver. I didn't test it so much but I wouldn't rely very much in the stability of a Firewall Hook driver that change packet content. Why? Because we don't know how IP driver manages these buffers and what risks will modify them. In a few words, my recommendation: see, but not touch.

Join Time!

Well, now we know the syntax of the filter function and we know the format of the packet passed to it. Now, we only have to know how to join these two things to get a packet filtering application. The method I have used is to try to define a filter function similar to the one used in Filter-Hook driver because it's easier to understand. Because the parameters passed to the filter functions in these drivers are different, for Firewall-Hook, I implement an intermediate function (the real Firewall-Hook filter function) that wraps the filter function. I mean, as the Firewall-Hook filter function, I use a function that processes the packet, copy it in a lineal buffer, and pass it to the filter function. With this piece of code, I think you will understand it better:

FORWARD_ACTION cbFilterFunction(VOID **pData,
                                     UINT RecvInterfaceIndex, 
                                     UINT *pSendInterfaceIndex, 
                                     UCHAR *pDestinationType, 
                                     VOID *pContext, 
                                     UINT ContextLength, 
                                     struct IPRcvBuf **pRcvBuf)
{
    FORWARD_ACTION result = FORWARD;
    char *pPacket = NULL;
    int iBufferSize;
    struct IPRcvBuf *pBbuffer =(struct IPRcvBuf *) *pData;
    PFIREWALL_CONTEXT_T fwContext = (PFIREWALL_CONTEXT_T)pContext;

    IPHeader *pIpHeader;

    // Convert chained buffer to lineal buffer as we see before.

    // This won't be the fastest code but

    // will help us to understand better the method.


    // ...........


    pIpHeader = (IPHeader *)pPacket;

    // Call the real filter function and return result     

    result = FilterPacket(pPacket,
                          // length in bytes = ipp->headerLength * (32 bits/8) 

                          pPacket + (pIpHeader ->headerLength * 4), 
                          iBufferSize - (pIpHeader ->headerLength * 4), 
                          (fwContext != NULL) ? fwContext->Direction: 0, 
                          RecvInterfaceIndex, 
                          (pSendInterfaceIndex != NULL) ? *pSendInterfaceIndex : 0);

    return result;
}

The Code

You can recognize the application of this article quickly. Yes, the GUI is exactly the one I used with my Filter Hook driver. Why? Because I have developed an easy packet filtering application that I use to test all firewalling methods I develop. In this way, I have a common GUI for all of them, that offer the user the same functionality, but at the lower level, work too different. I have different versions of this application (with minimum changes) to test my Filter-Hook driver, Firewall-Hook driver, LSP DLL, TDI filter driver, NDIS drivers... So, I think the methods are easy to understand. Few changes in GUI application, and you want to understand only the new method used.

As in my other article, this application only implements packet filtering. So many people asked me about adding some extra functionality as packet logging, install as service... But I want to follow the idea of offering methods, not solutions. If you want to add some of these extra functionalities, I am enchanted :). You can contact me to ask all questions you need.

Conclusion

Well, once time I have wrote this article, it's yours. I hope you can learn from it so much as I did. Enjoy it!!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralWant to work on packet filtering for WinXp and win7
adi.Shoukat
6:56 3 Dec '09  
Hello Jess O,
I am willing to make an application that captures all the Http packets that go out of my system. I know how to use .Net framework but i don't have ideas about C++ code that can capture all the Http packets ... can you help me please ???
if yes plz send your account ID at adi.shoukat@gmail.com
thanks.
Generalhelp,could i set DROP as a default action for packets?
orcininin
21:47 2 Nov '09  
thank u for the great work!
i want to realize a ip firewall that only allow authorized ip to access the host.
but if i set the rule:
sourceip 0.0.0.0,port 0,
IPmask:255.255.255.255;
destinationip 192.168.0.121,port: 0,
IPmask:255.255.255.255,
protocol:all,action:drop
that any ip would be dropped,then i add another rule that allow an ip to access the host.but it doesn't work.it drops all packets.
so,maybe i could modify the FilterPacket to make my idea come true,so i modify the FilterPacket(function)in FwHookDrv.c,to return DROP as an action for not finding a matching rule. but i failed again, it dropped all packets,too.
how could i to realise my goal? please help me , my email is zaishui321@163.com ,if you could contact me i will appreciate very much.
another question is i dont understand ip mask,what role it plays?something like netmask,to judge subnet?thank u~
GeneralCan I modify packet?such as ttl or something else。
noddy2
21:05 29 Jul '09  
I try but it does not work。
Generalhow can i modify received data?
xingworld
22:34 3 Apr '09  
This is a great article about Firewall-Hook Driver I have ever read.
It's great valuable to read. I will thank you very much.

Because of the limitation of my ability, I don't know how to modify received data.
I just want to modify Host information of Http request which IIS server received.
for example:
Host: www.yahoo.com
-->
Host: www.baidu.com

thank you very much.
GeneralRe: how can i modify received data?
ZUPERKOOL
9:44 7 Feb '10  
hi, i am trying to do the same... without editing host files....

did you find a solution to your task?

have a nice day.


ivo



QuestionQuestions
martinisa
0:27 12 Dec '08  
Hello,
I want to know if your program works with NDIS drivers?
I have some problems to open your file. I can't open neither with Microsoft Visual Studio .net 2005 nor Microsoft Visual Studio .net 2003.
What is the software that you have used to develop your code?

Thanks for your help.
GeneralOnly one filter
pku2009
20:54 11 Dec '08  
I find that it only works in this case:

Source IPBlush .0.0.0, PortBlush , IP Mask: 255.255.255.255

Destination IP Blush .0.0.0, PortBlush , IP Mask: 255.255.255.255

Other case such as

Source IP:192.168.1.8, PortBlush , IP Mask: 255.255.255.0

Destination IP :58.61.158.71.0.0.0, PortBlush , IP Mask: 255.0.0.0

it doesn't work. Why??Frown

今天没有时间,以后再写吧。

GeneralRe: Only one filter
pku2009
16:02 29 Dec '08  
I have get it works well,haha .

Source IPBlush .0.0.0, PortBlush , IP Mask: 255.255.255.255

Destination IP :58.61.158.71, PortBlush , IP Mask: 255.255.255.255

Then it works .This can drop the connection between you pc and the 58.61.158.71.

But it only drop the outpackets,can't drop the in packets. Why???

今天没有时间,以后再写吧。

QuestionWindows Server 2008 Compatibility?
tocsjung
16:31 3 Dec '08  
Hi,

Is this applicable in Windows Server 2008?
I built DrvFltIp.sys for Windows Server 2008 but it don't work.

Any answer'll be great appreciated!

Best regards.

tocsjung

QuestionUse in commercial product
b3h3mot
23:40 23 Nov '08  
hello,
Is it possible to use your firewall-hook driver and TDriver class in commercial product?
There are no license attached to Your software so i don't know how it can be used in other products.

Thanks in advance for Your answer
b3h3mot
AnswerRe: Use in commercial product
Jess O.
11:27 25 Nov '08  
Hi,

No problem, you can use this software in a commercial product. If you tell me in what product you pretend to use this software I will thanks you.

Best regarsds.
GeneralMore than one NIC
W M Suleiman
3:53 16 Jun '08  
Hello
First i want to thank you for your effort, it's so great.
i'm loading the driver on a PC with 3 NICs but the driver is able to see traffic on the first NIC only.
my question is can i control the NIC i want to filter packets on?

Thank you
Generalcan't run FirewallApp project
chandrika2111
19:44 18 Mar '08  
i can't run the project i get errors like
WINVER not defined. Defaulting to 0x0502 (Windows Server 2003),
warning C4996: 'CWinApp::Enable3dControls' was declared deprecated
GeneralVerey good jop.... thanks
Al-Shaikhly
5:23 10 Feb '08  
Hi... I've read all your articles , it's very useful , thanks.
I worked in my master project, can you help me by some notes, or code about capturing manipulating the HDLC layer. thanks in advance.
GeneralBuild error
Khey
23:53 21 Jan '08  
I have Visual Studio 2005, installed Windows Driver Development Kit (DDK) for Windows Server 2003 Service Pack 1 (SP1), Windows XP, and Windows 2000.

When I build this project, I receive error:

Windows has triggered a breakpoint in FirewallApp.exe.

This may be due to a corruption of the heap, and indicates a bug in FirewallApp.exe or any of the DLLs it has loaded.

What could be wrong?
GeneralRe: Build error
Khey
3:10 22 Jan '08  
Blahh, I just had to copy FwHookDrv.sys into debug directory.
QuestionCan I get packets in or out my computer?
MD84
4:42 27 Sep '07  
I want built an appication that can sniff packets in and out my computer. I saw in your code have a function can do that. But I don't know how to change it to use in catch packets on runtime.How I can stop or start the process sniff packet when I want. Thanks

AS84

GeneralDrop All ip , but Alow some ip
acob
16:29 13 Aug '07  
Thank you for your source
I have developed small firewall program which will be used in our office.
we need to prevent all internet access except one site

so i add '0.0.0.0 --- drop' and then '218.38.148.244 --- alow'
in this case all packet blocked

and i add '218.38.148.244 --- alow' and then '0.0.0.0 --- drop'
in this case all packet blocked too

thank for your reading
and I will wait for help
GeneralGood Artice
thomas_tom99
23:12 12 Aug '07  
[Message Deleted due to spam]
Generalspyware ip blacklist
fmoran
6:56 26 Jun '07  
Hi, i need a ip blacklist for spyware blocking.
I found a lot of sites containing blacklist for spam blocking, but I can't find any for spyware.
Please, help me.
QuestionNT 4.0 compability
Navascues
5:42 25 Jun '07  
hi all,

Is this applicable only in Windows 2000 and higher?

There is no ipfirewall.h header in NT DDK but I have readed that it's possible to use some newer libs in NT drivers... like ntstrsafe.lib.

Thanks for these articles, Jesús Oliva and codeproject people do a great job.

Julián
Generalip packet queueing
ermancetin
2:55 23 May '07  
How can we queue the ip packets with giving them priorities?
QuestionVista can not work????
Swhsu
23:15 15 May '07  
I tested it on vista, but it dont work.
Why it can not work on vista???
Help me, please. Thanks
GeneralIt dont work
hoanglinh9466
1:48 10 Apr '07  
I tested and it dont work, i think it does not change any thing
QuestionBlock - unblock
Jake123456
0:59 22 Dec '06  

Hi,

This is very nice application!

I tried it and it works a bit odd:

- I block at first rule all tcp traffic
- now I try to open all ports to DNS server and to a address
- it does not open

What I have done wrongConfused

Thanks in Advance,
Jake


Last Updated 28 Oct 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010