[Snort-devel] good news and a question

Todd Lewis tlewis at ...120...
Wed Jan 3 13:33:55 EST 2001


Ok, I have refitted the paengine interface to look like this:

     typedef struct _pa_packet {
            unsigned int code;
            struct pcap_pkthdr pkthdr;
            unsigned char * buf;
     } pa_packet;

     typedef struct _paengine_s {
        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 */
        pa_packet* (*get_packet)(void);
        int (*dispose_packet)(pa_packet *);
        int (*close)(void); /* close driver; 0 on success */
        int (*get_devtype)(void); /* # of the device type; called after conf() */
        int (*get_capabilities)(void); /* caps of the driver; called after conf() */
     } paengine_s;

snort.c:ProcessPacket() now looks like this:

     void ProcessPacket(paengine_s *pa)
     {
        int i;
        pa_packet *k;
        Packet p;

        while(1){

         k=pa->get_packet();
         if(k->code==PA_PACKET_CODE_OK){
         /* call the packet decoder */
         (*grinder)(&p, p.pkth, k->buf);
(...This middle part is the same as it ever was...)
         ClearDumpBuf();
	  k.code = p.verdict;
         i=pa->dispose_packet(k);
         } else {
             fprintf(stderr, "Packet engine returned error %i\n", k->code);
         }
        }
     }

I have modified the netfilter paengine to support this interface, and
it at least loads.  I've not gotten it actually running yet, since I'm
running 2.2 and don't feel like rebooting into 2.4 right now, and I've
not modified paengine_pcap.c yet, but both of those should come probably
tomorrow.

Marty, I know that this isn't exactly how you wanted this done, but
the processing needed to be hoisted from the paengine somehow, and I
didn't have any answers to my last set of questions about this matter,
so this is the only way I knew how to do it.  If someone can get me
answers to those questions, then I'll be happy to revise this along the
lines of what you were suggesting.

So, now that it compiles (ship it! ship it!), I need to retrofit the
only other use of ProcessPacket() to fit the new interface.  Interestingly
enough, it's a real doozy: spp_defrag.c:ReassembleIP().  There seems
to be some confusion in the code itself as to what it is:

     /*
      * Function: Packet *ReassembleIP(frag *froot)
      * Purpose: Generate a Packet * to pass to DecodeIP
      * Arguments:
      * froot - root of the tree containing the last packet of the frame
      * Returns: Packet *
      */
     Tree *ReassembleIP(Tree *froot)
     {
     (...)

I am guessing, based on the conflict between the comment and the code,
that this is recently modified code.  (Again, I'm working off of 1.6.3
for all of this.)

I hadn't really thought about the fragmentation/reassembly case.  I have
an idea for how to handle this case, and then I need some advice on how
to follow that plan.

The idea is this: firmly separate ProcessPacket() into four pieces, like
this:

	char * buf = get_packet();
	Packet * p = munge_packet();
	handle_packet(p, buf);
	dispose_packet(buf);

spp_defrag is called within handle_packet(), I am guessing.  I would
have spp_defrag take its IP fragment, put it through munge_packet()
and handle_packet(), and then take the resulting verdict on the traffic
and apply that to the original packets.  So, a trace would look like this:

p=pa->get_packet() => munge_packet(p) => handle_packet(p)                                 +=> dispose_packet(p);
                                                        |                                  |
                                                        +=> q = defrag(p)                  p.status=q.status <=+
							                      |                                       |
									        +=> munge_packet(q) => handle_packet(q)

Sorry for the crappy art; I hope that that wasn't too unclear.  To put
it another way, The main loop would call:

	char * buf = get_packet();
	Packet * p = munge_packet();
	handle_packet(p, buf);
	dispose_packet(buf, p.action);

Inside handle_packet(), spp_defrag would do this:

	char *dfbuf = defrag(buf);
	Packet * q = munge_packet();
	handle_packet(p, dfbuf);
	buf.action = dfbuf.action;
	return;

This way, if the fragmented packets contain an attack, it will be detected
in the normal course, via the examination of the defrag'd traffic, and
a verdict passed on it.  spp_defrag will convey this verdict upwards
so that it will be applied against the original, undefrag'd packets,
which will in this case be discarded.

Is this right?

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