[prev in list] [next in list] [prev in thread] [next in thread] 

List:       snort-devel
Subject:    [Snort-devel] spp_ttlwatch.c 1.0b1
From:       Dragos Ruiu <dr () dursec ! com>
Date:       2000-08-16 5:22:49
[Download RAW message or body]

I've been working on some interesting add-ons for snort....
I will likely be releasing a range of plug-ins to accompany
Fyodor's new plug-in management stuff.... here is the first.

Some discussion got me thinking about traceroutes.
This is a snort preprocessor that will conclusively tell you when
you are being tracerouted or firewalked.

For now, to add it to an existing snort distribution:

-add spp_ttlwatch.c to the list of souce files in the Makefile
-add spp_ttlwatch.o to the list of object files in the Makefile
-add a call to SetupTTLwatch() in InitPreprocessors() in file plugbase.c
-add a line to your rules file that says:

	preprocessor TTLwatch

And you are done.... now whenever you enable this preprocessor
it will keep track of the TTL for any IP address seen in the last hour
and tell you via an alarm whenever the TTL changes on an address.
This will conclusively tell you when and who is tracerouting....
But, you may find the alarming quite noisy.... it's there if you want it.
I wouldn't recommend everyday use of this, but it should be
handy in some high alert level situations.

Enjoy... comments, bug-reports, and feedback welcome.
I would especially welcome any feedback as to how this plug-in 
affects CPU utilization and memory footprint on a loaded 
down link (i.e. what is it with it enabled and without).

cheers,
--dr

P.s.  Caveat.... since it's based on a variant of the defragger this
may also have alignment issues under Solaris... 

-- 
dursec.com ltd. / kyx.net - we're from the future    http://www.dursec.com

["spp_ttlwatch.c" (text/x-c)]

/*
 * spp_ttlwatch.c v1.0b1 -  13 August 2000
 * 
 * Purpose: IP TTL Watcher PSnort Plug In
 * Author:  Dragos Ruiu (dr@dursec.com)
 * Copyright (c) 2000 dursec.com ltd.
 */


#include <pcap.h>
#include "decode.h"

/* Warning these are only valid for IPv4
   also note that these are still 
   in raw network order (see htons)  
   and these may fail on 64 bit machines 
   but I'm not worried about Unobtanium yet
   However I wish I could get it right
   for solaris
*/
#define SADDR(x)        *((u_int32_t *)(((char *)x->iph)+12))
#define TTL(x)		(x->iph->ip_ttl)


typedef struct tree_node Tree;
struct tree_node {
    Tree * left, * right;
    u_int32_t key;
    u_int8_t ttl;
    u_int32_t tssec;
    int size;   /* maintained to be the number of nodes rooted here */
};

Tree *troot;


/*  These next declarations are for the tree timeout and 
    and cleanup/sweeping process... time math routines are from
    an obscure piece of old code for a defunct video camera product
*/

#define TIMEOUTSEC	6000		/* 6000 seconds let's play safe for now */
#define FASTSWEEPLIM	16000000	/* memory use threhold for fast sweep */

long int treememuse;
int treesweep;  /* the timeout / garbage collection stuff  */

typedef struct _timestruct
{
        u_int32_t tv_sec;
        u_int32_t tv_usec;
} time_struct;

time_struct treetimeout;
 


/******Timestamp Routines******/

#define TIME_LT(x,y) (x tv_sec<y tv_sec||(x tv_sec==y tv_sec&&x tv_usec<y tv_usec))

void taddtime(time_struct *op1, time_struct *op2, time_struct *result)
{
    result->tv_usec = op1->tv_usec+op2->tv_usec;
    if (result->tv_usec > 999999)
    {
        result->tv_usec -= 1000000;
        op1->tv_sec++;
     }
     result->tv_sec = op1->tv_sec+op2->tv_sec;
}



/******Splay Tree Stuff******/

/* Function: addrcompare(i,j)				    */
/* This is the splay tree comparison.                       */
/* Returns 1 if i>j; 0 if i=j; -1 if i<j;                   */

int addrcompare(i,j)
u_int32_t i,j;
{
        if( i > j )
		 { return (1); }
	else if( i < j )
		 { return (-1); }
	return (0);
}
 
/* This macro returns the size of a node.  Unlike "x->size",     */
/* it works even if x=NULL.  The test could be avoided by using  */
/* a special version of NULL which was a real node with size 0.  */

