/* * copyright 2002 Edscott Wilson Garcia, under GNU-GPL * Example program using disk based hashed for a stream * of data from tcpdump to do network monitoring * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include <dbh.h> #define LINE_MAX (256*4*16) /*#define KEY_LEN (2+2+2+2+4+1)*/ #define KEY_LEN 13 char *trafico_raw="trafico.raw"; char whatever[256]; void update(DBHashTable *node,char *host){ char *w,*v,t[32]; long long int *hits; int i,j,withport=0; if (count_dots(host)>3) withport=1; if (!node) return; hits=(long long int *)(DBH_DATA(node)); memset(DBH_KEY(node), 0,DBH_KEYLENGTH(node)); if ((w=strtok(host,"."))==NULL) goto error_condition; i=atoi(w); sprintf(t,"%02x",i); strncpy((char *)DBH_KEY(node),t,2); for (j=1;j<=2;j++) { if ((w=strtok(NULL,"."))==NULL) goto error_condition; i=atoi(w); sprintf(t,"%02x",i); strncat((char *)DBH_KEY(node)+2*j,t,2); } if (!withport) { /* no port number */ w=w+strlen(w)+1; i=atoi(w); sprintf(t,"%02x",i); strncat((char *)DBH_KEY(node)+2*3,t,2); } else { if ((v=strtok(NULL,"."))==NULL) goto error_condition; i=atoi(v); sprintf(t,"%02x",i); strncat((char *)DBH_KEY(node)+2*3,t,2); /* port */ w=v+strlen(v)+1; i=atoi(w); sprintf(t,"%04x",i); strncat((char *)DBH_KEY(node)+2*4,t,4); } if (DBH_load(node)) (*hits)++; else *hits=1; /* setting the data length is necesary here because DBH_set_data() was not * called in this example. Instead, we are directly using the pointer to * the data area of the current DBHashTable record */ DBH_set_recordsize(node,sizeof(long long int)); if (!DBH_update(node)) { printf("trafico: Unable to update %s\n",DBH_PATH(node)); } /*else printf("trafico: updating %s -> %d\n",(char *)node->key,*hits);*/ return; error_condition: return; } FILE *outfile; void operate(DBHashTable *node){ long long int *hits; char key[256], buf[16]; int i,j[5]; if (!outfile) return; hits=(long long int *)DBH_DATA(node); memset((void *)buf, 0,16); memset((void *)j, 0,5*sizeof(int)); memset((void *)key, 0,256); for (i=0;i<4;i++){ if ( *DBH_KEY(node)+(i*2)) { strncpy(buf,(char *)DBH_KEY(node)+i*2,2); sscanf(buf,"%x",j+i); } } if ( *DBH_KEY(node)+(4*2)) { strncpy(buf,(char *)DBH_KEY(node)+4*2,4); sscanf(buf,"%x",j+4); } sprintf(key,"%d.%d.%d.%d:%d",j[0],j[1],j[2],j[3],j[4]); fprintf(outfile,"%-30s\t%lld\n",key,*hits); /*fprintf(stdout,"writing:%-30s\t%lld\n",key,*hits);*/ } void create_output(DBHashTable *src_node, DBHashTable *tgt_node, DBHashTable *src_nodeS, DBHashTable *tgt_nodeS){ outfile=fopen(trafico_raw,"w"); if (!outfile) { printf("trafico: cannot open file %s\n",trafico_raw); return; } /* else printf("trafico: processing %s\n",trafico_raw);*/ fprintf(outfile,"Source packets*****************************\n"); DBH_foreach_sweep(src_node,operate); fprintf(outfile,"Source summary-----------------------------\n"); DBH_foreach_sweep(src_nodeS,operate); fprintf(outfile,"Target packets*****************************\n"); DBH_foreach_sweep(tgt_node,operate); fprintf(outfile,"Target summary-----------------------------\n"); DBH_foreach_sweep(tgt_nodeS,operate); fclose(outfile); if (src_node) DBH_close(src_node); if (tgt_node) DBH_close(tgt_node); if (src_nodeS) DBH_close(src_nodeS); if (tgt_nodeS) DBH_close(tgt_nodeS); _exit(123); } int count_dots(char *addr){ int i=0; char *w; w=addr; while (w){ w=strchr(w+1,'.'); if (w && w[0]==0) break; if (w) i++; } /*printf("count:%s=%d\n",addr,i);*/ return i; } int main(int argc,char **argv){ /* tcpdump: * -n Don't convert host addresses to names. This can be used to avoid DNS lookups. -nn Don't convert protocol and port numbers etc. to names either. -l Make stdout line buffered. Useful if you want to see the data while capturing it. E.g., ``tcpdump -l | tee dat'' or ``tcpdump -l > dat & tail -f dat''. -q Quick (quiet?) output. Print less protocol inforĀ mation so output lines are shorter. -t Don't print a timestamp on each dump line. -e Print the link-level header on each dump line. */ char *cmd="/usr/sbin/tcpdump -n -nn -l -q -t"; char buffer[256]; char line[LINE_MAX]; FILE *pipe; char *timestamp,*src="src.html",*tgt="tgt.html",*tmp; int linecount=0,status; DBHashTable *src_node,*tgt_node; DBHashTable *src_nodeS,*tgt_nodeS; if (fork()) { /* master process */ printf("trafico: Running in background.\n"); exit(1); } pipe=fopen("trafico.conf","r"); if (!pipe){ pipe=fopen("trafico.conf","w"); printf("trafico: Creating new configuration file: trafico.conf with defaults.\n"); if (!pipe){ printf("trafico: Cannot create configuration file: trafico.conf.\nUsing defaults anyway.\n"); } else { fprintf(pipe,"trafico_raw :%s\n",trafico_raw); fclose(pipe); } } else { while (!feof(pipe)){ char *word; fgets(line,255,pipe); if (line[0]=='#'); else if (strstr(line,"trafico_raw :")){ strtok(line,":"); word=strtok(NULL,"\n");if (!word) break; trafico_raw=whatever; strcpy(whatever,word); } else { // printf("trafico: Invalid configuration line:\n%s",line); } } fclose(pipe); } DBH_Size(NULL,256); src_node=DBH_create("src.dbh",KEY_LEN); if (!src_node) { printf("trafico: Unable to create source host database.\n"); exit(1); } DBH_writeheader(src_node); src_nodeS=DBH_create("srcS.dbh",KEY_LEN); if (!src_nodeS) { printf("trafico: Unable to create source summary database.\n"); exit(1); } DBH_writeheader(src_nodeS); tgt_node=DBH_create("tgt.dbh",KEY_LEN); if (!tgt_node) { printf("trafico: Unable to create target host database.\n"); exit(1); } DBH_writeheader(tgt_node); tgt_nodeS=DBH_create("tgtS.dbh",KEY_LEN); if (!tgt_nodeS) { printf("trafico: Unable to create target summary database.\n"); exit(1); } DBH_writeheader(tgt_nodeS); pipe = popen (cmd, "r"); if (pipe){ //if (stdin){ printf("trafico: pipe is open\n"); while (!feof(pipe)){ char *end; usleep(100); if (!fgets(line,LINE_MAX-1,pipe)) continue; line[LINE_MAX-1]=0; #if 0 printf("%s",line); //printf(".",line);fflush(NULL); #endif /* parse output */ linecount++; src=strtok(line," "); if (!src || strcmp(src,"arp")==0) goto next; tmp=strtok(NULL," "); if (!tmp) goto next; tgt=strtok(NULL,":"); if (!tgt) goto next; /* update src and tgt databases */ strcpy(buffer,src); update(src_node,buffer); if ((end=strrchr(src,'.'))!=NULL) { if (count_dots(src)>3) end[0]=0; update(src_nodeS,src); } strcpy(buffer,tgt); update(tgt_node,buffer); if ((end=strrchr(tgt,'.'))!=NULL) { if (count_dots(tgt)>3) end[0]=0; update(tgt_nodeS,tgt); } next: if (linecount % 100 == 0) { pid_t pid=0; printf("trafico: Flushing %d packets from databases.\n",linecount); fflush(NULL); DBH_close(src_node); DBH_close(tgt_node); DBH_close(src_nodeS); DBH_close(tgt_nodeS); pid=fork(); if (pid==-1) printf("Unable to fork.\n"); if (pid) { /* zombie control */ src_node=DBH_openR("src.dbh"); tgt_node=DBH_openR("tgt.dbh"); src_nodeS=DBH_openR("srcS.dbh"); tgt_nodeS=DBH_openR("tgtS.dbh"); create_output(src_node,tgt_node,src_nodeS,tgt_nodeS); printf("trafico: This should never happen!\n"); } else { src_node=DBH_open("src.dbh"); tgt_node=DBH_open("tgt.dbh"); src_nodeS=DBH_open("srcS.dbh"); tgt_nodeS=DBH_open("tgtS.dbh"); } } } printf("trafico: closing pipe\n"); pclose (pipe); } if (src_node) DBH_close(src_node); if (tgt_node) DBH_close(tgt_node); if (src_nodeS) DBH_close(src_nodeS); if (tgt_nodeS) DBH_close(tgt_nodeS); }