/* * logtool - a logfile parsing/monitoring/manipulation utility * * Copyright (C) Y2K (2000) A.L.Lambert * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Yee ole includes (I put this all in one file for my sanity) */ #include "includes.h" /* * NOTES: * * This is some LONG and UGLY code. I think there's gotta be a way to * simplify it a whole lot, and to clean up some of the ugly, but for now * it's getting the job done. Too much stuff in one file for my tastes too. * :( * * Also, all yee would be code tweakers; the order in which these functions * are called is IMPORTANT!!! Each parser function modifies event.message, * and all subsequent parsing efforts expect previous ones to have been * completed. YOU WERE WARNED!!! * */ /* function to parse up the SID's from event.message (if exists) */ short int ltm_snort_psids(char *sids) { /* some tmp data storage */ char tmp_str[LSIZE]; long int i; /* if we got SID information at the beginning of the message, then crunch it into separate variable */ if(lt_match(event.message, "^\\[.*:.*:.*\\] .*") == TRUE) { sscanf(event.message, "%s %[^\n]", sids, tmp_str); /* strip the first string */ strcpy(event.message, tmp_str); /* copy the remainder back to event.message */ strcpy(tmp_str, ""); if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { for (i = 0 ; sids[i] != '\0' ; ++i ) { if(sids[i] == '[') { strcpy(tmp_str, "\033l[\033e\033c"); } else if(sids[i] == ']') { strcat(tmp_str, "\033e\033l]\033e"); } else { sprintf(tmp_str, "%s%c", tmp_str, sids[i]); } } strcpy(sids, tmp_str); } } /* add a space to the end of it so it doesn't look so cramped later */ return 0; } /* function to parse the (snort_preprocessor) text field (if exist) */ short int ltm_snort_pproc(char *pproc) { /* some tmp data storage */ char tmp_str[LSIZE]; long int i; /* see notes in ltm_snort_psids(); above */ if(lt_match(event.message, "^\\(.*_.*\\) ") == TRUE) { sscanf(event.message, "%s %[^\n]", pproc, tmp_str); strcpy(event.message, tmp_str); /* do some special effects if our output format == ansi */ if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { for (i = 0 ; pproc[i] != '\0' ; ++i ) { if(pproc[i] == '(') { strcpy(tmp_str, "\033l(\033e\033c"); } else if(pproc[i] == ')') { strcat(tmp_str, "\033e\033l)\033e"); } else { sprintf(tmp_str, "%s%c", tmp_str, pproc[i]); } } strcpy(pproc, tmp_str); } } return 0; } /* function to parse the "x.x.x.x:x -> x.x.x.x:x" from the end of a Snort message (if exist) */ short int ltm_snort_pips(char *src, char *src_prt, char *dst, char *dst_prt, short int resolv) { long int i, j; char *ptr; char tmp_str[LSIZE]; ptr = event.message; /* backspace from the end of the line, counting spaces to three */ for(i = (strlen(event.message) - 1), j = 0; j < 3; --i) { if(event.message[i] == ' ') ++j; } /* increment the ptr to the appropriate spot */ ptr = (ptr + i + 1); /* null byte it (will insert null byte into event.message * to clip the part we're about to parse separately) */ ptr[0] = '\0'; ++ptr; /* move ptr forward so we can work with data directly */ if(strstr(ptr, ":") != NULL) { /* then we've got a src:src_prt scenario */ sscanf(ptr, "%[^:]:%s -> %[^:]:%s", src, src_prt, dst, dst_prt); } else { /* this was probably an ICMP message; IP's only */ sscanf(ptr, "%s -> %s", src, dst); strcpy(dst_prt, ""); /* overkill way to make sure variable is blank */ strcpy(src_prt, ""); } if(resolv == TRUE) { ptr = get_host(src); if(ptr != NULL) { strcpy(tmp_str, src); strcpy(src, ptr); strcat(src, "("); strcat(src, tmp_str); strcat(src, ")"); } ptr = get_host(dst); if(ptr != NULL) { strcpy(tmp_str, dst); strcpy(dst, ptr); strcat(dst, "("); strcat(dst, tmp_str); strcat(dst, ")"); } if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { sprintf(tmp_str, "\033l(\033e\033w"); lt_strep(src, 512, "(", tmp_str); lt_strep(dst, 512, "(", tmp_str); sprintf(tmp_str, "\033l)\033e"); lt_strep(src, 512, ")", tmp_str); lt_strep(dst, 512, ")", tmp_str); } } /* if we're making an ANSI event, then do some special fancy tricks. */ if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { /* yeah, I could do all the below as a single sprintf(), and I may be doing * that soon. */ strcpy(tmp_str, "\033W"); strcat(tmp_str, src); strcat(tmp_str, "\033e"); strcpy(src, tmp_str); /* ditto */ strcpy(tmp_str, "\033W"); strcat(tmp_str, dst); strcat(tmp_str, "\033e"); strcpy(dst, tmp_str); /* if we got src/dst port's, then do the deed to them too */ if(src_prt[0] != '\0') { strcpy(tmp_str, "\033W"); strcat(tmp_str, src_prt); strcat(tmp_str, "\033e"); strcpy(src_prt, tmp_str); strcpy(tmp_str, "\033W"); strcat(tmp_str, dst_prt); strcat(tmp_str, "\033e"); strcpy(dst_prt, tmp_str); } } return 0; } /* function to parse the {PROTOCOL} text from a Snort event (if exist) */ short int ltm_snort_pproto(char *proto) { char *ptr = NULL; char tmp_str[LSIZE]; /* if we got a TCP, UDP, or ICMP message */ if(lt_match(event.message, "\\{TCP\\}$|\\{UDP\\}$|\\{ICMP\\}$") == TRUE) { /* parse it out of there */ ptr = strrchr(event.message, ' '); ptr[0] = '\0'; ++ptr; strcpy(proto, ptr); } /* you know about the ANSI prettyfication by now, don't you? */ if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { strcpy(tmp_str, "\033l"); strcat(tmp_str, "{"); strcat(tmp_str, "\033e"); strcat(tmp_str, "\033C"); lt_strep(proto, 512, "{", tmp_str); strcpy(tmp_str, "\033l"); strcat(tmp_str, "}"); strcat(tmp_str, "\033e"); lt_strep(proto, 512, "}", tmp_str); } return 0; } /* function to parse the [Priority: .*] text from a Snort event (if exist) */ short int ltm_snort_pprior(char *prior) { char *ptr; char tmp_str[LSIZE]; if((ptr = strstr(event.message, "[Priority: ")) != NULL) { strcpy(prior, ptr); --ptr; ptr[0] = '\0'; } lt_strep(prior, 512, "[Priority: ", "[Pri: "); if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { strcpy(tmp_str, "\033l"); strcat(tmp_str, "["); strcat(tmp_str, "\033e"); strcat(tmp_str, "\033c"); lt_strep(prior, 512, "[", tmp_str); strcpy(tmp_str, "\033l"); strcat(tmp_str, "]"); strcat(tmp_str, "\033e"); lt_strep(prior, 512, "]", tmp_str); } return 0; } /* function to parse the [Classification: .*] text from a snrot event (if exist) */ short int ltm_snort_pclass(char *class) { char *ptr; char tmp_str[LSIZE]; if((ptr = strstr(event.message, "[Classification: ")) != NULL) { strcpy(class, ptr); --ptr; ptr[0] = '\0'; } lt_strep(class, 512, "[Classification: ", "["); if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { strcpy(tmp_str, "\033l"); strcat(tmp_str, "["); strcat(tmp_str, "\033e"); strcat(tmp_str, "\033c"); lt_strep(class, 512, "[", tmp_str); strcpy(tmp_str, "\033l"); strcat(tmp_str, "]"); strcat(tmp_str, "\033e"); lt_strep(class, 512, "]", tmp_str); } return 0; } /* * yee ole showtime function. This is the only function which should be * called by any external routines. */ short int ltm_snort() { /* various varibles and such are in mods.h struct SNORT */ /* we use these in parsing and such */ char msg_tmp[LSIZE]; /* some TRUE/FALSE variables for display opts */ short int modsn_dispclass = FALSE; short int modsn_dispprior = FALSE; short int modsn_dispproto = FALSE; short int modsn_2lines = FALSE; short int modsn_dispsids = FALSE; short int modsn_dispproc = FALSE; short int modsn_resolvips = FALSE; /* setup the display opt's based no environment */ modsn_dispclass = mod_varcheck("modsn_dispclass"); modsn_dispprior = mod_varcheck("modsn_dispprior"); modsn_dispproto = mod_varcheck("modsn_dispproto"); modsn_dispsids = mod_varcheck("modsn_dispsids"); modsn_dispproc = mod_varcheck("modsn_dispproc"); modsn_2lines = mod_varcheck("modsn_2lines"); modsn_resolvips = mod_varcheck("modsn_resolvips"); /* Figure out what color this message should be */ lt_set_event_color(); /* parse up the basics (date format's, prog/src, etc) */ mod_premsg_setup(); /* initialize sids, and parse it if we can */ strcpy(sn.sids, ""); ltm_snort_psids(sn.sids); /* ditto for pproc */ strcpy(sn.pproc, ""); ltm_snort_pproc(sn.pproc); /* ok, got the first parts of the line processed, head * for the rear of the line and do the IP's */ ltm_snort_pips(sn.src, sn.src_prt, sn.dst, sn.dst_prt, modsn_resolvips); /* see comments above regarding sids and pproc */ strcpy(sn.proto, ""); ltm_snort_pproto(sn.proto); strcpy(sn.prior, ""); ltm_snort_pprior(sn.prior); strcpy(sn.class, ""); ltm_snort_pclass(sn.class); /* ok, now we're ready to setup the event.pmsg * (which is what we show the user later :) * * If we got display orders, and variables not == nothing, then do */ /* this puts the main message, in appropriate colors, into the output */ sprintf(msg_tmp, "%s%s%s", event.pcolor, event.message, "\033e"); strcpy(sn.msg, event.message); strcat(event.pmsg, " "); strcat(event.pmsg, msg_tmp); if(modsn_dispproc == TRUE && sn.pproc[0] != '\0') { strcat(event.pmsg, " "); strcat(event.pmsg, sn.pproc); } if(modsn_dispsids == TRUE && sn.sids[0] != '\0') { strcat(event.pmsg, " "); strcat(event.pmsg, sn.sids); } /* if we want a 2line display, then do this */ if(modsn_2lines == TRUE && cf.outfmt != OUTPUT_CSV) strcat(event.pmsg, "\n\t"); if(modsn_dispclass == TRUE && sn.class[0] != '\0') { strcat(event.pmsg, " "); strcat(event.pmsg, sn.class); } if(modsn_dispprior == TRUE && sn.prior[0] != '\0') { strcat(event.pmsg, " "); strcat(event.pmsg, sn.prior); } if(modsn_dispproto == TRUE && sn.proto[0] != '\0') { strcat(event.pmsg, " "); strcat(event.pmsg, sn.proto); } if(sn.src_prt[0] != '\0') { if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { sprintf(msg_tmp, "%s\033l:%s \033l-> %s\033l:\033e%s", sn.src, sn.src_prt, sn.dst, sn.dst_prt); } else { sprintf(msg_tmp, "%s:%s -> %s:%s", sn.src, sn.src_prt, sn.dst, sn.dst_prt); } } else { if(cf.outfmt == OUTPUT_ANSI || cf.outfmt == OUTPUT_HTML) { sprintf(msg_tmp, "%s \033l-> %s", sn.src, sn.dst); } else { sprintf(msg_tmp, "%s -> %s", sn.src, sn.dst); } } /* final finishing off of event.pmsg */ strcat(event.pmsg, " "); strcat(event.pmsg, msg_tmp); event.m.snort = &sn; /* we did some debug testing with the code block below */ /* fprintf(stderr, "msg:%s\n", event.m.snort->msg); fprintf(stderr, "dst:prt:%s:%s\n", event.m.snort->dst, event.m.snort->dst_prt); fprintf(stderr, "src:prt:%s:%s\n", event.m.snort->src, event.m.snort->src_prt); fprintf(stderr, "sids:%s\n", event.m.snort->sids); fprintf(stderr, "pproc:%s\n", event.m.snort->pproc); fprintf(stderr, "proto:%s\n", event.m.snort->proto); fprintf(stderr, "class:%s\n", event.m.snort->class); fprintf(stderr, "prior:%s\n", event.m.snort->prior); */ /* return 0; We really should be checking for errors above, * and bombing out if we got something bad, but hey, such is life. */ return 0; }