/* * tcpdsel - select packets from a tcpdump capture file. * * Input is a tcpdump packet stream. Output is likewise. Command line * holds a test expression. Output contains those input packets which * match the expression. * * The expression is formed by concatenating the command-line arguments * with a single space between each and the next. The result is then * parsed as an expression built up from: * * - Numbers, which may have 0 or 0x prefixes for octal or hex, * but are otherwise decimal. * * - Strings, which are delimited by " ", within which \ quotes * both " and \, but has no other effect (in particular, there * is no \0, \r, etc). * * - Niladic operators which return information about the * packet's timestamp: * month time year date hour day min sec hms * Of these, month, year, hour, day, min, and sec just return * those fields of the timestamp. time returns the timestamp * as a seconds-since-epoch number. date returns the date * portion of the time as an eight-digit number YYYYMMDD; hms, * the time-of-day portion of the time as a six-digit number * HHMMSS. * * - The usual set of monadic and dyadic arithmetic operators, * with approximately their C meanings: * < > + - * / % ! <= >= == != << >> && || ^^ & | ^ ~ * and the ternary ? : conditional operator. (C does not have * ^^; it is logical exclusive-or, being to && and || what ^ is * to & and |.) * * - Parens ( ) for grouping. * * - /0 and %0, which are just like / and % except that, if the * right-hand operand is zero, instead of producing an error, * they simply return 0. * * - A unary operator `contains' which takes a string as an * argument and returns true if the string is found anywhere in * the packet's data, false if not. * * This is admittedly suboptimal; for example, strings should be * capable of containing arbitrary octet sequences.... */ #include #include #include #include #include #include #include #include extern const char *__progname; /* Why is this not in a .h, rather than existing only in tcpdump source? */ #define TCPDUMP_MAGIC 0xa1b2c3d4 typedef struct pcap_file_header PFH; typedef struct pcap_pkthdr PP; typedef enum { OP_I_CONST = 1, OP_S_CONST, OP_LT, OP_LE, OP_GT, OP_GE, OP_EQ, OP_NE, OP_NEG, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_DIV0, OP_MOD0, OP_LSH, OP_RSH, OP_LOGAND, OP_LOGOR, OP_LOGXOR, OP_LOGNOT, OP_BITAND, OP_BITOR, OP_BITXOR, OP_BITNOT, OP_COND, OP_TIME, OP_YEAR, OP_MONTH, OP_DAY, OP_DATE, OP_HOUR, OP_MIN, OP_SEC, OP_HMS, OP_CONTAINS } OP; typedef enum { PSET_NODE = 1, PSET_TOK } PSETYPE; typedef enum { TT_EOF = 1, TT_I, TT_S, TT_LPAR, TT_RPAR, TT_LT, TT_LE, TT_GT, TT_GE, TT_EQ, TT_NE, TT_ADD, TT_SUB, TT_MUL, TT_DIV, TT_MOD, TT_DIV0, TT_MOD0, TT_LSH, TT_RSH, TT_LOGAND, TT_LOGOR, TT_LOGXOR, TT_LOGNOT, TT_BITAND, TT_BITOR, TT_BITXOR, TT_BITNOT, TT_QUES, TT_COLON, TT_TIME, TT_YEAR, TT_MONTH, TT_DAY, TT_DATE, TT_HOUR, TT_MIN, TT_SEC, TT_HMS, TT_CONTAINS } TOKTYPE; typedef struct node NODE; typedef struct pse PSE; typedef struct token TOKEN; struct token { TOKTYPE type; union { unsigned int ival; struct { int off; int len; } sval; } ; } ; struct pse { PSETYPE type; union { NODE *n; TOKTYPE tok; } ; } ; struct node { OP op; union { unsigned int iconst; char *sconst; struct { NODE *arg; } unary; struct { NODE *lhs; NODE *rhs; } binary; struct { NODE *test; NODE *ift; NODE *iff; } cond; struct { int len; unsigned char (*tbl)[256]; } contains; } ; } ; static pcap_t *ip; static PP iph; static struct tm *iphtm; static char *ipktbuf; static int ipktalloc; static pcap_dumper_t *op; static char *parse_str; static int parse_len; static int parse_off; static NODE *expr; static PSE **tokvec; static int tva; static int tvn; static int tvx; #define N4(x) (x), (x)+1, (x)+2, (x)+3 #define N16(x) N4(x), N4((x)+4), N4((x)+8), N4((x)+12) #define N64(x) N16(x), N16((x)+16), N16((x)+32), N16((x)+48) static const unsigned char trivial_equiv[256] = { N64(0), N64(64), N64(128), N64(192) }; #undef N4 #undef N16 #undef N64 #define Cisspace(x) isspace((unsigned char)(x)) #define Cisdigit(x) isdigit((unsigned char)(x)) #define Cisalpha(x) isalpha((unsigned char)(x)) static void start_input(void) { char errmsg[PCAP_ERRBUF_SIZE]; char s[2]; errmsg[0] = '\0'; // pcap_open_offline's first arg is not consted on 1.4T! s[0] = '-'; s[1] = '\0'; ip = pcap_open_offline(&s[0],&errmsg[0]); if (! ip) { fprintf(stderr,"%s: can't read input pcap: %s\n",__progname,&errmsg[0]); exit(1); } if (errmsg[0]) { fprintf(stderr,"%s: warning reading input pcap: %s\n",__progname,&errmsg[0]); } } static TOKEN next_token(void) { int i; TOKEN tok; while (1) { if (parse_off >= parse_len) return((TOKEN){.type=TT_EOF}); if (! Cisspace(parse_str[parse_off])) break; parse_off ++; } if (Cisdigit(parse_str[parse_off])) { int base; int ndig; unsigned int nval; int dval; i = parse_off; if ( (parse_len-i >= 2) && (parse_str[i] == '0') && ( (parse_str[i+1] == 'x') || (parse_str[i+1] == 'X') ) ) { base = 16; i += 2; } else if (parse_str[i] == '0') { base = 8; } else { base = 10; } ndig = 0; nval = 0; while (1) { if (i >= parse_len) break; switch (parse_str[i]) { case '0': dval = 0; break; case '1': dval = 1; break; case '2': dval = 2; break; case '3': dval = 3; break; case '4': dval = 4; break; case '5': dval = 5; break; case '6': dval = 6; break; case '7': dval = 7; break; case '8': dval = 8; break; case '9': dval = 9; break; case 'a': case 'A': dval = 10; break; case 'b': case 'B': dval = 11; break; case 'c': case 'C': dval = 12; break; case 'd': case 'D': dval = 13; break; case 'e': case 'E': dval = 14; break; case 'f': case 'F': dval = 15; break; default: dval = base; break; } if (dval >= base) break; nval = (nval * base) + dval; ndig ++; i ++; } if (ndig < 1) { fprintf(stderr,"%s: invalid number\n",__progname); exit(1); } parse_off = i; tok.type = TT_I; tok.ival = nval; return(tok); } else if (parse_str[parse_off] == '"') { int bq; bq = 0; i = parse_off + 1; while <"string"> (1) { if (i >= parse_len) { fprintf(stderr,"%s: unclosed \"\n",__progname); exit(1); } if (bq) { bq = 0; } else { switch (parse_str[i]) { case '\\': bq = 1; break; case '"': break <"string">; } } i ++; } tok.type = TT_S; tok.sval.off = parse_off + 1; tok.sval.len = i - tok.sval.off; parse_off = i + 1; return(tok); } else if (Cisalpha(parse_str[parse_off])) { for (i=parse_off;(i= 2) #define TWOCHAR(a,b) ((256*(unsigned char)(a))+(unsigned char)(b)) { parse_off += 2; switch (TWOCHAR(parse_str[parse_off-2],parse_str[parse_off-1])) { case TWOCHAR('<','='): return((TOKEN){.type=TT_LE}); break; case TWOCHAR('>','='): return((TOKEN){.type=TT_GE}); break; case TWOCHAR('=','='): return((TOKEN){.type=TT_EQ}); break; case TWOCHAR('!','='): return((TOKEN){.type=TT_NE}); break; case TWOCHAR('/','0'): return((TOKEN){.type=TT_DIV0}); break; case TWOCHAR('%','0'): return((TOKEN){.type=TT_MOD0}); break; case TWOCHAR('<','<'): return((TOKEN){.type=TT_LSH}); break; case TWOCHAR('>','>'): return((TOKEN){.type=TT_RSH}); break; case TWOCHAR('&','&'): return((TOKEN){.type=TT_LOGAND}); break; case TWOCHAR('|','|'): return((TOKEN){.type=TT_LOGOR}); break; case TWOCHAR('^','^'): return((TOKEN){.type=TT_LOGXOR}); break; } parse_off -= 2; } #undef TWOCHAR parse_off ++; switch (parse_str[parse_off-1]) { case '(': return((TOKEN){.type=TT_LPAR }); break; case ')': return((TOKEN){.type=TT_RPAR }); break; case '<': return((TOKEN){.type=TT_LT }); break; case '>': return((TOKEN){.type=TT_GT }); break; case '+': return((TOKEN){.type=TT_ADD }); break; case '-': return((TOKEN){.type=TT_SUB }); break; case '*': return((TOKEN){.type=TT_MUL }); break; case '/': return((TOKEN){.type=TT_DIV }); break; case '%': return((TOKEN){.type=TT_MOD }); break; case '?': return((TOKEN){.type=TT_QUES }); break; case ':': return((TOKEN){.type=TT_COLON }); break; case '!': return((TOKEN){.type=TT_LOGNOT}); break; case '&': return((TOKEN){.type=TT_BITAND}); break; case '|': return((TOKEN){.type=TT_BITOR }); break; case '^': return((TOKEN){.type=TT_BITXOR}); break; case '~': return((TOKEN){.type=TT_BITNOT}); break; } parse_off --; fprintf(stderr,"%s: bad operator char `%.1s'\n",__progname,parse_str+parse_off); exit(1); } } static const char *tok_name(TOKTYPE tt) { switch (tt) { case TT_EOF: return("end of expression"); break; case TT_I: return("numeric constant"); break; case TT_S: return("string constant"); break; case TT_LPAR: return("("); break; case TT_RPAR: return(")"); break; case TT_LT: return("<"); break; case TT_LE: return("<="); break; case TT_GT: return(">"); break; case TT_GE: return(">="); break; case TT_EQ: return("=="); break; case TT_NE: return("!="); break; case TT_ADD: return("+"); break; case TT_SUB: return("-"); break; case TT_MUL: return("*"); break; case TT_DIV: return("/"); break; case TT_MOD: return("%"); break; case TT_DIV0: return("/0"); break; case TT_MOD0: return("%0"); break; case TT_LSH: return("<<"); break; case TT_RSH: return(">>"); break; case TT_LOGAND: return("&&"); break; case TT_LOGOR: return("||"); break; case TT_LOGXOR: return("^^"); break; case TT_LOGNOT: return("!"); break; case TT_BITAND: return("&"); break; case TT_BITOR: return("|"); break; case TT_BITXOR: return("^"); break; case TT_BITNOT: return("~"); break; case TT_QUES: return("?"); break; case TT_COLON: return(":"); break; case TT_TIME: return("time"); break; case TT_YEAR: return("year"); break; case TT_MONTH: return("month"); break; case TT_DAY: return("day"); break; case TT_DATE: return("date"); break; case TT_HOUR: return("hour"); break; case TT_MIN: return("min"); break; case TT_SEC: return("sec"); break; case TT_HMS: return("hms"); break; case TT_CONTAINS: return("contains"); break; } abort(); } static NODE *new_node(void) { return(malloc(sizeof(NODE))); } static PSE *curpse(void) { if ((tvx < 0) || (tvx > tvn)) abort(); if (tvx == tvn) return(0); return(tokvec[tvx]); } static NODE *parse_leftbin(NODE *(*sub)(void), int nops, ...) { va_list ap; NODE *lhs; NODE *rhs; NODE *n; int i; TOKTYPE tt; OP op; PSE *e; lhs = (*sub)(); while (1) { e = curpse(); if (! e) break; if (e->type != PSET_TOK) break; va_start(ap,nops); do <"found"> { for (i=nops;i>0;i--) { tt = va_arg(ap,TOKTYPE); op = va_arg(ap,OP); if (e->tok == tt) break <"found">; } return(lhs); } while (0); va_end(ap); tvx ++; rhs = (*sub)(); if (! rhs) { fprintf(stderr,"%s: missing RHS to %s\n",__progname,tok_name(e->tok)); exit(1); } n = new_node(); n->op = op; n->binary.lhs = lhs; n->binary.rhs = rhs; lhs = n; } return(lhs); } static NODE *parse_leftbin_nomix(NODE *(*sub)(void), int nops, ...) { va_list ap; NODE *lhs; NODE *rhs; NODE *n; int i; TOKTYPE tt; TOKTYPE ttcur; OP op; PSE *e; lhs = (*sub)(); ttcur = TT_EOF; while (1) { e = curpse(); if (! e) break; if (e->type != PSET_TOK) break; va_start(ap,nops); do <"found"> { for (i=nops;i>0;i--) { tt = va_arg(ap,TOKTYPE); op = va_arg(ap,OP); if (e->tok == tt) break <"found">; } return(lhs); } while (0); va_end(ap); if ((ttcur != TT_EOF) && (tt != ttcur)) { fprintf(stderr,"%s: mixing %s and %s requires parens\n",__progname,tok_name(tt),tok_name(ttcur)); exit(1); } ttcur = tt; tvx ++; rhs = (*sub)(); if (! rhs) { fprintf(stderr,"%s: missing RHS to %s\n",__progname,tok_name(e->tok)); exit(1); } n = new_node(); n->op = op; n->binary.lhs = lhs; n->binary.rhs = rhs; lhs = n; } return(lhs); } static NODE *parse_top(void); // forward static NODE *parse_unary(void) { PSE *e; NODE *sub; NODE *n; if (tvx >= tvn) return(0); e = curpse(); if (! e) return(0); n = 0; switch (e->type) { case PSET_TOK: switch (e->tok) { case TT_CONTAINS: tvx ++; sub = parse_unary(); if (! sub) { fprintf(stderr,"%s: missing argument to `contains'\n",__progname); exit(1); } if (sub->op != OP_S_CONST) { fprintf(stderr,"%s: `contains' argument must be a string\n",__progname); exit(1); } n = new_node(); n->op = OP_CONTAINS; n->contains.len = strlen(sub->sconst); if (n->contains.len > 255) { fprintf(stderr,"%s: `contains' argument too long (max 255)\n",__progname); exit(1); } n->contains.tbl = malloc(n->contains.len*sizeof(*n->contains.tbl)); searchstr_maketbl(n->contains.tbl,sub->sconst,n->contains.len,&trivial_equiv[0]); break; case TT_SUB: { OP op; op = OP_NEG; if (0) { case TT_LOGNOT: op = OP_LOGNOT; } if (0) { case TT_BITNOT: op = OP_BITNOT; } tvx ++; sub = parse_unary(); if (! sub) { fprintf(stderr,"%s: missing argument to `-'\n",__progname); exit(1); } n = new_node(); n->op = op; n->unary.arg = sub; } break; case TT_LPAR: tvx ++; n = parse_top(); if (! n) return(0); e = curpse(); if (! e) { fprintf(stderr,"%s: unclosed (\n",__progname); exit(1); } if ((e->type == PSET_TOK) && (e->tok == TT_RPAR)) { tvx ++; } else { fprintf(stderr,"%s: improperly closed (\n",__progname); exit(1); } break; default: break; } break; case PSET_NODE: tvx ++; n = e->n; break; } if (! n) { fprintf(stderr,"%s: expression syntax error\n",__progname); exit(1); } return(n); } static NODE *parse_muldiv(void) { return(parse_leftbin(&parse_unary,5, TT_MUL,OP_MUL,TT_DIV,OP_DIV,TT_MOD,OP_MOD, TT_DIV0,OP_DIV0,TT_MOD0,OP_MOD0)); } static NODE *parse_addsub(void) { return(parse_leftbin(&parse_muldiv,2,TT_ADD,OP_ADD,TT_SUB,OP_SUB)); } static NODE *parse_cmp(void) { return(parse_leftbin(&parse_addsub,6, TT_LT,OP_LT,TT_LE,OP_LE,TT_EQ,OP_EQ, TT_GT,OP_GT,TT_GE,OP_GE,TT_NE,OP_NE)); } static NODE *parse_shift(void) { return(parse_leftbin(&parse_cmp,2,TT_LSH,OP_LSH,TT_RSH,OP_RSH)); } static NODE *parse_bit(void) { return(parse_leftbin_nomix(&parse_shift,3,TT_BITAND,OP_BITAND,TT_BITOR,OP_BITOR,TT_BITXOR,OP_BITXOR)); } static NODE *parse_cond(void) { NODE *lhs; NODE *mhs; NODE *rhs; NODE *n; lhs = parse_bit(); if (lhs && (tvx < tvn) && (curpse()->type == PSET_TOK) && (curpse()->tok == TT_QUES)) { tvx ++; mhs = parse_cond(); if (mhs && (tvx < tvn) && (curpse()->type == PSET_TOK) && (curpse()->tok == TT_COLON)) { tvx ++; rhs = parse_cond(); if (rhs) { n = new_node(); n->op = OP_COND; n->cond.test = lhs; n->cond.ift = mhs; n->cond.iff = rhs; return(n); } else { fprintf(stderr,"%s: botched ? : operator\n",__progname); exit(1); } } else { fprintf(stderr,"%s: botched ? : operator\n",__progname); exit(1); } } else { return(lhs); } } static NODE *parse_logical(void) { return(parse_leftbin_nomix(&parse_cond,3,TT_LOGAND,OP_LOGAND,TT_LOGOR,OP_LOGOR,TT_LOGXOR,OP_LOGXOR)); } static NODE *parse_top(void) { return(parse_logical()); } static void parse_expr(int ac, char **av) { int i; int l; int o; TOKEN t; NODE *n; PSE *e; parse_len = -1; for (i=1;i 1) parse_str[o++] = ' '; l = strlen(av[i]); bcopy(av[i],parse_str+o,l); o += l; } if (o != parse_len) abort(); parse_off = 0; tokvec = 0; tva = 0; tvn = 0; while <"tokenize"> (1) { t = next_token(); switch (t.type) { default: abort(); break; case TT_EOF: break <"tokenize">; case TT_I: n = new_node(); n->op = OP_I_CONST; n->iconst = t.ival; break; case TT_S: n = new_node(); n->op = OP_S_CONST; n->sconst = malloc(t.sval.len+1); bcopy(parse_str+t.sval.off,n->sconst,t.sval.len); n->sconst[t.sval.len] = '\0'; break; #define NILADIC(o) do { n = new_node(); n->op = (o); } while (0) case TT_TIME: NILADIC(OP_TIME); break; case TT_YEAR: NILADIC(OP_YEAR); break; case TT_MONTH: NILADIC(OP_MONTH); break; case TT_DAY: NILADIC(OP_DAY); break; case TT_DATE: NILADIC(OP_DATE); break; case TT_HOUR: NILADIC(OP_HOUR); break; case TT_MIN: NILADIC(OP_MIN); break; case TT_SEC: NILADIC(OP_SEC); break; case TT_HMS: NILADIC(OP_HMS); break; #undef NILADIC case TT_LPAR: case TT_RPAR: case TT_LT: case TT_LE: case TT_GT: case TT_GE: case TT_EQ: case TT_NE: case TT_ADD: case TT_SUB: case TT_MUL: case TT_DIV: case TT_MOD: case TT_DIV0: case TT_MOD0: case TT_LSH: case TT_RSH: case TT_LOGAND: case TT_LOGOR: case TT_LOGXOR: case TT_LOGNOT: case TT_BITAND: case TT_BITOR: case TT_BITXOR: case TT_BITNOT: case TT_QUES: case TT_COLON: case TT_CONTAINS: n = 0; break; } e = malloc(sizeof(PSE)); if (n) { e->type = PSET_NODE; e->n = n; } else { e->type = PSET_TOK; e->tok = t.type; } if (tvn >= tva) tokvec = realloc(tokvec,(tva=tvn+8)*sizeof(PSE *)); tokvec[tvn++] = e; } tvx = 0; expr = parse_top(); } // XXX should avoid copying packet data static void read_packet_handler(u_char *ep, const PP *h, const u_char *pktdata) { if (h->caplen > ipktalloc) { free(ipktbuf); ipktalloc = h->caplen; ipktbuf = malloc(ipktalloc); if (ipktbuf == 0) { fprintf(stderr,"%s: can't allocate packet buffer (len=%d)\n",__progname,ipktalloc); *ep = 1; return; } } bcopy(pktdata,ipktbuf,h->caplen); iph = *h; iphtm = 0; } static int read_packet(void) { u_char err; err = 0; if (! pcap_dispatch(ip,1,&read_packet_handler,&err)) return(0); return(!err); } static struct tm *iph_tm(void) { if (! iphtm) { time_t tt; tt = iph.ts.tv_sec; iphtm = localtime(&tt); } return(iphtm); } static int eval(NODE *); // forward static int eval_cmp(NODE *lhs, NODE *rhs, int mask) { int v1; int v2; int bit; v1 = eval(lhs); v2 = eval(rhs); if (v1 < v2) bit = 1; else if (v1 > v2) bit = 4; else bit = 2; return((mask&bit)?1:0); } static int eval_arith(NODE *lhs, NODE *rhs, int (*doit)(int, int)) { int v1; int v2; v1 = eval(lhs); v2 = eval(rhs); return((*doit)(v1,v2)); } static int perform_add(int a, int b) { return(a+b); } static int perform_sub(int a, int b) { return(a-b); } static int perform_mul(int a, int b) { return(a*b); } static int perform_div(int a, int b) { if (b == 0) { fprintf(stderr,"%s: / by zero\n",__progname); exit(1); } return(a/b); } static int perform_mod(int a, int b) { if (b == 0) { fprintf(stderr,"%s: %% by zero\n",__progname); exit(1); } return(a%b); } static int perform_div0(int a, int b) { if (b == 0) return(0); return(a/b); } static int perform_mod0(int a, int b) { if (b == 0) return(0); return(a%b); } static int perform_rsh(int a, int b) { return((b>0)?(a>>b):(a<<-b)); } static int perform_lsh(int a, int b) { return((b>0)?(a<>-b)); } static int perform_bitand(int a, int b) { return(a&b); } static int perform_bitor(int a, int b) { return(a|b); } static int perform_bitxor(int a, int b) { return(a^b); } static int eval_logand(NODE *lhs, NODE *rhs) { int v; v = eval(lhs); if (! v) return(0); v = eval(rhs); return(v?1:0); } static int eval_logor(NODE *lhs, NODE *rhs) { int v; v = eval(lhs); if (v) return(1); v = eval(rhs); return(v?1:0); } static int eval(NODE *n) { switch (n->op) { case OP_I_CONST: return(n->iconst); break; case OP_S_CONST: fprintf(stderr,"%s: strings may be used only with `contains'\n",__progname); exit(1); break; case OP_LT: return(eval_cmp(n->binary.lhs,n->binary.rhs,1)); break; case OP_LE: return(eval_cmp(n->binary.lhs,n->binary.rhs,3)); break; case OP_GT: return(eval_cmp(n->binary.lhs,n->binary.rhs,4)); break; case OP_GE: return(eval_cmp(n->binary.lhs,n->binary.rhs,6)); break; case OP_EQ: return(eval_cmp(n->binary.lhs,n->binary.rhs,2)); break; case OP_NE: return(eval_cmp(n->binary.lhs,n->binary.rhs,5)); break; case OP_NEG: return(-eval(n->unary.arg)); break; case OP_ADD: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_add)); break; case OP_SUB: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_sub)); break; case OP_MUL: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_mul)); break; case OP_DIV: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_div)); break; case OP_MOD: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_mod)); break; case OP_DIV0: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_div0)); break; case OP_MOD0: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_mod0)); break; case OP_LSH: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_lsh)); break; case OP_RSH: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_rsh)); break; case OP_LOGAND: return(eval_logand(n->binary.lhs,n->binary.rhs)); break; case OP_LOGOR: return(eval_logor(n->binary.lhs,n->binary.rhs)); break; case OP_LOGXOR: return(eval(n->binary.lhs)?!eval(n->binary.rhs):eval(n->binary.rhs)); break; case OP_LOGNOT: return(!eval(n->unary.arg)); break; case OP_BITAND: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_bitand)); break; case OP_BITOR: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_bitor)); break; case OP_BITXOR: return(eval_arith(n->binary.lhs,n->binary.rhs,&perform_bitxor)); break; case OP_BITNOT: return(~eval(n->unary.arg)); break; case OP_COND: return(eval(eval(n->cond.test)?n->cond.ift:n->cond.iff)); break; case OP_TIME: return(iph.ts.tv_sec); break; case OP_YEAR: return(iph_tm()->tm_year+1900); break; case OP_MONTH: return(iph_tm()->tm_mon+1); break; case OP_DAY: return(iph_tm()->tm_mday); break; case OP_DATE: return( (iph_tm()->tm_year * 10000) + (iph_tm()->tm_mon * 100) + iph_tm()->tm_mday + 19000100 ); break; case OP_HOUR: return(iph_tm()->tm_hour); break; case OP_MIN: return(iph_tm()->tm_min); break; case OP_SEC: return(iph_tm()->tm_sec); break; case OP_HMS: return( (iph_tm()->tm_hour * 10000) + (iph_tm()->tm_min * 100) + iph_tm()->tm_sec ); break; case OP_CONTAINS: return(searchstr(ipktbuf,iph.caplen,n->contains.tbl,n->contains.len)>=0); break; default: abort(); break; } } static void write_packet(void) { // XXX API botch on first and third args pcap_dump((void *)op,&iph,(void *)ipktbuf); } static void write_ohdr(void) { char s[2]; // pcap_dump_open doesn't const its second arg on 1.4T! s[0] = '-'; s[1] = '\0'; op = pcap_dump_open(ip,&s[0]); if (! op) { fprintf(stderr,"%s: can't write output: %s\n",__progname,pcap_geterr(ip)); exit(1); } } int main(int, char **); int main(int ac, char **av) { parse_expr(ac,av); start_input(); write_ohdr(); while (read_packet()) if (eval(expr)) write_packet(); #if 0 while (write_packet()); #endif return(0); }