[Snort-devel] announcement & questions: user space firewall

Todd Lewis tlewis at ...120...
Tue Nov 28 19:55:15 EST 2000


Woops; I sent this to the wrong mailing list!

--
Todd Lewis                                       tlewis at ...120...

  God grant me the courage not to give up what I think is right, even
  though I think it is hopeless.          - Admiral Chester W. Nimitz

---------- Forwarded message ----------
Date: Tue, 28 Nov 2000 19:12:58 -0500 (EST)
From: Todd Lewis <tlewis at ...120...>
To: Snort Users <snort-users at lists.sourceforge.net>
Subject: announcement & questions: user space firewall

1) INTRODUCTION

I have modified snort to support its use as a user-space firewall.
This work was done using netfilter' IP queue support under Linux-2.4.

My modifications right now are sort of hacky and should definitely
be considered proof-of-concept.  I have a plan, which I outline below,
for integrating this support properly into snort.  I release this
patch not so that people will use it, but to engender discussion.
That said, the patch is GPL'd, and anyone who would like to is free
to use it.

2) BACKGROUND

The new firewalling mechanism under Linux-2.4, netfilter/iptables,
includes support for passing packets up to userspace via a netlink socket.
The iptables guys have created a helper library, libipq, to handle
most of the ickiness.  Basically, you receive a packet, and then you
inform the kernel of the action which should be taken on that packet.
Unfortunately, this is all still new enough that there's no documentation
to speak of.  For more information, pull the iptables distribution from
the netfilter page, http://netfilter.kernelnotes.org/.  You'll also need
linux-2.4.0-test9 or greater, I believe, configured with the something
like following options:

	- Kernel/User netlink socket
	- Network packet filtering (replaces ipchains)
	- IP: Netfilter Configuration:
		+ Userspace queueing via NETLINK (EXPERIMENTAL)
		+ IP tables support (required for filtering/masq/NAT)

3) IT WORKS!

First, I add in two rules using iptables under 2.4 to give the following:

	# iptables -A INPUT -s 140.103.29.3 -j QUEUE
	# iptables -A INPUT -s 207.69.200.226 -j QUEUE
	# ipchains -L
	Chain INPUT (policy ACCEPT)
	target     prot opt source               destination         
	QUEUE      all  --  acs.wooster.edu      anywhere           
	QUEUE      all  --  blount.mail.mindspring.net  anywhere           
	(...)

I then run snort normally, using the following rule file:

	alert icmp  140.103.29.3 any -> any any (msg:"Wooster ping";)
	alert icmp  207.69.200.226 any -> any any (msg:"MindSpring ping";firewall;)

Notice that the 207.69.200.226 target has a "firewall" directive, while
140.103.29.3 does not.

This gives the following results:

	eccehomo% for i in 140.103.29.3 207.69.200.226
	> do
	> ping -c 2 $i
	> done
	PING 140.103.29.3 (140.103.29.3): 56 data bytes
	64 bytes from 140.103.29.3: icmp_seq=0 ttl=241 time=116.1 ms
	64 bytes from 140.103.29.3: icmp_seq=1 ttl=241 time=100.7 ms
	
	--- 140.103.29.3 ping statistics ---
	2 packets transmitted, 2 packets received, 0% packet loss
	round-trip min/avg/max = 100.7/108.4/116.1 ms
	PING 207.69.200.226 (207.69.200.226): 56 data bytes
	
	--- 207.69.200.226 ping statistics ---
	2 packets transmitted, 0 packets received, 100% packet loss
	
Snort chimes in with this:

	-*> Snort! <*-
	Version 1.6.3
	By Martin Roesch (roesch at ...16..., www.snort.org)
	Entering ipq loop.
	passing packet... (1) done.
	Entering ipq loop.
	passing packet... (1) done.
	Entering ipq loop.
	passing packet... Killing packet! (0) done.
	Entering ipq loop.
	passing packet... Killing packet! (0) done.

4) THE PRESENT IMPLEMENTATION

The present implementation is very unsatisfactory for the long-haul, but
proves that this functionality is possible.  Since I didn't want to hack
into snort's guts too heavily to begin with, I have a global variable
that determines whether the packet lives or dies, and then my plugin
for the "firewall" directive just sets that flag to die.  The packet
handling routines were all #ifdef'd in and are written to emulate pcap.

This setup is not multi-threadable, it's gross, using a plugin is the
wrong way, it doesn't make use of a number of cool netfilter features,
and it doesn't support any mechanisms other than netfilter.  Still,
it appears to work.

5) PROPOSED CHANGES

I would like to make two major changes to the snort core to formalize
this support.  I think that with these changes, this functionality
should not affect the normal use of snort at all, and there are positive
side-effects of the proposed changes as well.  I would very much like
to hear other developers' opinions of these changes.

	A) MULTIPLE ACTIONS PER RULE

I propose that a single rule begin with a set of one or more actions,
rather than one and only one action as it is now.  I think that this
change is necessary even without my modifications; the fact that alert
implicitly calls log is pretty gross, and as more actions are added to
snort, the ability to combine them is important.

The syntax that I propose is a comma-delimited sequence of actions,
just like Martin's multiple-network support.  It would look something
like this:

