%{ #include "ipf.h" #undef OPT_NAT #undef OPT_VERBOSE #include "ipmon_l.h" #include "ipmon.h" #define YYDEBUG 1 extern void yyerror __P((char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; typedef struct opt { struct opt *o_next; int o_line; int o_type; int o_num; char *o_str; struct in_addr o_ip; } opt_t; static void build_action __P((struct opt *)); static opt_t *new_opt __P((int)); static action_t *alist = NULL; %} %union { char *str; u_32_t num; struct in_addr addr; struct opt *opt; union i6addr ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPM_ACTION IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT %token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_TAG IPM_YES %type ipv4 %type direction dstip dstport every execute group interface option %type options protocol result rule srcip srcport tag %% file: line | assign | file line | file assign ; line: IPM_ACTION '{' options '}' ';' { build_action($3); resetlexer(); } | IPM_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; options: option { $$ = $1; } | option ',' options { $1->o_next = $3; $$ = $1; } ; option: direction { $$ = $1; } | dstip { $$ = $1; } | dstport { $$ = $1; } | every { $$ = $1; } | execute { $$ = $1; } | group { $$ = $1; } | interface { $$ = $1; } | protocol { $$ = $1; } | result { $$ = $1; } | rule { $$ = $1; } | srcip { $$ = $1; } | srcport { $$ = $1; } | tag { $$ = $1; } ; direction: IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); $$->o_num = IPM_IN; } | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); $$->o_num = IPM_OUT; } ; dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); $$->o_ip = $3; $$->o_num = $5; } ; dstport: IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); $$->o_num = $3; } | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); $$->o_str = $3; } ; every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); $$->o_num = 1; } | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); $$->o_num = $2; } | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); $$->o_num = 1; } | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); $$->o_num = $2; } ; execute: IPM_EXECUTE '=' YY_STR { $$ = new_opt(IPM_EXECUTE); $$->o_str = $3; } ; group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); $$->o_num = $3; } | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); $$->o_str = $3; } ; interface: IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); $$->o_str = $3; } ; protocol: IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); $$->o_num = $3; } | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); $$->o_num = getproto($3); free($3); } ; result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); $$->o_str = $3; } ; rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); $$->o_num = YY_NUMBER; } ; srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); $$->o_ip = $3; $$->o_num = $5; } ; srcport: IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); $$->o_num = $3; } | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); $$->o_str = $3; } ; tag: IPM_TAG '=' YY_NUMBER { $$ = new_opt(IPM_TAG); $$->o_num = $3; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.s_addr = htonl($$.s_addr); } %% static struct wordtab yywords[] = { { "action", IPM_ACTION }, { "body", IPM_BODY }, { "direction", IPM_DIRECTION }, { "dstip", IPM_DSTIP }, { "dstport", IPM_DSTPORT }, { "every", IPM_EVERY }, { "execute", IPM_EXECUTE }, { "group", IPM_GROUP }, { "in", IPM_IN }, { "interface", IPM_INTERFACE }, { "no", IPM_NO }, { "out", IPM_OUT }, { "packet", IPM_PACKET }, { "packets", IPM_PACKETS }, { "protocol", IPM_PROTOCOL }, { "result", IPM_RESULT }, { "rule", IPM_RULE }, { "second", IPM_SECOND }, { "seconds", IPM_SECONDS }, { "srcip", IPM_SRCIP }, { "srcport", IPM_SRCPORT }, { "tag", IPM_TAG }, { "yes", IPM_YES }, { NULL, 0 } }; static int macflags[15][2] = { { IPM_DIRECTION, IPMAC_DIRECTION }, { IPM_DSTIP, IPMAC_DSTIP }, { IPM_DSTPORT, IPMAC_DSTPORT }, { IPM_EXECUTE, IPMAC_EXECUTE }, { IPM_GROUP, IPMAC_GROUP }, { IPM_INTERFACE, IPMAC_INTERFACE }, { IPM_PACKET, IPMAC_EVERY }, { IPM_PROTOCOL, IPMAC_PROTOCOL }, { IPM_RESULT, IPMAC_RESULT }, { IPM_RULE, IPMAC_RULE }, { IPM_SECOND, IPMAC_EVERY }, { IPM_SRCIP, IPMAC_SRCIP }, { IPM_SRCPORT, IPMAC_SRCPORT }, { IPM_TAG, IPMAC_TAG }, { 0, 0 } }; static opt_t *new_opt(type) int type; { opt_t *o; o = (opt_t *)malloc(sizeof(*o)); if (o == NULL) yyerror("sorry, out of memory"); o->o_type = type; o->o_line = yylineNum; o->o_num = 0; o->o_str = (char *)0; return o; } static void build_action(olist) opt_t *olist; { action_t *a; opt_t *o; u_32_t m; char c; int i; a = (action_t *)calloc(1, sizeof(*a)); if (!a) return; while ((o = olist)) { for (i = 0; macflags[i][0]; i++) if (macflags[i][0] == o->o_type) break; if (macflags[i][1] & a->ac_mflag) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); if (o->o_str != NULL) free(o->o_str); olist = o->o_next; free(o); continue; } a->ac_mflag |= macflags[i][1]; switch (o->o_type) { case IPM_DIRECTION : a->ac_direction = o->o_num; break; case IPM_DSTIP : a->ac_dip = o->o_ip.s_addr; for (i = o->o_num, m = 0; i; i--) { m >>= 1; m |= 0x80000000; } a->ac_dmsk = htonl(m); break; case IPM_DSTPORT : a->ac_dport = htons(o->o_num); break; case IPM_EXECUTE : a->ac_exec = o->o_str; c = *o->o_str; if (c== '"'|| c == '\'') { if (o->o_str[strlen(o->o_str) - 1] == c) { a->ac_run = strdup(o->o_str + 1); a->ac_run[strlen(a->ac_run) - 1] ='\0'; } else a->ac_run = o->o_str; } else a->ac_run = o->o_str; o->o_str = NULL; break; case IPM_INTERFACE : a->ac_iface = o->o_str; o->o_str = NULL; break; case IPM_GROUP : if (o->o_str != NULL) strncpy(a->ac_group, o->o_str, FR_GROUPLEN); else sprintf(a->ac_group, "%d", o->o_num); break; case IPM_PACKET : a->ac_packet = o->o_num; break; case IPM_PROTOCOL : a->ac_proto = o->o_num; break; case IPM_RULE : a->ac_rule = o->o_num; break; case IPM_RESULT : if (!strcasecmp(o->o_str, "pass")) a->ac_result = IPMR_PASS; else if (!strcasecmp(o->o_str, "block")) a->ac_result = IPMR_BLOCK; else if (!strcasecmp(o->o_str, "short")) a->ac_result = IPMR_SHORT; else if (!strcasecmp(o->o_str, "nomatch")) a->ac_result = IPMR_NOMATCH; else if (!strcasecmp(o->o_str, "log")) a->ac_result = IPMR_LOG; break; case IPM_SECOND : a->ac_second = o->o_num; break; case IPM_SRCIP : a->ac_sip = o->o_ip.s_addr; for (i = o->o_num, m = 0; i; i--) { m >>= 1; m |= 0x80000000; } a->ac_smsk = htonl(m); break; case IPM_SRCPORT : a->ac_sport = htons(o->o_num); break; case IPM_TAG : a->ac_tag = o->o_num; break; default : break; } olist = o->o_next; if (o->o_str != NULL) free(o->o_str); free(o); } a->a_next = alist; alist = a; } void check_action(buf, opts, log) char *buf; int opts; char *log; { struct timeval tv; ipflog_t *ipf; tcphdr_t *tcp; iplog_t *ipl; action_t *a; u_long t1; ip_t *ip; ipl = (iplog_t *)buf; ipf = (ipflog_t *)(ipl +1); ip = (ip_t *)(ipf + 1); tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); for (a = alist; a; a = a->a_next) { if (a->ac_mflag & IPMAC_DIRECTION) { if (a->ac_direction == IPM_IN) { if (!(ipf->fl_flags & FR_INQUE)) continue; } else if (a->ac_direction == IPM_OUT) { if (!(ipf->fl_flags & FR_OUTQUE)) continue; } } if (a->ac_mflag & IPMAC_EVERY) { gettimeofday(&tv, NULL); t1 = tv.tv_sec - a->ac_lastsec; if (tv.tv_usec <= a->ac_lastusec) t1--; if (a->ac_second) { if (t1 < a->ac_second) continue; a->ac_lastsec = tv.tv_sec; a->ac_lastusec = tv.tv_usec; } if (a->ac_packet) { if (!a->ac_pktcnt) a->ac_pktcnt++; else if (a->ac_pktcnt == a->ac_packet) { a->ac_pktcnt = 0; continue; } else { a->ac_pktcnt++; continue; } } } if (a->ac_mflag & IPMAC_DSTIP) { if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) continue; } if (a->ac_mflag & IPMAC_DSTPORT) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_dport != a->ac_dport) continue; } if (a->ac_mflag & IPMAC_GROUP) { if (strncmp(a->ac_group, ipf->fl_group, FR_GROUPLEN) != 0) continue; } if (a->ac_mflag & IPMAC_INTERFACE) { if (strcmp(a->ac_iface, ipf->fl_ifname)) continue; } if (a->ac_mflag & IPMAC_PROTOCOL) { if (a->ac_proto != ip->ip_p) continue; } if (a->ac_mflag & IPMAC_RESULT) { if (ipf->fl_lflags & FI_SHORT) { if (a->ac_result != IPMR_SHORT) continue; } else if (FR_ISPASS(ipf->fl_flags)) { if (a->ac_result != IPMR_PASS) continue; } else if (FR_ISBLOCK(ipf->fl_flags)) { if (a->ac_result != IPMR_BLOCK) continue; } else if (ipf->fl_flags & FF_LOGNOMATCH) { if (a->ac_result != IPMR_NOMATCH) continue; } else { /* Log only */ if (a->ac_result != IPMR_LOG) continue; } } if (a->ac_mflag & IPMAC_RULE) { if (a->ac_rule != ipf->fl_rule) continue; } if (a->ac_mflag & IPMAC_SRCIP) { if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) continue; } if (a->ac_mflag & IPMAC_SRCPORT) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_sport != a->ac_sport) continue; } if (a->ac_mflag & IPMAC_TAG) { if (a->ac_tag != ipf->fl_tag) continue; } /* * It matched so now execute the command */ if (a->ac_exec) { switch (fork()) { case 0 : { FILE *pi; pi = popen(a->ac_run, "w"); if (pi) { fprintf(pi, "%s\n", log); if (opts & OPT_HEXHDR) { dumphex(pi, 0, buf, sizeof(*ipl) + sizeof(*ipf)); } if (opts & OPT_HEXBODY) { dumphex(pi, 0, (char *)ip, ipf->fl_hlen + ipf->fl_plen); } pclose(pi); } exit(1); } case -1 : break; default : break; } } } } int load_config(file) char *file; { FILE *fp; yylineNum = 0; (void) yysettab(yywords); fp = fopen(file, "r"); if (!fp) { perror("load_config:fopen:"); return -1; } yyin = fp; while (!feof(fp)) yyparse(); fclose(fp); return 0; }