#define node_size(x) ((!x) ? 0 : ((x)->size))
 
/* Function: treesplay(i, t)					*/
/* Splay using the key i (which may or may not be in the tree.) */
/* The starting root is t, size fields are maintained		*/

Tree *treesplay(u_int32_t i, Tree *t) 
{
    Tree N, *l, *r, *y;
    int comp, root_size, l_size, r_size;
    if(!t) return t;
    N.left = N.right = NULL;
    l = r = &N;
    root_size = node_size(t);
    l_size = r_size = 0;
 
    for (;;) {
        comp = addrcompare(i, t->key);
        if(comp < 0) {
            if(!t->left) break;
            if(addrcompare(i, t->left->key) < 0) {
                y = t->left;                           /* rotate right */
                t->left = y->right;
                y->right = t;
                t->size = node_size(t->left) + node_size(t->right) + 1;
                t = y;
                if(!t->left) break;
            }
            r->left = t;                               /* link right */
            r = t;
            t = t->left;
            r_size += 1+node_size(r->right);
        } else if (comp > 0) {
            if(!t->right) break;
            if(addrcompare(i, t->right->key) > 0) {
                y = t->right;                          /* rotate left */
                t->right = y->left;
                y->left = t;
		t->size = node_size(t->left) + node_size(t->right) + 1;
                t = y;
                if(!t->right) break;
            }
            l->right = t;                              /* link left */
            l = t;
            t = t->right;
            l_size += 1+node_size(l->left);
        } else {
            break;
        }
    }
    l_size += node_size(t->left);  /* Now l_size and r_size are the sizes of */
    r_size += node_size(t->right); /* the left and right trees we just built.*/
    t->size = l_size + r_size + 1;

    l->right = r->left = NULL;

    /* The following two loops correct the size fields of the right path  */
    /* from the left child of the root and the right path from the left   */
    /* child of the root.                                                 */
    for(y = N.right; y; y = y->right) {
        y->size = l_size;
        l_size -= 1+node_size(y->left);
    }
    for(y = N.left; y; y = y->left) {
        y->size = r_size;
        r_size -= 1+node_size(y->right);
    }
 
    l->right = t->left;                                /* assemble */
    r->left = t->right;
    t->left = N.right;
    t->right = N.left;

    return t;
}

/* Function: Tree * treeinsert(truct in_addr i, Tree * t) 		*/
/* Insert addr i into the tree t, if it is not already there. 	*/
/* Return a pointer to the resulting tree.                   	*/

Tree *treeinsert(u_int32_t i, u_int8_t ttl, u_int32_t time, Tree * t) {
    Tree * new;
    if(t) {
	t = treesplay(i,t);
	if (addrcompare(i, t->key)==0) {
	    return t;  /* it's already there */
	}
    }
    new = (Tree *) malloc (sizeof (Tree));
    if(!new) { ErrorMessage("Ran out of space\n"); return(t);}
    if(!t) {
	new->left = new->right = NULL;
    } else if(addrcompare(i, t->key) < 0) {
	new->left = t->left;
	new->right = t;
	t->left = NULL;
	t->size = 1+node_size(t->right);
    } else {
	new->right = t->right;
	new->left = t;
	t->right = NULL;
	t->size = 1+node_size(t->left);
    }
    new->key = i;
    new->ttl = ttl;
    new->tssec = time;
    new->size = 1 + node_size(new->left) + node_size(new->right);
    return new;
}

/* Function: Tree * treedelete(struct in_addr i, Tree *t) 	*/
/* Deletes i from the tree if it's there.   	                */
/* Return a pointer to the resulting tree.      	        */

Tree *treedelete( u_int32_t i, Tree *t) {
    Tree * x;
    int tsize;

    if (!t) return NULL;
    tsize = t->size;
    t = treesplay(i,t);
    if(addrcompare(i, t->key) == 0) {               /* found it */
	if(!t->left) {
	    x = t->right;
	} else {
	    x = treesplay(i, t->left);
	    x->right = t->right;
	}
	
	free(t);
	if(x) {
	    x->size = tsize-1;
	}
	return x;
    } else {
	return t;                         /* It wasn't there */
    }
}

