---[[ libnids应用实例 ]]----------------------------------

1、nids_next()函数的应用

============================ cut here ============================

/*
This is an example how one can use nids_getfd() and nids_next() functions.
You can replace printall.c's function main with this file.
*/

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main ()
{
   // here we can alter libnids params, for instance:
   // nids_params.n_hosts=256;
   int fd;
   int time = 0;
   fd_set rset;
   struct timeval tv;

   if (!nids_init ())
   {
         fprintf(stderr,"%s\n",nids_errbuf);
         exit(1);
   }
   nids_register_tcp (tcp_callback);
   fd = nids_getfd ();
   for (;;)
     {
       tv.tv_sec = 1;
       tv.tv_usec = 0;
       FD_ZERO (&rset);
       FD_SET (fd, &rset);
       // add any other fd we need to take care of
       if (select (fd + 1, &rset, 0, 0, &tv))
         {
                 if (FD_ISSET(fd,&rset)   // need to test it if there are other
                                         // fd in rset
                         if (!nids_next ()) break;
         }
       else
         fprintf (stderr, "%i ", time++);
     }
   return 0;
}

============================ cut here ============================

2、Simple sniffer

============================ cut here ============================

/*
    Copyright (c) 1999 Rafal Wojtczuk <nergal@avet.com.pl>. All rights reserved.
    See the file COPYING for license details.
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <fcntl.h>
#include "nids.h"

#define LOG_MAX 100
#define SZLACZEK "\n--------------------------------------------------\n"

#define int_ntoa(x)      inet_ntoa(*((struct in_addr *)&x))

char *
adres (struct tuple4 addr)
{
   static char buf[256];
   strcpy (buf, int_ntoa (addr.saddr));
   sprintf (buf + strlen (buf), ",%i,", addr.source);
   strcat (buf, int_ntoa (addr.daddr));
   sprintf (buf + strlen (buf), ",%i : ", addr.dest);
   return buf;
}

int logfd;
void
do_log (char *adres_txt, char *data, int ile)
{
   write (logfd, adres_txt, strlen (adres_txt));
   write (logfd, data, ile);
   write (logfd, SZLACZEK, strlen (SZLACZEK));
}

void
sniff_callback (struct tcp_stream *a_tcp, void **this_time_not_needed)
{
   int dest;
   if (a_tcp->nids_state == NIDS_JUST_EST)
     {
       dest = a_tcp->addr.dest;
       if (dest == 21 || dest == 23 || dest == 110 || dest == 143 || dest == 513)
         a_tcp->server.collect++;
       return;
     }
   if (a_tcp->nids_state != NIDS_DATA)
     {
       // seems the stream is closing, log as much as possible
       do_log (adres (a_tcp->addr), a_tcp->server.data,
               a_tcp->server.count - a_tcp->server.offset);
       return;
     }
   if (a_tcp->server.count - a_tcp->server.offset < LOG_MAX)
     {
       // we haven't got enough data yet; keep all of it
       nids_discard (a_tcp, 0);
       return;
     }
    
   // enough data  
   do_log (adres (a_tcp->addr), a_tcp->server.data, LOG_MAX);

   // Now procedure sniff_callback doesn't want to see this stream anymore.
   // So, we decrease all the "collect" fields we have previously increased.
   // If there were other callbacks following a_tcp stream, they would still
   // receive data
   a_tcp->server.collect--;
}


int
main ()
{
   logfd = open ("./logfile", O_WRONLY | O_CREAT | O_TRUNC, 0600);
   if (logfd < 0)
     {
       perror ("opening ./logfile:");
       exit (1);
     }
   if (!nids_init ())
     {
       fprintf (stderr, "%s\n", nids_errbuf);
       exit (1);
     }
   nids_register_tcp (sniff_callback);
   nids_run ();
   return 0;
}

============================ cut here ============================

3、Wu-FTPd overflow attack detector

============================ cut here ============================

/*
Copyright (c) 1999 Rafal Wojtczuk <nergal@avet.com.pl>. All rights reserved.
See the file COPYING for license details.
*/

/*
This code attempts to detect attack against imapd (AUTHENTICATE hole) and
wuftpd (creation of deep directory). This code is to ilustrate use of libnids;
in order to improve readability, some simplifications were made, which enables
an attacker to bypass this code (note, the below routines should be improved,
not libnids)
*/  

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "nids.h"

#define int_ntoa(x)      inet_ntoa(*((struct in_addr *)&x))

char *
adres (struct tuple4 addr)
{
   static char buf[256];
   strcpy (buf, int_ntoa (addr.saddr));
   sprintf (buf + strlen (buf), ",%i,", addr.source);
   strcat (buf, int_ntoa (addr.daddr));
   sprintf (buf + strlen (buf), ",%i", addr.dest);
   return buf;
}


/*
if we find a pattern AUTHENTICATE {an_int} in data stream sent to an imap
server, where an_int >1024, it means an buffer overflow attempt. We kill the
connection.
*/

#define PATTERN "AUTHENTICATE {"
#define PATLEN strlen(PATTERN)
void
detect_imap (struct tcp_stream *a_tcp)
{
   char numbuf[30];
   int i, j, datalen, numberlen;
   struct half_stream *hlf;
   if (a_tcp->nids_state == NIDS_JUST_EST)
     {
       if (a_tcp->addr.dest == 143)
         {
           a_tcp->server.collect++;
           return;
         }
       else
         return;
     }
   if (a_tcp->nids_state != NIDS_DATA)
     return;
   hlf = &a_tcp->server;
   datalen = hlf->count - hlf->offset;
   if (datalen < PATLEN)
     {
       // we have too small amount of data to work on. Keep all data in buffer.
       nids_discard (a_tcp, 0);
       return;
     }
   for (i = 0; i <= datalen - PATLEN; i++)
     if (!memcmp (PATTERN, hlf->data + i, PATLEN)) //searching for a pattern
       break;
   if (i > datalen - PATLEN)
     {
       // retain PATLEN bytes in buffer
       nids_discard (a_tcp, datalen - PATLEN);
       return;
     }
   for (j = i + PATLEN; j < datalen; j++) // searching for a closing '}'
     if (*(hlf->data + j) == '}')
       break;
   if (j > datalen)
     {
       if (datalen > 20)
         {
           //number too long, perhaps we should log it, too
         }
       return;
     }
   numberlen = j - i - PATLEN;
   memcpy (numbuf, hlf->data + i + PATLEN, numberlen); //numbuf contains
                                                       // AUTH argument
   numbuf[numberlen] = 0;
   if (atoi (numbuf) > 1024)
     {
       // notify admin
       syslog(nids_params.syslog_level,
       "Imapd exploit attempt, connection %s\n",adres(a_tcp->addr));
       // kill the connection
       nids_killtcp (a_tcp);
     }
   nids_discard (a_tcp, datalen - PATLEN);
   return;
}

// auxiliary structure, needed to keep current dir of ftpd daemon
struct supp
{
   char *currdir;
   int last_newline;
};

// the below function adds "elem" string to "path" string, taking care of
// ".." and multiple '/'. If the resulting path is longer than 768,
// return value is 1, otherwise 0
int
add_to_path (char *path, char *elem, int len)
{
int plen;
char * ptr;
   if (len > 768)
     return 1;
   if (len == 2 && elem[0] == '.' && elem[1] == '.')
     {
       ptr = rindex (path, '/');
       if (ptr != path)
         *ptr = 0;
     }
   else if (len > 0)
     {
       plen = strlen (path);
       if (plen + len + 1 > 768)
         return 1;
         if (plen==1)
         {
         strncpy(path+1,elem,len);
         path[1+len]=0;
         }
         else
         {
       path[plen] = '/';
       strncpy (path + plen + 1, elem, len);
       path[plen + 1 + len] = 0;
         }
     }
return 0;
}

void
do_detect_ftp (struct tcp_stream *a_tcp, struct supp **param_ptr)
{
   struct supp *p = *param_ptr;
   int index = p->last_newline + 1;
   char *buf = a_tcp->server.data;
   int offset = a_tcp->server.offset;
   int n_bytes = a_tcp->server.count - offset;
   int path_index, pi2, index2, remcaret;
   for (;;)
     {
       index2 = index;
       while (index2 - offset < n_bytes && buf[index2 - offset] != '\n')
         index2++;
       if (index2 - offset >= n_bytes)
         break;
       if (!strncasecmp (buf + index - offset, "cwd ", 4))
         {
           path_index = index + 4;
           if (buf[path_index - offset] == '/')
             {
               strcpy (p->currdir, "/");
               path_index++;
             }
           for (;;)
             {
               pi2 = path_index;
               while (buf[pi2 - offset] != '\n' && buf[pi2 - offset] != '/')
                 pi2++;
                 if (buf[pi2-offset]=='\n' && buf[pi2-offset-1]=='\r')
                 remcaret=1;
                 else remcaret=0;
               if (add_to_path (p->currdir, buf + path_index-offset, pi2 - path_index-remcaret))
                 {
                   // notify admin
                   syslog(nids_params.syslog_level,
                   "Ftpd exploit attempt, connection %s\n",adres(a_tcp->addr));
                   nids_killtcp (a_tcp);
                   return;
                 }
               if (buf[pi2 - offset] == '\n')
                 break;
               path_index = pi2 + 1;
             }
         }
       index = index2 + 1;
     }
   p->last_newline = index - 1;
   nids_discard (a_tcp, index - offset);
}

void
detect_ftpd (struct tcp_stream *a_tcp, struct supp **param)
{
   if (a_tcp->nids_state == NIDS_JUST_EST)
     {
       if (a_tcp->addr.dest == 21)
         {
           struct supp *one_for_conn;
           a_tcp->server.collect++;
           one_for_conn = (struct supp *) malloc (sizeof (struct supp));
           one_for_conn->currdir = malloc (1024);
           strcpy (one_for_conn->currdir, "/");
           one_for_conn->last_newline = 0;
           *param=one_for_conn;
         }
       return;
     }
   if (a_tcp->nids_state != NIDS_DATA)
     {
       free ((*param)->currdir);
       free (*param);
       return;
     }
   do_detect_ftp (a_tcp, param);
}

int
main ()
{
   if (!nids_init ())
   {
         fprintf(stderr,"%s\n",nids_errbuf);
         exit(1);
   }
   nids_register_tcp (detect_imap);
   nids_register_tcp (detect_ftpd);
   nids_run ();
   return 0;
}