/* $Id: parser.c,v 1.11 2006/03/03 17:27:38 bhockney Exp $ */ /* (C) 2004-2006 by Bob Hockney * * Based on fwlogwatch written by * * Boris Wesslowski * * * * syslog parser for wfwl_syslog * * * * This code is distributed under the terms of GNU GPL */ #include #include #include #include #include #include #include "parser.h" #include "compare.h" #include "utils.h" #include #include #include #include #include #include "main.h" #include "ipchains.h" #include "netfilter.h" #include "ipfilter.h" #include "win_xp.h" #include "ipfw.h" extern struct options opt; extern struct selection *selection; extern struct conn_data *first; extern struct fields_used fields_used; unsigned long int rowid = 0; struct conn_data_sum *data_sum = NULL; /* adds detail for summarized lines for populating cache */ void add_data_sum(struct log_line *line, unsigned long int rownum) { struct conn_data_sum *sum; sum = xmalloc(sizeof(struct conn_data_sum)); sum->rowid = rownum; sum->protocol = line->protocol; sum->shost = line->shost; sum->dhost = line->dhost; sum->sport = line->sport; sum->dport = line->dport; sum->next = data_sum; data_sum = sum; } /* adds a row to data for output */ void add_entry() { struct conn_data *data; data = xmalloc(sizeof(struct conn_data)); xstrncpy(data->filename, opt.line->filename, FILESIZE); data->rowid = ++rowid; data->linenum = opt.line->linenum; data->count = opt.line->count; data->local_time = opt.line->time; data->start_time = opt.line->time; data->end_time = opt.line->time; xstrncpy(data->hostname, opt.line->hostname, SHOSTLEN); xstrncpy(data->log_label, opt.line->log_label, SHORTLEN); xstrncpy(data->branchname, opt.line->branchname, SHORTLEN); xstrncpy(data->interface, opt.line->interface, SHORTLEN); /* drop this line */ data->protocol = opt.line->protocol; data->datalen = opt.line->datalen; data->shost = opt.line->shost; xstrncpy(data->shostname, opt.line->shostname, SHORTLEN); data->sport = opt.line->sport; xstrncpy(data->sservice, opt.line->sservice, SHORTLEN); data->dhost = opt.line->dhost; xstrncpy(data->dhostname, opt.line->dhostname, SHORTLEN); data->dport = opt.line->dport; xstrncpy(data->dservice, opt.line->dservice, SHORTLEN); data->flags = opt.line->flags; xstrncpy(data->raw_mac, opt.line->raw_mac, SHORTLEN); data->fwmark = opt.line->fwmark; xstrncpy(data->inif, opt.line->inif, SHORTLEN); xstrncpy(data->outif, opt.line->outif, SHORTLEN); data->tos = opt.line->tos; data->ttl = opt.line->ttl; data->ihl = opt.line->ihl; data->csum = opt.line->csum; data->ipid = opt.line->ipid; data->fragoff = opt.line->fragoff; data->tcp_seq = opt.line->tcp_seq; data->tcp_ack_seq = opt.line->tcp_ack_seq; data->tcp_window = opt.line->tcp_window; data->tcp_urgp = opt.line->tcp_urgp; data->udp_len = opt.line->udp_len; data->icmp_type = opt.line->icmp_type; data->icmp_code = opt.line->icmp_code; data->icmp_echoid = opt.line->icmp_echoid; data->icmp_echoseq = opt.line->icmp_echoseq; data->icmp_gw = opt.line->icmp_gw; data->icmp_mtu = opt.line->icmp_mtu; data->ahesp_spi = opt.line->ahesp_spi; if (opt.resolve_hosts && CACHE_POPULATE) add_data_sum(opt.line, rowid); data->next = first; first = data; opt.report_rows++; } /* called when parsed line is not excluded by specification */ void build_list() { struct conn_data *this; char stime[TIMESIZE]; int j; /* first (file scope, static) contains list to output */ /* if new row matches row in struct first, count is incremented by opt.line->count (after repeats) */ /* if new row does not match, it is added to struct first with count = opt.line->count */ /* Summarization is done here */ if (opt.mode == LOG_SUMMARY) { this = first; while (this != NULL) { if ((fields_used.dhost) && (this->dhost.s_addr != opt.line->dhost.s_addr)) {goto no_match;} if ((fields_used.shost) && (this->shost.s_addr != opt.line->shost.s_addr)) {goto no_match;} if ((fields_used.dport) && (this->dport != opt.line->dport)) {goto no_match;} if ((fields_used.sport) && (this->sport != opt.line->sport)) {goto no_match;} if ((fields_used.protocol) && (this->protocol != opt.line->protocol)) {goto no_match;} if ((fields_used.flags) && (this->flags != opt.line->flags)) {goto no_match;} if ((fields_used.inif) && (strncmp (this->interface, opt.line->interface, SHORTLEN) != 0)) {goto no_match;} if ((fields_used.log_label) && (strncmp (this->log_label, opt.line->log_label, SHORTLEN) != 0)) {goto no_match;} if ((fields_used.hostname) && (strncmp (this->hostname, opt.line->hostname, SHOSTLEN) != 0)) {goto no_match;} if ((fields_used.outif) && (strncmp(this->outif, opt.line->outif, SHORTLEN) != 0)) {goto no_match;} if ((fields_used.fwmark) && (this->fwmark != opt.line->fwmark)) {goto no_match;} if ((fields_used.raw_mac) && (strncmp(this->raw_mac, opt.line->raw_mac, SHORTLEN) != 0)) {goto no_match;} if ((fields_used.ipid) && (this->ipid != opt.line->ipid)) {goto no_match;} if ((fields_used.csum) && (this->csum != opt.line->csum)) {goto no_match;} if ((fields_used.fragoff) && (this->fragoff != opt.line->fragoff)) {goto no_match;} if ((fields_used.ihl) && (this->ihl != opt.line->ihl)) {goto no_match;} if ((fields_used.tos) && (this->tos != opt.line->tos)) {goto no_match;} if ((fields_used.ttl) && (this->ttl != opt.line->ttl)) {goto no_match;} if ((fields_used.icmp_type) && (this->icmp_type != opt.line->icmp_type)) {goto no_match;} if ((fields_used.icmp_code) && (this->icmp_code != opt.line->icmp_code)) {goto no_match;} if ((fields_used.totlen) && (this->datalen != opt.line->datalen)) {goto no_match;} if ((fields_used.tcp_seq) && (this->tcp_seq != opt.line->tcp_seq)) {goto no_match;} if ((fields_used.tcp_ack_seq) && (this->tcp_ack_seq != opt.line->tcp_ack_seq)) {goto no_match;} if ((fields_used.tcp_window) && (this->tcp_window != opt.line->tcp_window)) {goto no_match;} if ((fields_used.tcp_urgp) && (this->tcp_urgp != opt.line->tcp_urgp)) {goto no_match;} if ((fields_used.udp_len) && (this->udp_len != opt.line->udp_len)) {goto no_match;} if ((fields_used.icmp_echoid) && (this->icmp_echoid != opt.line->icmp_echoid)) {goto no_match;} if ((fields_used.icmp_echoseq) && (this->icmp_echoseq != opt.line->icmp_echoseq)) {goto no_match;} if ((fields_used.icmp_gw) && (this->icmp_gw.s_addr != opt.line->icmp_gw.s_addr)) {goto no_match;} if ((fields_used.icmp_mtu) && (this->icmp_mtu != opt.line->icmp_mtu)) {goto no_match;} if ((fields_used.ahesp_spi) && (this->ahesp_spi != opt.line->ahesp_spi)) {goto no_match;} if (opt.line->time >= this->end_time || opt.line->time <= this->start_time) { if (opt.line->time >= this->end_time) { this->end_time = opt.line->time; } if (opt.line->time <= this->start_time) { this->start_time = opt.line->time; } } else { if(opt.verbose >= VERBOSE_WARNING && strcmp(this->filename, opt.line->filename) == 0) { strftime(stime, TIMESIZE, "%b %d %H:%M:%S", localtime(&this->end_time)); fprintf(stderr, "Timewarp in log file (%s", stime); strftime(stime, TIMESIZE, "%b %d %H:%M:%S", localtime(&opt.line->time)); fprintf(stderr, " > %s).\n", stime); } } this->count += opt.line->count; for (j = opt.line->count; j > 1; j--) { opt.matched_entries++; } if (opt.resolve_hosts && CACHE_POPULATE) add_data_sum(opt.line, this->rowid); return; no_match: this = this->next; } /* end while (this != NULL) */ } for (j = opt.line->count; j > 1; j--) { opt.matched_entries++; } if (opt.mode == LOG_SUMMARY) { add_entry(); } else { opt.line->count = 1; for (j = opt.line->count; j > 0; j--) { add_entry(); } } } /* parses a logfile line */ /* called with input = log line and linenum = line number */ unsigned char parse_line(char *input, int linenum) { unsigned char retval; char *pnt; /* if repeated message, update count */ pnt = strstr(input, " last message repeated "); if (pnt != NULL) { if (opt.repeated == 1) { char month[4], time[9], name[SHOSTLEN], rest[BUFSIZE]; int day; retval = sscanf(input, "%3s %2d %8s %" SHOSTLEN_S "s %" BUFSIZE_S "s", month, &day, time, name, rest); if (retval == 5) { if(strncmp(opt.line->hostname, name, SHOSTLEN) == 0) { int repeated; repeated = atoi(pnt+23); /* opt.orig_count is 0 or 1 */ opt.line->count = opt.orig_count * repeated; build_list(); if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "r"); return PARSE_OK; } } if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "_"); return PARSE_NO_HIT; } } /* try parsers until one works */ if ((opt.format & PARSER_IPCHAINS) && (strstr(input, " kernel: Packet log: "))) { /* For ipchains log format see (in kernel 2.2 source) */ /* /usr/src/linux/net/ipv4/ip_fw.c */ retval = flex_ipchains(input, linenum); } else if ((opt.format & PARSER_NETFILTER) && (strstr(input, " OUT="))) { /* For netfilter log format see (in kernel 2.4 source) */ /* /usr/src/linux/net/ipv4/netfilter/ipt_LOG.c */ retval = flex_netfilter(input, linenum); } else if ((opt.format & PARSER_IPFILTER) && (strstr(input, " ipmon"))) { /* For ipfilter log format see the source */ /* http://coombs.anu.edu.au/~avalon/ */ retval = flex_ipfilter(input, linenum); } else if ((opt.format & PARSER_IPFW) && (strstr(input, " ipfw: "))) { retval = flex_ipfw(input, linenum); } else if (opt.format & PARSER_WIN_XP){ retval = win_xp(input, linenum); } else { retval = PARSE_NO_HIT; } if (retval == PARSE_NO_HIT) { if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "_"); return PARSE_NO_HIT; } /* true if successfully matched my a parser */ if (retval == PARSE_OK) { { unsigned int match = P_MATCH_NONE; unsigned long int match_inc = MATCH_MUL_NONE; unsigned long int match_exc = MATCH_MUL_NONE; struct selection *sel; struct in_addr *inp; regex_t *buf; int res; time_t time; /* set match = P_MATCH_EXC to exclude parsed line */ /* For fields that allow multiple criteria, all rules must be * * tested before verdict can be reached, so match is not used * * in favor of match_exc, which is checked after all rules * * have been processed. */ sel = selection; while (sel != NULL && match != P_MATCH_EXC) { if (sel->have_value == -1) { sel = sel->next; continue; } switch (sel->field) { case SEL_LOCAL_HOST: buf = xmalloc(sizeof(regex_t)); res = regcomp(buf, sel->svalue, REG_NOSUB||REG_EXTENDED); if (res) { /* error */ if (opt.verbose >= VERBOSE_NOTICE) fprintf(stderr, "error %i in regex expression %s\n", res, sel->svalue); break; } res = regexec(buf, opt.line->hostname, 0, NULL, 0); if ((res == 0 && sel->invert) || (res == REG_NOMATCH && !sel->invert)) match = P_MATCH_EXC; regfree(buf); free (buf); break; case SEL_PREFIX: buf = xmalloc(sizeof(regex_t)); res = regcomp(buf, sel->svalue, REG_NOSUB||REG_EXTENDED); if (res) { /* error */ if (opt.verbose >= VERBOSE_NOTICE) fprintf(stderr, "error %i in regex expression %s\n", res, sel->svalue); break; } res = regexec(buf, opt.line->log_label, 0, NULL, 0); if ((res == 0 && sel->invert) || (res == REG_NOMATCH && !sel->invert)) match = P_MATCH_EXC; regfree(buf); free (buf); break; case SEL_SOURCEHOST: if ((sel->invert && (match_exc & MATCH_SRC_HOST)) || (!sel->invert && (match_inc & MATCH_SRC_HOST))) break; inp = xmalloc(sizeof(struct in_addr)); if (convert_ip(sel->svalue, inp)) {fprintf(stderr, "Couldn't convert %s\n", sel->svalue); break;} /* error */ if ((((ntohl(opt.line->shost.s_addr) & sel->netmask) != (ntohl(inp->s_addr) & sel->netmask)) && !(sel->invert)) \ || ((ntohl(opt.line->shost.s_addr) & sel->netmask) == (ntohl(inp->s_addr) & sel->netmask) && (sel->invert)) ) { match_exc |= MATCH_SRC_HOST; match_inc &= ~MATCH_SRC_HOST; } else { match_inc |= MATCH_SRC_HOST; match_exc &= ~MATCH_SRC_HOST; } free(inp); break; case SEL_DESTHOST: if ((sel->invert && (match_exc & MATCH_DST_HOST)) || (!sel->invert && (match_inc & MATCH_DST_HOST))) break; inp = xmalloc(sizeof(struct in_addr)); if (convert_ip(sel->svalue, inp)) {fprintf(stderr, "Couldn't convert %s\n", sel->svalue); break;} /* error */ if ((((ntohl(opt.line->dhost.s_addr) & sel->netmask) != (ntohl(inp->s_addr) & sel->netmask)) && !(sel->invert)) \ || ((ntohl(opt.line->dhost.s_addr) & sel->netmask) == (ntohl(inp->s_addr) & sel->netmask) && (sel->invert)) ) { match_exc |= MATCH_DST_HOST; match_inc &= ~MATCH_DST_HOST; } else { match_inc |= MATCH_DST_HOST; match_exc &= ~MATCH_DST_HOST; } free(inp); break; case SEL_PROTOCOL: if ((sel->invert && (match_exc & MATCH_PROTOCOL)) || (!sel->invert && (match_inc & MATCH_PROTOCOL))) break; if (((opt.line->protocol < sel->value || opt.line->protocol > sel->max_value) && !(sel->invert)) \ || (opt.line->protocol >= sel->value && opt.line->protocol <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_PROTOCOL; match_inc &= ~MATCH_PROTOCOL; } else { match_inc |= MATCH_PROTOCOL; match_exc &= ~MATCH_PROTOCOL; } break; case SEL_IN_IF: buf = xmalloc(sizeof(regex_t)); res = regcomp(buf, sel->svalue, REG_NOSUB||REG_EXTENDED); if (res) { /* error */ if (opt.verbose >= VERBOSE_NOTICE) fprintf(stderr, "error %i in regex expression %s\n", res, sel->svalue); break; } res = regexec(buf, opt.line->inif, 0, NULL, 0); if ((res == 0 && sel->invert) || (res == REG_NOMATCH && !sel->invert)) match = P_MATCH_EXC; regfree(buf); free (buf); break; case SEL_OUT_IF: buf = xmalloc(sizeof(regex_t)); res = regcomp(buf, sel->svalue, REG_NOSUB||REG_EXTENDED); if (res) { /* error */ if (opt.verbose >= VERBOSE_NOTICE) fprintf(stderr, "error %i in regex expression %s\n", res, sel->svalue); break; } res = regexec(buf, opt.line->outif, 0, NULL, 0); if ((res == 0 && sel->invert) || (res == REG_NOMATCH && !sel->invert)) match = P_MATCH_EXC; regfree(buf); free (buf); break; case SEL_ICMP_TYPE: if (opt.line->protocol != 1 || (sel->invert && (match_exc & MATCH_ICMP_TYPE)) || (!sel->invert && (match_inc & MATCH_ICMP_TYPE))) break; if (((opt.line->icmp_type < sel->value || opt.line->icmp_type > sel->max_value) && !(sel->invert)) \ || (opt.line->icmp_type >= sel->value && opt.line->icmp_type <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_ICMP_TYPE; match_inc &= ~MATCH_ICMP_TYPE; } else { match_inc |= MATCH_ICMP_TYPE; match_exc &= ~MATCH_ICMP_TYPE; } break; case SEL_ICMP_CODE: if (opt.line->protocol != 1 || (sel->invert && (match_exc & MATCH_ICMP_CODE)) || (!sel->invert && (match_inc & MATCH_ICMP_CODE))) break; if (((opt.line->icmp_code < sel->value || opt.line->icmp_code > sel->max_value) && !(sel->invert)) \ || (opt.line->icmp_code >= sel->value && opt.line->icmp_code <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_ICMP_CODE; match_inc &= ~MATCH_ICMP_CODE; } else { match_inc |= MATCH_ICMP_CODE; match_exc &= ~MATCH_ICMP_CODE; } break; case SEL_AHESP_SPI: if ((sel->invert && (match_exc & MATCH_AHESP_SPI)) || (!sel->invert && (match_inc & MATCH_AHESP_SPI))) break; if (((opt.line->ahesp_spi < sel->value || opt.line->ahesp_spi > sel->max_value) && !(sel->invert)) \ || (opt.line->ahesp_spi >= sel->value && opt.line->ahesp_spi <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_AHESP_SPI; match_inc &= ~MATCH_AHESP_SPI; } else { match_inc |= MATCH_AHESP_SPI; match_exc &= ~MATCH_AHESP_SPI; } break; case SEL_UDP_DPORT: if (opt.line->protocol != 17 || (sel->invert && (match_exc & MATCH_UDP_DPORT)) || (!sel->invert && (match_inc & MATCH_UDP_DPORT))) break; if (((opt.line->dport < sel->value || opt.line->dport > sel->max_value) && !(sel->invert)) \ || (opt.line->dport >= sel->value && opt.line->dport <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_UDP_DPORT; match_inc &= ~MATCH_UDP_DPORT; } else { match_inc |= MATCH_UDP_DPORT; match_exc &= ~MATCH_UDP_DPORT; } break; case SEL_UDP_SPORT: if (opt.line->protocol != 17 || (sel->invert && (match_exc & MATCH_UDP_SPORT)) || (!sel->invert && (match_inc & MATCH_UDP_SPORT))) break; if (((opt.line->sport < sel->value || opt.line->sport > sel->max_value) && !(sel->invert)) \ || (opt.line->sport >= sel->value && opt.line->sport <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_UDP_SPORT; match_inc &= ~MATCH_UDP_SPORT; } else { match_inc |= MATCH_UDP_SPORT; match_exc &= ~MATCH_UDP_SPORT; } break; case SEL_TCP_DPORT: if (opt.line->protocol != 6 || (sel->invert && (match_exc & MATCH_TCP_DPORT)) || (!sel->invert && (match_inc & MATCH_TCP_DPORT))) break; if (((opt.line->dport < sel->value || opt.line->dport > sel->max_value) && !(sel->invert)) \ || (opt.line->dport >= sel->value && opt.line->dport <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_DPORT; match_inc &= ~MATCH_TCP_DPORT; } else { match_inc |= MATCH_TCP_DPORT; match_exc &= ~MATCH_TCP_DPORT; } break; case SEL_TCP_SPORT: if (opt.line->protocol != 6 || (sel->invert && (match_exc & MATCH_TCP_SPORT)) || (!sel->invert && (match_inc & MATCH_TCP_SPORT))) break; if (((opt.line->sport < sel->value || opt.line->sport > sel->max_value) && !(sel->invert)) \ || (opt.line->sport >= sel->value && opt.line->sport <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_SPORT; match_inc &= ~MATCH_TCP_SPORT; } else { match_inc |= MATCH_TCP_SPORT; match_exc &= ~MATCH_TCP_SPORT; } break; case SEL_MIN_DATE: time = get_date(sel->svalue, NULL); if (opt.line->time < time) match = P_MATCH_EXC; break; case SEL_MAX_DATE: time = get_date(sel->svalue, NULL); if (opt.line->time > time) match = P_MATCH_EXC; break; case SEL_TCP_FLAGS: if (opt.line->protocol == 6 && !(opt.line->flags & TCP_FLAGS_MATCH)) { if (sel->value & TCP_OPTS_EXACT) { if (opt.line->flags == (sel->value ^ TCP_OPTS_EXACT)) break; } else { if (!(opt.line->flags | sel->value) || (opt.line->flags & sel->value)) break; } match = P_MATCH_EXC; } break; case SEL_IP_TOS: if ((sel->invert && (match_exc & MATCH_IP_TOS)) || (!sel->invert && (match_inc & MATCH_IP_TOS))) break; if (((opt.line->tos < sel->value || opt.line->tos > sel->max_value) && !(sel->invert)) \ || (opt.line->tos >= sel->value && opt.line->tos <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_TOS; match_inc &= ~MATCH_IP_TOS; } else { match_inc |= MATCH_IP_TOS; match_exc &= ~MATCH_IP_TOS; } break; case SEL_IP_TTL: if ((sel->invert && (match_exc & MATCH_IP_TTL)) || (!sel->invert && (match_inc & MATCH_IP_TTL))) break; if (((opt.line->ttl < sel->value || opt.line->ttl > sel->max_value) && !(sel->invert)) \ || (opt.line->ttl >= sel->value && opt.line->ttl <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_TTL; match_inc &= ~MATCH_IP_TTL; } else { match_inc |= MATCH_IP_TTL; match_exc &= ~MATCH_IP_TTL; } break; case SEL_IP_IHL: if ((sel->invert && (match_exc & MATCH_IP_IHL)) || (!sel->invert && (match_inc & MATCH_IP_IHL))) break; if (((opt.line->ihl < sel->value || opt.line->ihl > sel->max_value) && !(sel->invert)) \ || (opt.line->ihl >= sel->value && opt.line->ihl <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_IHL; match_inc &= ~MATCH_IP_IHL; } else { match_inc |= MATCH_IP_IHL; match_exc &= ~MATCH_IP_IHL; } break; case SEL_IP_TOTLEN: if ((sel->invert && (match_exc & MATCH_IP_TOTLEN)) || (!sel->invert && (match_inc & MATCH_IP_TOTLEN))) break; if (((opt.line->datalen < sel->value || opt.line->datalen > sel->max_value) && !(sel->invert)) \ || (opt.line->datalen >= sel->value && opt.line->datalen <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_TOTLEN; match_inc &= ~MATCH_IP_TOTLEN; } else { match_inc |= MATCH_IP_TOTLEN; match_exc &= ~MATCH_IP_TOTLEN; } break; case SEL_IP_ID: if ((sel->invert && (match_exc & MATCH_IP_ID)) || (!sel->invert && (match_inc & MATCH_IP_ID))) break; if (((opt.line->ipid < sel->value || opt.line->ipid > sel->max_value) && !(sel->invert)) \ || (opt.line->ipid >= sel->value && opt.line->ipid <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_ID; match_inc &= ~MATCH_IP_ID; } else { match_inc |= MATCH_IP_ID; match_exc &= ~MATCH_IP_ID; } break; case SEL_IP_CSUM: if ((sel->invert && (match_exc & MATCH_IP_CSUM)) || (!sel->invert && (match_inc & MATCH_IP_CSUM))) break; if (((opt.line->csum < sel->value || opt.line->csum > sel->max_value) && !(sel->invert)) \ || (opt.line->csum >= sel->value && opt.line->csum <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_CSUM; match_inc &= ~MATCH_IP_CSUM; } else { match_inc |= MATCH_IP_CSUM; match_exc &= ~MATCH_IP_CSUM; } break; case SEL_IP_FRAGOFF: if ((sel->invert && (match_exc & MATCH_IP_FRAGOFF)) || (!sel->invert && (match_inc & MATCH_IP_FRAGOFF))) break; if (((opt.line->fragoff < sel->value || opt.line->fragoff > sel->max_value) && !(sel->invert)) \ || (opt.line->fragoff >= sel->value && opt.line->fragoff <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_IP_FRAGOFF; match_inc &= ~MATCH_IP_FRAGOFF; } else { match_inc |= MATCH_IP_FRAGOFF; match_exc &= ~MATCH_IP_FRAGOFF; } break; case SEL_OOB_MARK: if ((sel->invert && (match_exc & MATCH_OOB_MARK)) || (!sel->invert && (match_inc & MATCH_OOB_MARK))) break; if (((opt.line->fwmark < sel->value || opt.line->fwmark > sel->max_value) && !(sel->invert)) \ || (opt.line->fwmark >= sel->value && opt.line->fwmark <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_OOB_MARK; match_inc &= ~MATCH_OOB_MARK; } else { match_inc |= MATCH_OOB_MARK; match_exc &= ~MATCH_OOB_MARK; } break; case SEL_TCP_SEQ: if ((sel->invert && (match_exc & MATCH_TCP_SEQ)) || (!sel->invert && (match_inc & MATCH_TCP_SEQ))) break; if (((opt.line->tcp_seq < sel->value || opt.line->tcp_seq > sel->max_value) && !(sel->invert)) \ || (opt.line->tcp_seq >= sel->value && opt.line->tcp_seq <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_SEQ; match_inc &= ~MATCH_TCP_SEQ; } else { match_inc |= MATCH_TCP_SEQ; match_exc &= ~MATCH_TCP_SEQ; } break; case SEL_TCP_ACKSEQ: if ((sel->invert && (match_exc & MATCH_TCP_ACKSEQ)) || (!sel->invert && (match_inc & MATCH_TCP_ACKSEQ))) break; if (((opt.line->tcp_ack_seq < sel->value || opt.line->tcp_ack_seq > sel->max_value) && !(sel->invert)) \ || (opt.line->tcp_ack_seq >= sel->value && opt.line->tcp_ack_seq <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_ACKSEQ; match_inc &= ~MATCH_TCP_ACKSEQ; } else { match_inc |= MATCH_TCP_ACKSEQ; match_exc &= ~MATCH_TCP_ACKSEQ; } break; case SEL_TCP_WINDOW: if ((sel->invert && (match_exc & MATCH_TCP_WINDOW)) || (!sel->invert && (match_inc & MATCH_TCP_WINDOW))) break; if (((opt.line->tcp_window < sel->value || opt.line->tcp_window > sel->max_value) && !(sel->invert)) \ || (opt.line->tcp_window >= sel->value && opt.line->tcp_window <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_WINDOW; match_inc &= ~MATCH_TCP_WINDOW; } else { match_inc |= MATCH_TCP_WINDOW; match_exc &= ~MATCH_TCP_WINDOW; } break; case SEL_TCP_URGP: if ((sel->invert && (match_exc & MATCH_TCP_URGP)) || (!sel->invert && (match_inc & MATCH_TCP_URGP))) break; if (((opt.line->tcp_urgp < sel->value || opt.line->tcp_urgp > sel->max_value) && !(sel->invert)) \ || (opt.line->tcp_urgp >= sel->value && opt.line->tcp_urgp <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_TCP_URGP; match_inc &= ~MATCH_TCP_URGP; } else { match_inc |= MATCH_TCP_URGP; match_exc &= ~MATCH_TCP_URGP; } break; case SEL_ICMP_ECHOID: if ((sel->invert && (match_exc & MATCH_ICMP_ECHOID)) || (!sel->invert && (match_inc & MATCH_ICMP_ECHOID))) break; if (((opt.line->icmp_echoid < sel->value || opt.line->icmp_echoid > sel->max_value) && !(sel->invert)) \ || (opt.line->icmp_echoid >= sel->value && opt.line->icmp_echoid <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_ICMP_ECHOID; match_inc &= ~MATCH_ICMP_ECHOID; } else { match_inc |= MATCH_ICMP_ECHOID; match_exc &= ~MATCH_ICMP_ECHOID; } break; case SEL_ICMP_ECHOSEQ: if ((sel->invert && (match_exc & MATCH_ICMP_ECHOSEQ)) || (!sel->invert && (match_inc & MATCH_ICMP_ECHOSEQ))) break; if (((opt.line->icmp_echoseq < sel->value || opt.line->icmp_echoseq > sel->max_value) && !(sel->invert)) \ || (opt.line->icmp_echoseq >= sel->value && opt.line->icmp_echoseq <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_ICMP_ECHOSEQ; match_inc &= ~MATCH_ICMP_ECHOSEQ; } else { match_inc |= MATCH_ICMP_ECHOSEQ; match_exc &= ~MATCH_ICMP_ECHOSEQ; } break; case SEL_ICMP_GATEWAY: if ((sel->invert && (match_exc & MATCH_ICMP_GATEWAY)) || (!sel->invert && (match_inc & MATCH_ICMP_GATEWAY))) break; inp = xmalloc(sizeof(struct in_addr)); if (convert_ip(sel->svalue, inp)) {fprintf(stderr, "Couldn't convert %s\n", sel->svalue); break;} /* error */ if ((((ntohl(opt.line->icmp_gw.s_addr) & sel->netmask) != (ntohl(inp->s_addr) & sel->netmask)) && !(sel->invert)) \ || ((ntohl(opt.line->icmp_gw.s_addr) & sel->netmask) == (ntohl(inp->s_addr) & sel->netmask) && (sel->invert)) ) { match_exc |= MATCH_ICMP_GATEWAY; match_inc &= ~MATCH_ICMP_GATEWAY; } else { match_inc |= MATCH_ICMP_GATEWAY; match_exc &= ~MATCH_ICMP_GATEWAY; } free(inp); case SEL_ICMP_FRAGMTU: if ((sel->invert && (match_exc & MATCH_ICMP_FRAGMTU)) || (!sel->invert && (match_inc & MATCH_ICMP_FRAGMTU))) break; if (((opt.line->icmp_mtu < sel->value || opt.line->icmp_mtu > sel->max_value) && !(sel->invert)) \ || (opt.line->icmp_mtu >= sel->value && opt.line->icmp_mtu <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_ICMP_FRAGMTU; match_inc &= ~MATCH_ICMP_FRAGMTU; } else { match_inc |= MATCH_ICMP_FRAGMTU; match_exc &= ~MATCH_ICMP_FRAGMTU; } break; case SEL_UDP_LEN: if ((sel->invert && (match_exc & MATCH_UDP_LEN)) || (!sel->invert && (match_inc & MATCH_UDP_LEN))) break; if (((opt.line->udp_len < sel->value || opt.line->udp_len > sel->max_value) && !(sel->invert)) \ || (opt.line->udp_len >= sel->value && opt.line->udp_len <= sel->max_value && (sel->invert)) ) { match_exc |= MATCH_UDP_LEN; match_inc &= ~MATCH_UDP_LEN; } else { match_inc |= MATCH_UDP_LEN; match_exc &= ~MATCH_UDP_LEN; } break; case SEL_RAW_MAC: if (((strcmp(opt.line->raw_mac, sel->svalue) != 0) && !(sel->invert)) \ || ((strcmp(opt.line->raw_mac, sel->svalue) == 0) && (sel->invert)) ) match = P_MATCH_EXC; break; default: break; } sel = sel->next; } if(match == P_MATCH_EXC || match_exc != MATCH_MUL_NONE) { if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "e"); return PARSE_EXCLUDED; } } /* if not excluded, add to data */ /* opt.line->count is either 0 or 1 */ opt.orig_count = opt.line->count; xstrncpy(opt.line->filename, opt.filename, FILESIZE); opt.line->linenum = linenum; build_list(); if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "."); } /* end 'if (retval == PARSE_OK') */ return retval; } int parse_time(char *input) { char *string, *pnt, c; int seconds; string = strdup(input); pnt = string; while (isdigit((int)*pnt)) { pnt++; } c = *pnt; if (c != '\0') { *pnt = '\0'; seconds = atoi(string); switch(c) { case 'm': seconds = seconds * 60; break; case 'h': seconds = seconds * 60 * 60; break; case 'd': seconds = seconds * 60 * 60 * 24; break; case 'w': seconds = seconds * 60 * 60 * 24 * 7; break; case 'M': seconds = seconds * 60 * 60 * 24 * 31; break; case 'y': seconds = seconds * 60 * 60 * 24 * 31 * 12; break; } } else { seconds = atoi(string); } free(string); return seconds; } /* If parsers specified on command line or in rcfile, use only those */ void select_parsers() { unsigned char i = 0; if (opt.format_sel[0] == '\0') { return; } else { opt.format = 0; while ((i < SHORTLEN) && (opt.format_sel[i] != '\0')) { switch (opt.format_sel[i]) { case 'i': opt.format = opt.format | PARSER_IPCHAINS; break; case 'n': opt.format = opt.format | PARSER_NETFILTER; break; case 'f': opt.format = opt.format | PARSER_IPFILTER; break; case 'w': opt.format = opt.format | PARSER_WIN_XP; break; case 'b': opt.format = opt.format | PARSER_IPFW; break; default: fprintf(stderr, "Unknown parser: '%c'.\n", opt.format_sel[i]); exit(EXIT_FAILURE); } i++; } } }