[Snort-devel] more fun questions

Todd Lewis tlewis at ...120...
Tue Dec 19 14:53:54 EST 2000


On Fri, 8 Dec 2000, Todd Lewis wrote:

> It would probably look something like this in each paengine:
> 
> 	static void take_action(Packet *p);
> 
> 	void paengine_main_loop(void (*munge_packet_callback)())
> 	{
> 		u_char buf[BUFSIZE];
> 		Packet p;
> 
> 		while(get_packet(&buf, sizeof(buf))){
> 			(*munge_packet_callback)(&buf, &p); /* dependent on packet type */
> 			process_packet(&p);                 /* global, general for snort */
> 			take_action(&p);
> 		}
> 	}
> 
> That way, the paengine has visibility into the Packet struct, which
> can be extended to pass around whatever info is needed.
> 
> What do people think of these two approaches?

Ok, so I am looking into doing this, and it seems easy enough.
The first one, munge_packet_callback, is the grinder, and the second
one is rules.c:Preprocess().  This entire loop is reminiscent of
snort.c:ProcessPacket(), and this fact has got me thinking, is the
paengine really the place to do this?  After all, all of this
code is going to be duplicated in each paengine, and that's a very
good warning sign that your layering is wrong.

So, here's another idea.  What if we took ProcessPacket() and turned
that into the main loop.  It would look basically like it does now,
only it'd be a loop and would call the paengine to get and dispose of
packets, like this:

	void
	ProcessPackets(int (*grinder))
	{
		struct pastructure pas;
		u_char buf[10240];
		Packet p;

		pas.buf=&buf;
		pas.buf_size=sizeof(buf);
		pas.Packet = &p;

		while(1){
			pa->get_packet(&pas);
			(*grinder)(&pas);
			Preprocess(&p);
			switch(p.disposition){
				case DISCARD:
					if(!pa->discard(&pas))
						log_error("DISCARD called on packet where paengine %s does not support it!\n", \
							pa->name);
					break;
				case ALLOW:
					pa->pass(&pas);
					break;
				/* Add in other actions here */
				default:
					pa->pass(&pas);
					break;
			}
		}

By hoisting this logic into the snort core, out of the paengine, I think that
we would get several wins:

	- it makes the paengines generic and therefore portable among
	  projects other than snort;
	- it reduces code duplicated among paengines;
	- it is easier to expand the range of supported actions on packets;
	- it makes the whole thing multi-threadable, which can be
	  important for performance reasons, especially once snort is
	  in the critical path on firewalls.

The last one is important to me.  With Linux 2.4 having a completely
multi-threaded networking stack in the kernel, it is conceivable that on
an oct-way intel machine, you could user-space firewall gigabit ethernet
at wire speed, which would be such a coup that I get a woody just thinking
about it.  Ditto for the mainstream packet examination code.  (We would
have to clean up some of the globals, etc., but it shouldn't be too bad.)

So, this is my thinking.  Agree or disagree?  I would love to hear
people's thoughts on this stuff, but if I don't then I'll just go ahead
and code it along these lines.

--
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





More information about the Snort-devel mailing list