[PATCH] ng_pf and l7 filtering possibility with PF

Ermal Luçi ermal.luci at gmail.com
Tue May 29 20:18:51 UTC 2007


This is ng_pf node based on ng_ipfw code and idea.
It allows interaction of PF and netgraph.
Below are the node features and a dummy example of how to use it.
Patch is attached.

Features,
1- By default it sends any packet that matches the rule to netgraph.
Syntax: pass in from any to any netgraph 41 #41 is the hook number(it
needs to be a number)

2- You can specify how many packets will be sent to netgraph. This is
implemented as a keep state option.
Syntax: pass in from any to any netgraph 41 keep
state(max-packets-to-netgraph 4)

3- You can specify flags when adding the tag to the node.
Syntax ngctl msg pf: addtag { tagname=\"TEST\" tag=60 flags=4 }


There are 4 flags for now:
    NG_PF_KILL_STATE (actually removes state from the state pool
directly from the node
   NG_PF_IGNORE_STATE (it schedules the state to be removed later but
behaves as the above and is really faster and safer)
   NG_PF_SKIP_FIREWALLS (skips firewalls; the way it is implemented
this really skips any firewall on freebsd at least ipfw and pf). This
is per tag setting
meaning you can specify which packet whith a specific tag should skip
reparssing the rules.
  NG_PF_DROP_PACKET (really drops packet; faster than telling a rule
on PF to drop it, i don't like it personally cause is kinda magic; but
it is there)


4- The node has these messages:
       NGM_PF_ADD_TAG         (needs tagname, tagid, flags)
       struct ng_pf_command {
            char            name[NG_PF_TAG_NAME_SIZE];
            u_int16_t       tag;
            int             flags;
       };

       NGM_PF_RMV_TAG,        (needs tagname)

       NGM_PF_GET_TAGS,       (no arguments)
#ifdef NG_PF_DEBUG
       NGM_PF_GET_STATS,       (number of packets in/out)
       NGM_PF_CLR_STATS,
       NGM_PF_GETCLR_STATS,
#endif
       NGM_PF_SET_TAGZONE,
       NGM_PF_GET_TAGZONE,
       NGM_PF_DEFAULT_TAGZONE  (for help)


5- You can send back and forth a packet(reparse ruleset multiple
times) by resending a packet that has already passed once to netgraph
by a matching rule with a different hook number. I.e.:
....
.....
pass in on $int from any to any netgraph 41
pass in on $int tagged ONCE_TO_NETGRAPH netgraph 42
pass in on $int tagged TWICE_TO_NETGRAPH netgraph 43
....
...

For an example how to find DC++ packets with ng_bpf tag these packets
with ng_tag is available at ng_tag manual page. After that just
connect a hook to ng_pf and you're done. Surely even the rule that
sends the packet to the correct queue on PF side.

For more discussion on ng_bpf and packet matching for P2P packets follow,
http://lists.freebsd.org/pipermail/freebsd-current/2006-June/063863.html.

Sample configuration of the node.

1 - kldload ng_pf (after compiling).
2 - create a sample pf.conf file like the following:

pass out quick on $INT all tagged TRY keep state
pass out quick  on $INT proto tcp from any to any port 80 netgraph 41

# or even this. It does the same thing.
pass out on $INT proto tcp from any to any port 80 netgraph 41
pass out on $INT all tagged TRY keep state

#The tag TRY is added to ng_pf list of tags to translate and the tag
is added to the #packet with ng_tag.

3 - configure netgraph part of things. I  used the following commands
on my tests:

# You understand the first 2 commands :).
pfctl -e
pfctl -F all -f /etc/pf.test

# Here we configure a tag to be translated on ng_pf node. The node translates
# tagname=TRY as known by PF.
ngctl msg pf: addtag { tagname=\"TRY\" tag=52 flags=0 }

# Create a hook with a ng_tag node.
ngctl mkpeer pf: tag 41 th1

# Give a name to the hook for simplicity.
ngctl name pf:41 match

# Configure ng_tag node.

# We tell ng_tag to not touch the packets incoming/entering on hook = "th1"
ngctl msg match: sethookin { thisHook=\"th1\" ifNotMatch=\"th1\" }

# ng_tag will tag packets leaving hook="th1" with tagname=TRY.
ngctl msg match: sethookout { \
       thisHook=\"th1\" \  #hookname
       tag_id=24            \  # PACKET_TAG_PF_TAG.(1)
       tag_len=4            \  # usually 4 bytes since we only pass a
number/tag_id.
       tag_data=[ 52 ] }   # the tag we want to apply packets on this hook.
{ (1) PACKET_TAG_PF_TAG = 24 is taken from sys/mbuf.h }

After this if you try to connect to port 80 of any webserver if you
check the PF
statistics on rule matches with:
pfctl -s rules -v
you'll see that packets have gone through 'match by tag' rule after
passing through netgraph.


Feedback is appriciated,
Ermali


More information about the freebsd-pf mailing list