alert,log,block tcp any any -> 192.168.1.0/24 any (msg:"Foo";)

To implement this, I would like to change RuleTreeNode.type from an
enumeration to a bit-field.  The logic in the core would then read:

	if (RuleTreeNode.type & ACTION_ALERT)
		alert(packet);
	if (RuleTreeNode.type & ACTION_LOG)
		log(packet);
	if (RuleTreeNode.type & ACTION_BLOCK)
		block(packet);

or, even better:

	for(action=actions[0];action=action++;action!+NULL){
		if(RuleTreeNode.type & action.flag)
			action.jackson(packet);
	}

(Personally, I think that the present behaviour of alert is wrong
and should be replaced with "alert,log".  Since this would not be
reverse-compatible, you could call it "alert2,log" and then denigrate
the usage of "alert".  This change is not really a big issue, but it
would set a good example on how to use the multiple action support.)

	B) PLUGGABLE PACKET ACQUISITION ENGINES

pcap is not the only way to get packets.  I would like to abstract out the
package acquisition mechanism, convert pcap into the first such engine,
and then take my libipq stuff and make that into an engine.

snort would default to pcap, or whatever else the builder wants the
default to be.  The engine could then be set either via a command-line
argument or via a config file entry.

(Not that I want to do this now, but my personal preference is that these
engines be dynamically-loadable shared objects.  I used this approach for
drivers for a DNS server called Dents that I helped develop.  Then again,
I believe that snort's plugins should be loaded in the same way.  I know
that this raises portability problems, so I'm not going to tackle it for
now, but if others are interested, I can certainly help in this work.
I am intentionally proposing this interface in such a way that it is
amenable to being used via loadable modules later.)

The high points of this new interface are as follows:

- The module would export init() and close() routines for, well,
  initialization and closing.
- Each module would basically emulate the pcap packet loop.
- The module would identify the media type from which it is acquiring
  packets.  This allows the core to chose the proper grinder routine for
  processing packets.
- The module would advertise the actions that it supports.  Thus, if you are
  attempting to use the "deny" action with the pcap engine, snort can warn
  you that it's not supported.
- The module would be configured by passing it a configuration line from the
  config file, similar to how plugins are configured now.

Future work:

- This interface only supports one connection per engine.  It would be nice
  to use session identifiers to differentiate among different connections.
  This would require for the loop to be outside of the engine and for
  the engines to export enough functionality to fit into an external
  select loop, or something.  Complicated, and since snort doesn't support
  this presently anyway, ignored for now.

Here's the interface as I have it now:

     #define DEVTYPE_RAW        0
     #define DEVTYPE_ETH        1
     #define DEVTYPE_TR         2
     #define DEVTYPE_FDDI       3
     #define DEVTYPE_SLIP       4
     #define DEVTYPE_PPP        5
     #define DEVTYPE_NULL       6
     #define DEVTYPE_I4LRAWIP   7
     #define DEVTYPE_I4LCISCOIP 8

     typedef struct paengine {
        char *name; /* name of the paengine, e.g., "pcap" */
        int (*configure)(char * config); /* config file entry for engine; 0 on
                                          * success, other on error */
        int (*init)(void); /* initialize driver; 0 on success */
        int (*loop)(void (*)(Packet *, struct pcap_pkthdr *, u_char *));
                       /* loop function for driver; takes a grinder as an
                        * argument. 0 on success, other on failure. */
        int (*close)(void); /* close driver; 0 on success */
        int dev_type; /* number of the device type; called after configure() */
        int capabilities; /* caps of the driver; called after configure() */
     } paengine;

My plan is for each engine to be implemented in a separate C file and for
that file to export a single symbol, which is this struct for that engine.
snort will, for now, have a hard-coded array of these structs, with
"#ifdef" statements around each.  snort will default to using the pcap
engine, but if you specify an alternative engine, then it will iterate
through these paengine's until it finds one where paengine->name matches
your request and then use that.

Again, I plan on taking the existing pcap code and converting it into
one of these engines and then taking the netfilter stuff and making that
into a second engine.  I hope to rope one of the few FreeBSD fanatics
here into writing an engine to support divert sockets.

And then I'd like to make two minor changes:

	C) FIREWALL SUPPORT

I have to add a flag to decode.h:Packet in order to record the firewall
verdict on a packet.  This should be completely unobtrusive to normal
usage of snort with the pcap engine, or even in non-firewall mode with
netfilter.

	D) INTEGRATION WORK

I will probably need some help with the auto* stuff to get this integrated
properly.  I plan to program this with all of the #ifdef's I need in
the code and, by default, have it all turned off.

6) THANKS

Thanks to the other kind folks at SecureWorks for not whining while I
work on this.

--
Todd Lewis                                       tlewis at ...120...

  God grant me the courage not to give up what I think is right, even
  though I think it is hopeless.          - Admiral Chester W. Nimitz
-------------- next part --------------
A non-text attachment was scrubbed...
Name: snort.usf.patch.1.bz2
Type: application/octet-stream
Size: 8044 bytes
Desc: 
URL: <https://lists.snort.org/pipermail/snort-devel/attachments/20001128/4a28f7fa/attachment.obj>


More information about the Snort-devel mailing list