Determining order of passing packets throught packet filters in FreeBSD

| | Comments (0)
The order of loading kernel modules of packet filters affects the order of registering hooks in pfil interface.
So this code shows how pfil calls specified hook:

for (pfh = pfil_hook_get(dir, ph);
        pfh != NULL;
        pfh = TAILQ_NEXT(pfh, pfil_link)) {
            if (pfh->pfil_func != NULL) {
                rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp);
                if (rv != 0 || m == NULL)
                       break;
            }  
}

So we check all hooks begining from TAILQ_FIRST and pass packet to each hook as parameter.
If hook drops packet, we do not check other hooks.

This code register hooks in pfil interface:

    /*
     * insert the input list in reverse order of the output list
     * so that the same path is followed in or out of the kernel.
     */
    if (flags & PFIL_IN)
        TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
    else
        TAILQ_INSERT_TAIL(list, pfh1, pfil_link);

So for inbound traffic module that adds its hook  last would process packets first, and for outbound traffic module that adds its hook first would process packets first.
Now let's determine load order of kernel modules.
Modules on load attach to subsystems, that are described in sys/kernel.h:

    SI_SUB_PROTO_IF     = 0x8400000,    /* interfaces*/
    SI_SUB_PROTO_DOMAIN = 0x8800000,    /* domains (address families?)*/
    SI_SUB_PROTO_IFATTACHDOMAIN = 0x8800001,    /* domain dependent data init*/
Subsystems are loading in order of their number, first are loaded subsystems with lesser number.
Module on load can be attached to subsystem in different module too, this order is declared in macro DECLARE_MODULE:

enum sysinit_elem_order {
    SI_ORDER_FIRST      = 0x0000000,    /* first*/
    SI_ORDER_SECOND     = 0x0000001,    /* second*/
    SI_ORDER_THIRD      = 0x0000002,    /* third*/
    SI_ORDER_MIDDLE     = 0x1000000,    /* somewhere in the middle */
    SI_ORDER_ANY        = 0xfffffff /* last*/
};
So we should check subsystem of module and order of attachement to subsystem for each packet filter module:
pf:
DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST);
ipfw:
DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
ipfilter:
DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);

Subsystems loads in this order:  SI_SUB_PROTO_DOMAIN -> SI_SUB_PROTO_IFATTACHDOMAIN (ipfilter -> (ipfw, pf)), according to order of attachement of modules to subsystems the chain of loading must look like ipfilter -> pf -> ipfw.
Process order for inbound traffic:
ipfw -> pf -> ipfilter -> stack
and for outbound:
stack -> ipfilter -> pf -> ipfw

On the other hand ps is often loaded as kld, and is not statically compiled in the kernel, so if you can see pf.ko in loaded modules list (kldstat), pf is loaded after ipfw, not before. So traffic pass chains must look like this:
pf -> ipfw -> ipfilter -> stack - for inbound
stack -> ipfilter -> ipfw -> pf - for outbound

The order of passing trafic throught packet filters is very important in case of NAT, as next filter in chain can receive modified packet.

Leave a comment

Static pages

About this Entry

This page contains a single entry by Vsevolod Stakhov published on December 12, 2007 5:50 PM.

XCLIENT in Exim is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Powered by Movable Type 4.01 Powered by FreeBSD