%{ /* extract - A network log processor Copyright (C) 1993 Douglas Lee Schales, David K. Hess, David R. Safford Please see the file `COPYING' for the complete copyright notice. grammar.y - 03/20/93 */ #include #include #include #include #include #include #include "lex.h" #include "chario.h" #include "parser.h" #include "builder.h" #include "timesub.h" #include "stdunix.h" extern int parse_error; #define TCPDATA 6 #define UDPDATA 17 #define ICMPDATA 1 extern int protoflag; struct icmptypes { char *name; unsigned short type; }; static struct icmptypes icmptbl[] = { { "echorep", 0x0000 }, { "netunreach", 0x0300 }, { "hostunreach", 0x0301 }, { "protounreach", 0x0302 }, { "portunreach", 0x0303 }, { "fraglost", 0x0304 }, { "badsrcroute", 0x0305 }, { "srcquench", 0x0400 }, { "netredir", 0x0500 }, { "hostredir", 0x0501 }, { "tosnetredir", 0x0502 }, { "toshostredir", 0x0503 }, { "echoreq", 0x0800 }, { "tstampreq", 0x0d00 }, { "tstamprep", 0x0e00 }, { "inforeq", 0x0f00 }, { "inforep", 0x1000 }, { "maskreq", 0x1100 }, { "maskrep", 0x1200 }, { 0, 0 } }; %} %union { unsigned int intval; unsigned long *intpval; char *strval; } %token DSTPORT SRCPORT DSTADDR SRCADDR SRCNET DSTNET DATE TIME PORT HOST NET PROTO PKTS OCTETS FLAG FLAGS DSTIFACE SRCIFACE IFACE NEXTHOP SRCHP DSTHP HP %token TODAY YEST INCLUDE %token OR AND MASKOPER NOT SINCE BEFORE %token NEQ LEQ GEQ %token INTEGER BYTEVAL STRING %token PRINT NEXT PRINTALL %token RANGE %type INTEGER BYTEVAL %type OR AND %type oper NEQ LEQ GEQ '=' '<' '>' '!' NOT %type netop %type DATE TIME TODAY YEST SINCE BEFORE %type SRCADDR DSTADDR SRCPORT DSTPORT SRCNET DSTNET PORT HOST NET PROTO PKTS OCTETS FLAG FLAGS SRCIFACE DSTIFACE IFACE NEXTHOP SRCHP DSTHP HP %type INCLUDE %type PRINT NEXT PRINTALL %type STRING %type ip_address netmask integer tcpport datespec timespec %type hostspec %left OR %left AND %right '!' %% file : stmt file | stmt ; stmt : cond '{' actionset '}' { queuestmt(); } | INCLUDE STRING ';' { if(includefile($2) != 0){ fprintf(stderr, "\"%s\", line %d: include file error.\n", getfilename(), getlinenum()); parse_error = 1; } } ; cond : /* */ | cond OR cond { pushoper($2); } | cond AND cond { pushoper($2); } | term ; actionset : action ';' actionset | action ';' | action ; action : PRINT { queueact($1); } | NEXT { queueact($1); } | PRINTALL { queueact($1); } | error ; term : PORT oper tcpport { pushkey(SRCPORT); pushval($3); pushoper($2); pushkey(DSTPORT); pushval($3); pushoper($2); if ($2 == NEQ) pushoper(AND); else pushoper(OR); } | PORT tcpport RANGE tcpport { pushkey(SRCPORT); pushval($2); pushoper('>'); pushkey(SRCPORT); pushval($4); pushoper('<'); pushoper(AND); pushkey(DSTPORT); pushval($2); pushoper('>'); pushkey(DSTPORT); pushval($4); pushoper('<'); pushoper(AND); pushoper(OR); } | SRCPORT oper tcpport { pushkey(SRCPORT); pushval($3); pushoper($2); } | SRCPORT tcpport RANGE tcpport { pushkey(SRCPORT); pushval($2); pushoper('>'); pushkey(SRCPORT); pushval($4); pushoper('<'); pushoper(AND); } | DSTPORT oper tcpport { pushkey(DSTPORT); pushval($3); pushoper($2); } | DSTPORT tcpport RANGE tcpport { pushkey(DSTPORT); pushval($2); pushoper('>'); pushkey(DSTPORT); pushval($4); pushoper('<'); pushoper(AND); } | HOST oper hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(SRCADDR); pushval(ntohl(addrp[i])); pushoper($2); pushkey(DSTADDR); pushval(ntohl(addrp[i])); pushoper($2); if ($2 == NEQ) pushoper(AND); else pushoper(OR); if(i) if ($2 == NEQ) pushoper(AND); else pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | HP oper hostspec tcpport { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(SRCADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } pushkey(SRCPORT); pushval($4); pushoper($2); if ($2 == NEQ) pushoper(OR); else pushoper(AND); if(addrp){ i = 0; do { pushkey(DSTADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } pushkey(DSTPORT); pushval($4); pushoper($2); if ($2 == NEQ) pushoper(OR); else pushoper(AND); if ($2 == NEQ) pushoper(AND); else pushoper(OR); } | NEXTHOP oper hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(NEXTHOP); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | SRCADDR oper hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(SRCADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | SRCHP oper hostspec tcpport { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(SRCADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } pushkey(SRCPORT); pushval($4); pushoper($2); if ($2 == NEQ) pushoper(OR); else pushoper(AND); } | DSTADDR oper hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(DSTADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | DSTHP oper hostspec tcpport { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushkey(DSTADDR); pushval(ntohl(addrp[i])); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } pushkey(DSTPORT); pushval($4); pushoper($2); if ($2 == NEQ) pushoper(OR); else pushoper(AND); } | NET netop hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { unsigned long mask = getmask(ntohl(addrp[i])); pushval(addrp[i]); pushval(mask); pushoper(MASKOPER); /* net & mask */ pushkey(SRCNET); pushval(mask); pushoper(MASKOPER); /* SRCADDR & mask */ pushoper($2); pushval(ntohl(addrp[i])); pushval(mask); pushoper(MASKOPER); /* net & mask */ pushkey(DSTNET); pushval(mask); /* dstaddr & mask */ pushoper(MASKOPER); pushoper($2); if ($2 == NEQ) pushoper(AND); else pushoper(OR); if(i) if ($2 == NEQ) pushoper(AND); else pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | NET netop hostspec '/' netmask { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushval(ntohl(addrp[i])); pushval($5); pushoper(MASKOPER); /* net & mask */ pushkey(SRCNET); pushval($5); pushoper(MASKOPER); /* srcaddr & mask */ pushoper($2); pushval(ntohl(addrp[i])); pushval($5); pushoper(MASKOPER); /* net & mask */ pushkey(DSTNET); pushval($5); pushoper(MASKOPER); /* dstaddr & mask */ pushoper($2); pushoper(OR); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | PROTO oper integer { pushkey($1); pushval($3); pushoper($2); } | PROTO integer RANGE integer { pushkey($1); pushval($2); pushoper('>'); pushkey($1); pushval($4); pushoper('<'); pushoper(AND); } | PKTS oper integer { pushkey($1); pushval($3); pushoper($2); } | PKTS integer RANGE integer { pushkey($1); pushval($2); pushoper('>'); pushkey($1); pushval($4); pushoper('<'); pushoper(AND); } | OCTETS oper integer { pushkey($1); pushval($3); pushoper($2); } | OCTETS integer RANGE integer { pushkey($1); pushval($2); pushoper('>'); pushkey($1); pushval($4); pushoper('<'); pushoper(AND); } | FLAG STRING { if (strcasecmp($2, "FIN") == 0) { pushval(0x01); pushkey(FLAG); pushoper(MASKOPER); } else if (strcasecmp($2, "SYN") == 0) { pushval(0x02); pushkey(FLAG); pushoper(MASKOPER); } else if (strcasecmp($2, "RST") == 0) { pushval(0x04); pushkey(FLAG); pushoper(MASKOPER); } else if (strcasecmp($2, "PUSH") == 0) { pushval(0x08); pushkey(FLAG); pushoper(MASKOPER); } else if (strcasecmp($2, "ACK") == 0) { pushval(0x10); pushkey(FLAG); pushoper(MASKOPER); } else if (strcasecmp($2, "URG") == 0) { pushval(0x20); pushkey(FLAG); pushoper(MASKOPER); } else { fprintf(stderr, "\"%s\", line %d: unknown tcp flag.\n", getfilename(), getlinenum()); parse_error = 1; } } | FLAGS STRING { int flags; int mask; char *two; int i; i = 0; flags = 0; mask = 0x3f; two = $2; while (two[i] != '\0') { if (two[i] == 'F' || two[i] == 'f') { flags += 0x01; } else if (two[i] == 'S' || two[i] == 's') { flags += 0x02; } else if (two[i] == 'R' || two[i] == 'r') { flags += 0x04; } else if (two[i] == 'P' || two[i] == 'p') { flags += 0x08; } else if (two[i] == 'A' || two[i] == 'a') { flags += 0x10; } else if (two[i] == 'U' || two[i] == 'u') { flags += 0x20; } else { fprintf(stderr, "\"%s\", line %d: unknown tcp flag.\n", getfilename(), getlinenum()); parse_error = 1; } i++; } pushval(mask); pushkey(FLAG); pushoper(MASKOPER); pushval(flags); pushoper('='); } | FLAGS STRING '/' STRING { int flags; int mask; int i; char *two; char *four; i = flags = mask = 0; two = $2; four = $4; while (two[i] != '\0') { if (two[i] == 'F' || two[i] == 'f') { flags += 0x01; } else if (two[i] == 'S' || two[i] == 's') { flags += 0x02; } else if (two[i] == 'R' || two[i] == 'r') { flags += 0x04; } else if (two[i] == 'P' || two[i] == 'p') { flags += 0x08; } else if (two[i] == 'A' || two[i] == 'a') { flags += 0x10; } else if (two[i] == 'U' || two[i] == 'u') { flags += 0x20; } else { fprintf(stderr, "\"%s\", line %d: unknown tcp flag.\n", getfilename(), getlinenum()); parse_error = 1; } i++; } i = 0; while (four[i] != '\0') { if (four[i] == 'F' || four[i] == 'f') { mask += 0x01; } else if (four[i] == 'S' || four[i] == 's') { mask += 0x02; } else if (four[i] == 'R' || four[i] == 'r') { mask += 0x04; } else if (four[i] == 'P' || four[i] == 'p') { mask += 0x08; } else if (four[i] == 'A' || four[i] == 'a') { mask += 0x10; } else if (four[i] == 'U' || four[i] == 'u') { mask += 0x20; } else { fprintf(stderr, "\"%s\", line %d: unknown tcp flag in mask.\n", getfilename(), getlinenum()); parse_error = 1; } i++; } if (!(flags & mask)) { fprintf(stderr, "\"%s\", line %d: tcp flag not in mask.\n", getfilename(), getlinenum()); parse_error = 1; } pushval(mask); pushkey(FLAG); pushoper(MASKOPER); pushval(flags); pushoper('='); } | SRCNET netop hostspec { unsigned long *addrp; int i; addrp=$3; if(addrp){ i = 0; do { unsigned long mask = getmask(ntohl(addrp[i])); pushval(ntohl(addrp[i])); pushval(mask); pushoper(MASKOPER); pushkey(SRCNET); pushval(mask); pushoper(MASKOPER); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | DSTNET netop hostspec { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { unsigned long mask = getmask(ntohl(addrp[i])); pushval(ntohl(addrp[i])); pushval(mask); pushoper(MASKOPER); pushkey(DSTNET); pushval(mask); pushoper(MASKOPER); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | SRCNET netop hostspec '/' netmask { unsigned long *addrp; int i; addrp = $3; if(addrp){ i = 0; do { pushval(ntohl(addrp[i])); pushval($5); pushoper(MASKOPER); pushkey(SRCNET); pushval($5); pushoper(MASKOPER); pushoper($2); if(i) pushoper(OR); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | DSTNET netop hostspec '/' netmask { unsigned long *addrp; int i; addrp=$3; if(addrp){ i = 0; do { pushval(ntohl(addrp[i])); pushval($5); pushoper(MASKOPER); pushkey(DSTNET); pushval($5); pushoper(MASKOPER); pushoper($2); if(i) pushoper(i); } while(addrp[++i]); free(addrp); } else switch($2){ case '=': pushval(0); break; default: pushval(1); break; } } | IFACE oper integer { pushkey(SRCIFACE); pushval($3); pushoper($2); pushkey(DSTIFACE); pushval($3); pushoper($2); if ($2 == NEQ) pushoper(AND); else pushoper(OR); } | IFACE integer RANGE integer { pushkey(SRCIFACE); pushval($2); pushoper('>'); pushkey(SRCIFACE); pushval($4); pushoper('<'); pushoper(AND); pushkey(DSTIFACE); pushval($2); pushoper('>'); pushkey(DSTIFACE); pushval($4); pushoper('<'); pushoper(AND); pushoper(OR); } | SRCIFACE oper integer { pushkey(SRCIFACE); pushval($3); pushoper($2); } | SRCIFACE integer RANGE integer { pushkey(SRCIFACE); pushval($2); pushoper('>'); pushkey(SRCIFACE); pushval($4); pushoper('<'); pushoper(AND); } | DSTIFACE oper integer { pushkey(DSTIFACE); pushval($3); pushoper($2); } | DSTIFACE integer RANGE integer { pushkey(DSTIFACE); pushval($2); pushoper('>'); pushkey(DSTIFACE); pushval($4); pushoper('<'); pushoper(AND); } | DATE oper datespec { switch($2){ case '>': case LEQ: case '<': case GEQ: pushkey($1); pushval(timeofday($3, 23, 59, 59)); pushoper($2); break; case '=': pushkey($1); pushval($3); pushoper(GEQ); pushkey($1); pushval(timeofday($3, 23, 59, 59)); pushoper(LEQ); pushoper(AND); break; case NEQ: pushkey($1); pushval($3); pushoper('<'); pushkey($1); pushval(timeofday($3, 23, 59, 59)); pushoper('>'); pushoper(OR); break; default: pushkey($1); pushval($3); pushoper($2); break; } } | DATE datespec RANGE datespec { pushkey($1); pushval($2); pushoper('>'); pushkey($1); pushval($4); pushoper('<'); pushoper(AND); } | TIME oper timespec { pushkey($1); pushval($3); pushoper($2); } | TIME timespec RANGE timespec { pushkey($1); pushval($2); pushoper('>'); pushkey($1); pushval($4); pushoper('<'); pushoper(AND); } | SINCE datespec BYTEVAL ':' BYTEVAL { pushkey(DATE); pushval(timeofday($2, $3, $5, 0)); pushoper(GEQ); } | SINCE datespec BYTEVAL ':' BYTEVAL ':' BYTEVAL { pushkey(DATE); pushval(timeofday($2, $3, $5, $7)); pushoper(GEQ); } | SINCE datespec { pushkey(DATE); pushval($2); pushoper(GEQ); } | BEFORE datespec BYTEVAL ':' BYTEVAL { pushkey(DATE); pushval(timeofday($2, $3, $5, 0)); pushoper('<'); } | BEFORE datespec BYTEVAL ':' BYTEVAL ':' BYTEVAL { pushkey(DATE); pushval(timeofday($2, $3, $5, $7)); pushoper('<'); } | BEFORE datespec { pushkey(DATE); pushval($2); pushoper('<'); } | '(' cond ')' | '!' term { pushuoper($1); } | NOT term { pushuoper('!'); } | error { pushval(0); } ; oper : '=' {$$ = $1;} | '>' {$$ = $1;} | '<' {$$ = $1;} | NEQ {$$ = $1;} | LEQ {$$ = $1;} | GEQ {$$ = $1;} | error { pushoper(0); } ; netop : '=' {$$ = $1;} | NEQ {$$ = $1;} | error { pushoper(0); } ; datespec : BYTEVAL '/' BYTEVAL { int year = getyear(); year += 1900; if($1 < 1 || $1 > 12 || !validmday($1, $3, year)){ fprintf(stderr, "\"%s\", line %d: malformed date.\n", getfilename(), getlinenum()); parse_error = 1; } else $$ = makedate($1, $3, year); } | BYTEVAL '/' BYTEVAL '/' integer { int year = $5; if(year < 38) year += 2000; if(year < 100) year += 1900; if(!checkyear(year)) { fprintf(stderr, "\"%s\", line %d: year out of range %d.\n", getfilename(), getlinenum(), year); parse_error = 1; } else if($1 < 1 || $1 > 12 || !validmday($1, $3, year)){ fprintf(stderr, "\"%s\", line %d: malformed date.\n", getfilename(), getlinenum()); parse_error = 1; } else $$ = makedate($1, $3, year); } | integer '-' BYTEVAL '-' BYTEVAL { int year = $1; if(year < 38) year += 2000; if(year < 100) year += 1900; if(!checkyear(year)) { fprintf(stderr, "\"%s\", line %d: year out of range %d.\n", getfilename(), getlinenum(), year); parse_error = 1; } else if($3 < 1 || $3 > 12 || !validmday($3, $5, year)){ fprintf(stderr, "\"%s\", line %d: malformed date.\n", getfilename(), getlinenum()); parse_error = 1; } else $$ = makedate($3, $5, year); } | TODAY { $$ = today(); } | YEST { $$ = yesterday(); } | error { $$ = 0; } ; timespec : BYTEVAL ':' BYTEVAL { $$ = $1*3600 + $3*60; } | BYTEVAL ':' BYTEVAL ':' BYTEVAL { $$ = $1*3600 + $3*60 + $5; } | error { $$ = 0; } ; tcpport : integer { $$ = $1; } | STRING { if(protoflag != ICMPDATA){ struct servent *se; if((se = getservbyname($1, protoflag == TCPDATA ? "tcp" : "udp"))){ $$ = ntohs(se->s_port); } else { fprintf(stderr, "\"%s\", line %d: unknown service: %s\n", getfilename(), getlinenum(),$1); parse_error = 1; $$ = 0; } } else { int i; for(i=0;icmptbl[i].name;i++) if(strcasecmp(icmptbl[i].name, $1) == 0) break; if(icmptbl[i].name) $$ = icmptbl[i].type; else { fprintf(stderr, "\"%s\", line %d: unknown ICMP type: %s\n", getfilename(), getlinenum(), $1); parse_error = 1; $$ = 0xffff; } } free($1); } | error {$$ = 0;} ; integer : INTEGER { $$ = $1; } | BYTEVAL { $$ = $1; } ; hostspec : ip_address { unsigned long *addrp; addrp = (unsigned long *)malloc(sizeof(unsigned long) * 2); addrp[0] = ntohl($1); addrp[1] = 0; $$ = addrp; } | STRING { struct hostent *he; struct { int ipaddr:32; } host; if((he = gethostbyname($1))){ int num; unsigned long *addrp; for(num=0;he->h_addr_list[num];num++) ; addrp = (unsigned long *)malloc((num+1)*sizeof(unsigned long)); addrp[num] = 0; for(num--;num>=0;num--) memcpy(&addrp[num], he->h_addr_list[num], 4); $$ = addrp; } else { fprintf(stderr, "\"%s\", line %d: unknown host: %s\n", getfilename(), getlinenum(), $1); $$ = 0; } free($1); } | error { $$ = 0; } ; netmask : ip_address { $$=$1;} ; ip_address : BYTEVAL '.' BYTEVAL '.' BYTEVAL '.' BYTEVAL { $$ = (($1 << 24 | $3 << 16 | $5 << 8 | $7)); } ; %% struct keywords keywords[] = { { "dstport", DSTPORT }, { "srcport", SRCPORT }, { "srchost", SRCADDR }, { "dsthost", DSTADDR }, { "srchp", SRCHP }, { "dsthp", DSTHP }, { "hp", HP }, { "srcnet", SRCNET }, { "dstnet", DSTNET }, { "port", PORT }, { "host", HOST }, { "net", NET }, { "nexthop", NEXTHOP }, { "proto", PROTO }, { "pkts", PKTS }, { "octets", OCTETS }, { "flag", FLAG }, { "flags", FLAGS }, { "dstiface", DSTIFACE }, { "srciface", SRCIFACE }, { "iface", IFACE }, { "time", TIME }, { "date", DATE }, { "since", SINCE }, { "before", BEFORE }, { "today", TODAY }, { "yesterday", YEST }, { "include", INCLUDE }, { "or", OR }, { "and", AND }, { "not", NOT }, { "print", PRINT }, { "next", NEXT }, { "printall", PRINTALL }, { (char *)0, 0 } }; void yyerror() { fprintf(stderr, "\"%s\", line %d: syntax error.\n", getfilename(), getlinenum()); parse_error = 1; } unsigned long getmask(unsigned long addr) { if(IN_CLASSA(addr)) return IN_CLASSA_NET; else if(IN_CLASSB(addr)) return IN_CLASSB_NET; else if(IN_CLASSC(addr)) return IN_CLASSC_NET; else return 0xffffffff; }