/* Function: Tree *treefind_rank(int r, Tree *t)		   */ 
/* Returns a pointer to the node in the tree with the given rank.  */
/* Returns NULL if there is no such node.                          */
/* Does not change the tree.  To guarantee logarithmic behavior,   */
/* the node found here should be splayed to the root.              */

Tree *treefind_rank(int r, Tree *t) {
    int lsize;
    if ((r < 0) || (r >= node_size(t))) return NULL;
    for (; t != 0 ;) {
	lsize = node_size(t->left);
	if (r < lsize) {
	    t = t->left;
	} else if (r > lsize) {
	    r = r - lsize -1;
	    t = t->right;
	} else {
	    return t;
	}
    }
    return NULL;
}

/* Function: treeget_rank(t)					   */
/* returns the rank of a tree element				   */

int treeget_rank(Tree *t) {
	if(!t)
		return(0);
	return(node_size(t->left)+1);
}





/******TTLwatch Stuff******/

/*
 * Function: PreprocTTLwatch(Packet *)
 * Purpose:
 * Driver function for the TTL change watch preprocessor.
 * Arguments: p => pointer to the current packet data struct
 * Returns: void function
 */
void PreprocTTLwatch(Packet *p)
{
	time_struct timecheck, timetemp;
	Tree *found;

	if(!p || !p->pkth || !p->pkt)
	{
		ErrorMessage("%s\n","Garbage Packet with Null Pointer discarded!");
		return;
	}
	if(!p->iph)
		return;	/* return quietly for arps and such with no ip headers */
	troot = treesplay(SADDR(p), troot);
	if(troot && addrcompare(troot->key, SADDR(p)) == 0)
	{
		if(troot->ttl != TTL(p))
		{
			char msgbuf[256];
			sprintf(msgbuf,"TTL Changed for Source %s new TTL %d",
				 inet_ntoa(p->iph->ip_src), TTL(p));
			 (*AlertFunc)(p, msgbuf);
			fprintf(stderr, "%s\n", msgbuf);
			troot->ttl = TTL(p);
		}
	}
	else
	{
		troot = treeinsert(SADDR(p),TTL(p),p->pkth->ts.tv_sec, troot);
		treememuse += sizeof(Tree);
	}
	if(troot)
	{
		if(++treesweep > node_size(troot)+1)
			treesweep = 1;
		found = treefind_rank(treesweep,troot);
		if(found)
		{
			troot = treesplay(found->key, troot);
			timetemp.tv_sec = troot->tssec;
			timetemp.tv_usec = 0;
	                taddtime(&timetemp, &treetimeout, &timecheck);
                        if(TIME_LT(timecheck. , p->pkth->ts.))
                        {
                                treememuse -= sizeof(Tree);
				troot = treedelete(troot->key, troot); 
				treesweep--;
			}
		}
		/* and now do the whole thing again if we are being a memory hog */
		if(troot && treememuse > FASTSWEEPLIM)
		{
			if(++treesweep > node_size(troot)+1)
				treesweep = 1;
			found = treefind_rank(treesweep,troot);
			if(found)
			{
				troot = treesplay(found->key, troot);
				timetemp.tv_sec = troot->tssec;
				timetemp.tv_usec = 0;
				taddtime(&timetemp, &treetimeout, &timecheck);
				if(TIME_LT(timecheck. , p->pkth->ts.))
				{
					treememuse -= sizeof(Tree);
					troot = treedelete(troot->key, troot); 
					treesweep--;
				}
			}
		}
	}
	return;
}



/*
 * Function: TTLwatchInit(u_char *)
 * Purpose:
 * Calls the argument parsing function, performs final setup on data
 * structs, links the preproc function into the function list.
 * Arguments: args => ptr to argument string
 * Returns: void function
 */
void TTLwatchInit(u_char *args)
{
	AddFuncToPreprocList(PreprocTTLwatch);

	troot = NULL;  /* initialize empty tree */
	treememuse = 0;	/* No memory yet */
	treetimeout.tv_sec = TIMEOUTSEC;
	treetimeout.tv_usec = 0;
	treesweep = 0;
}


/*
 * Function: SetupTTLwatch()
 * Purpose:
 * Registers the preprocessor keyword and initialization function
 * into the preprocessor list.  This is the function that gets called from
 * InitPreprocessors() in plugbase.c.
 * Arguments: None.
 * Returns: void function
 */
void SetupTTLwatch()
{
	RegisterPreprocessor("TTLwatch", TTLwatchInit);


}



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic