4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
20 extern void yyerror __P((char *));
21 extern int yyparse __P((void));
22 extern int yylex __P((void));
28 typedef struct opt_s {
39 static void build_action __P((opt_t *, ipmon_doing_t *));
40 static opt_t *new_opt __P((int));
41 static void free_action __P((ipmon_action_t *));
42 static void print_action __P((ipmon_action_t *));
43 static int find_doing __P((char *));
44 static ipmon_doing_t *build_doing __P((char *, char *));
45 static void print_match __P((ipmon_action_t *));
46 static int install_saver __P((char *, char *));
48 static ipmon_action_t *alist = NULL;
50 ipmon_saver_int_t *saverlist = NULL;
59 struct ipmon_doing_s *ipmd;
62 %token <num> YY_NUMBER YY_HEX
66 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
67 %token YY_RANGE_OUT YY_RANGE_IN
69 %token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
70 %token IPM_EVERY IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT IPM_LOADACTION
71 %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
72 %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
73 %token IPM_DO IPM_DOING IPM_TYPE IPM_NAT
74 %token IPM_STATE IPM_NATTAG IPM_IPF
76 %type <opt> direction dstip dstport every group interface
77 %type <opt> protocol result rule srcip srcport logtag matching
78 %type <opt> matchopt nattag type
80 %type <ipmd> doopt doing
93 line: IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}'
94 { build_action($3, $8);
97 | IPM_LOADACTION YY_STR YY_STR { if (install_saver($2, $3))
98 yyerror("install saver");
102 assign: YY_STR assigning YY_STR { set_variable($1, $3);
111 '=' { yyvarnext = 1; }
115 matchopt { $$ = $1; }
116 | matchopt ',' matching { $1->o_next = $3; $$ = $1; }
120 direction { $$ = $1; }
122 | dstport { $$ = $1; }
125 | interface { $$ = $1; }
126 | protocol { $$ = $1; }
127 | result { $$ = $1; }
130 | srcport { $$ = $1; }
131 | logtag { $$ = $1; }
132 | nattag { $$ = $1; }
138 | doopt ',' doing { $1->ipmd_next = $3; $$ = $1; }
142 YY_STR { if (find_doing($1) != IPM_DOING)
143 yyerror("unknown action");
145 '(' YY_STR ')' { $$ = build_doing($1, $4);
147 yyerror("action building");
149 | YY_STR { if (find_doing($1) == IPM_DOING)
150 $$ = build_doing($1, NULL);
155 IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION);
156 $$->o_num = IPM_IN; }
157 | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION);
158 $$->o_num = IPM_OUT; }
161 dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP);
167 IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT);
169 | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT);
173 every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND);
175 | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND);
177 | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET);
179 | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET);
183 group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP);
185 | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP);
190 IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE);
194 logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG);
198 nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG);
203 IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL);
205 | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL);
206 $$->o_num = getproto($3);
211 result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT);
215 rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE);
216 $$->o_num = YY_NUMBER; }
219 srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP);
225 IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT);
227 | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT);
231 type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE);
236 IPM_IPF { $$ = IPL_MAGIC; }
237 | IPM_NAT { $$ = IPL_MAGIC_NAT; }
238 | IPM_STATE { $$ = IPL_MAGIC_STATE; }
243 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
244 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
245 yyerror("Invalid octet string for IP address");
248 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
249 $$.s_addr = htonl($$.s_addr);
252 static struct wordtab yywords[] = {
253 { "body", IPM_BODY },
254 { "direction", IPM_DIRECTION },
256 { "dstip", IPM_DSTIP },
257 { "dstport", IPM_DSTPORT },
258 { "every", IPM_EVERY },
259 { "group", IPM_GROUP },
261 { "interface", IPM_INTERFACE },
263 { "load_action",IPM_LOADACTION },
264 { "logtag", IPM_LOGTAG },
265 { "match", IPM_MATCH },
267 { "nattag", IPM_NATTAG },
270 { "packet", IPM_PACKET },
271 { "packets", IPM_PACKETS },
272 { "protocol", IPM_PROTOCOL },
273 { "result", IPM_RESULT },
274 { "rule", IPM_RULE },
275 { "second", IPM_SECOND },
276 { "seconds", IPM_SECONDS },
277 { "srcip", IPM_SRCIP },
278 { "srcport", IPM_SRCPORT },
279 { "state", IPM_STATE },
280 { "with", IPM_WITH },
284 static int macflags[17][2] = {
285 { IPM_DIRECTION, IPMAC_DIRECTION },
286 { IPM_DSTIP, IPMAC_DSTIP },
287 { IPM_DSTPORT, IPMAC_DSTPORT },
288 { IPM_GROUP, IPMAC_GROUP },
289 { IPM_INTERFACE, IPMAC_INTERFACE },
290 { IPM_LOGTAG, IPMAC_LOGTAG },
291 { IPM_NATTAG, IPMAC_NATTAG },
292 { IPM_PACKET, IPMAC_EVERY },
293 { IPM_PROTOCOL, IPMAC_PROTOCOL },
294 { IPM_RESULT, IPMAC_RESULT },
295 { IPM_RULE, IPMAC_RULE },
296 { IPM_SECOND, IPMAC_EVERY },
297 { IPM_SRCIP, IPMAC_SRCIP },
298 { IPM_SRCPORT, IPMAC_SRCPORT },
299 { IPM_TYPE, IPMAC_TYPE },
300 { IPM_WITH, IPMAC_WITH },
310 o = (opt_t *)calloc(1, sizeof(*o));
312 o->o_line = yylineNum;
319 build_action(olist, todo)
327 a = (ipmon_action_t *)calloc(1, sizeof(*a));
331 while ((o = olist) != NULL) {
333 * Check to see if the same comparator is being used more than
334 * once per matching statement.
336 for (i = 0; macflags[i][0]; i++)
337 if (macflags[i][0] == o->o_type)
339 if (macflags[i][1] & a->ac_mflag) {
340 fprintf(stderr, "%s redfined on line %d\n",
341 yykeytostr(o->o_type), yylineNum);
342 if (o->o_str != NULL)
349 a->ac_mflag |= macflags[i][1];
354 a->ac_direction = o->o_num;
357 a->ac_dip = o->o_ip.s_addr;
358 a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
361 a->ac_dport = htons(o->o_num);
364 a->ac_iface = o->o_str;
368 if (o->o_str != NULL)
369 strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
371 sprintf(a->ac_group, "%d", o->o_num);
374 a->ac_logtag = o->o_num;
377 strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
380 a->ac_packet = o->o_num;
383 a->ac_proto = o->o_num;
386 a->ac_rule = o->o_num;
389 if (!strcasecmp(o->o_str, "pass"))
390 a->ac_result = IPMR_PASS;
391 else if (!strcasecmp(o->o_str, "block"))
392 a->ac_result = IPMR_BLOCK;
393 else if (!strcasecmp(o->o_str, "nomatch"))
394 a->ac_result = IPMR_NOMATCH;
395 else if (!strcasecmp(o->o_str, "log"))
396 a->ac_result = IPMR_LOG;
399 a->ac_second = o->o_num;
402 a->ac_sip = o->o_ip.s_addr;
403 a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
406 a->ac_sport = htons(o->o_num);
409 a->ac_type = o->o_num;
418 if (o->o_str != NULL)
427 if (ipmonopts & IPMON_VERBOSE)
433 check_action(buf, log, opts, lvl)
449 ipl = (iplog_t *)buf;
450 ipf = (ipflog_t *)(ipl +1);
451 ip = (ip_t *)(ipf + 1);
452 tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
455 msg.imm_dsize = ipl->ipl_dsize;
456 msg.imm_when = ipl->ipl_time.tv_sec;
458 msg.imm_msglen = strlen(log);
459 msg.imm_loglevel = lvl;
461 for (a = alist; a != NULL; a = a->ac_next) {
462 verbose(0, "== checking config rule\n");
463 if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
464 if (a->ac_direction == IPM_IN) {
465 if ((ipf->fl_flags & FR_INQUE) == 0) {
466 verbose(8, "-- direction not in\n");
469 } else if (a->ac_direction == IPM_OUT) {
470 if ((ipf->fl_flags & FR_OUTQUE) == 0) {
471 verbose(8, "-- direction not out\n");
477 if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) {
478 verbose(8, "-- type mismatch\n");
482 if ((a->ac_mflag & IPMAC_EVERY) != 0) {
483 gettimeofday(&tv, NULL);
484 t1 = tv.tv_sec - a->ac_lastsec;
485 if (tv.tv_usec <= a->ac_lastusec)
487 if (a->ac_second != 0) {
488 if (t1 < a->ac_second) {
489 verbose(8, "-- too soon\n");
492 a->ac_lastsec = tv.tv_sec;
493 a->ac_lastusec = tv.tv_usec;
496 if (a->ac_packet != 0) {
497 if (a->ac_pktcnt == 0)
499 else if (a->ac_pktcnt == a->ac_packet) {
501 verbose(8, "-- packet count\n");
505 verbose(8, "-- packet count\n");
511 if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
512 if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) {
513 verbose(8, "-- dstip wrong\n");
518 if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
519 if (ip->ip_p != IPPROTO_UDP &&
520 ip->ip_p != IPPROTO_TCP) {
521 verbose(8, "-- not port protocol\n");
524 if (tcp->th_dport != a->ac_dport) {
525 verbose(8, "-- dport mismatch\n");
530 if ((a->ac_mflag & IPMAC_GROUP) != 0) {
531 if (strncmp(a->ac_group, ipf->fl_group,
533 verbose(8, "-- group mismatch\n");
538 if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
539 if (strcmp(a->ac_iface, ipf->fl_ifname)) {
540 verbose(8, "-- ifname mismatch\n");
545 if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
546 if (a->ac_proto != ip->ip_p) {
547 verbose(8, "-- protocol mismatch\n");
552 if ((a->ac_mflag & IPMAC_RESULT) != 0) {
553 if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
554 if (a->ac_result != IPMR_NOMATCH) {
555 verbose(8, "-- ff-flags mismatch\n");
558 } else if (FR_ISPASS(ipf->fl_flags)) {
559 if (a->ac_result != IPMR_PASS) {
560 verbose(8, "-- pass mismatch\n");
563 } else if (FR_ISBLOCK(ipf->fl_flags)) {
564 if (a->ac_result != IPMR_BLOCK) {
565 verbose(8, "-- block mismatch\n");
568 } else { /* Log only */
569 if (a->ac_result != IPMR_LOG) {
570 verbose(8, "-- log mismatch\n");
576 if ((a->ac_mflag & IPMAC_RULE) != 0) {
577 if (a->ac_rule != ipf->fl_rule) {
578 verbose(8, "-- rule mismatch\n");
583 if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
584 if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) {
585 verbose(8, "-- srcip mismatch\n");
590 if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
591 if (ip->ip_p != IPPROTO_UDP &&
592 ip->ip_p != IPPROTO_TCP) {
593 verbose(8, "-- port protocol mismatch\n");
596 if (tcp->th_sport != a->ac_sport) {
597 verbose(8, "-- sport mismatch\n");
602 if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
603 if (a->ac_logtag != ipf->fl_logtag) {
604 verbose(8, "-- logtag %d != %d\n",
605 a->ac_logtag, ipf->fl_logtag);
610 if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
611 if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
613 verbose(8, "-- nattag mismatch\n");
619 verbose(8, "++ matched\n");
622 * It matched so now perform the saves
624 for (d = a->ac_doing; d != NULL; d = d->ipmd_next)
625 (*d->ipmd_store)(d->ipmd_token, &msg);
638 while ((d = a->ac_doing) != NULL) {
639 a->ac_doing = d->ipmd_next;
640 (*d->ipmd_saver->ims_destroy)(d->ipmd_token);
644 if (a->ac_iface != NULL) {
662 s = getenv("YYDEBUG");
670 (void) yysettab(yywords);
672 fp = fopen(file, "r");
674 perror("load_config:fopen:");
688 ipmon_saver_int_t *sav, **imsip;
692 while ((a = alist) != NULL) {
698 * Look for savers that have been added in dynamically from the
699 * configuration file.
701 for (imsip = &saverlist; (sav = *imsip) != NULL; ) {
702 if (sav->imsi_handle == NULL)
703 imsip = &sav->imsi_next;
705 dlclose(sav->imsi_handle);
707 *imsip = sav->imsi_next;
723 for (a = alist; a != NULL; a = a->ac_next) {
741 for (d = a->ac_doing; d != NULL; d = d->ipmd_next) {
742 printf("%s", d->ipmd_saver->ims_name);
743 if (d->ipmd_saver->ims_print != NULL) {
745 (*d->ipmd_saver->ims_print)(d->ipmd_token);
756 ipmon_saver_t *saver;
758 ipmon_saver_int_t *it;
760 if (find_doing(saver->ims_name) == IPM_DOING)
763 it = calloc(1, sizeof(*it));
766 it->imsi_stor = saver;
767 it->imsi_next = saverlist;
777 ipmon_saver_int_t *it;
779 for (it = saverlist; it != NULL; it = it->imsi_next) {
780 if (!strcmp(it->imsi_stor->ims_name, string))
787 static ipmon_doing_t *
788 build_doing(target, options)
792 ipmon_saver_int_t *it;
794 ipmon_doing_t *d, *d1;
798 d = calloc(1, sizeof(*d));
802 for (it = saverlist; it != NULL; it = it->imsi_next) {
803 if (!strcmp(it->imsi_stor->ims_name, target))
811 strarray[0] = options;
814 d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray);
815 if (d->ipmd_token == NULL) {
820 save = it->imsi_stor;
821 d->ipmd_saver = save;
822 d->ipmd_store = it->imsi_stor->ims_store;
825 * Look for duplicate do-things that need to be dup'd
827 for (a = alist; a != NULL; a = a->ac_next) {
828 for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) {
829 if (save != d1->ipmd_saver)
831 if (save->ims_match == NULL || save->ims_dup == NULL)
833 if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token))
836 (*d->ipmd_saver->ims_destroy)(d->ipmd_token);
837 d->ipmd_token = (*save->ims_dup)(d1->ipmd_token);
852 if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
853 printf("direction = ");
854 if (a->ac_direction == IPM_IN)
856 else if (a->ac_direction == IPM_OUT)
861 if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
862 printf("%sdstip = ", coma);
863 printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk);
867 if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
868 printf("%sdstport = %hu", coma, ntohs(a->ac_dport));
872 if ((a->ac_mflag & IPMAC_GROUP) != 0) {
873 char group[FR_GROUPLEN+1];
875 strncpy(group, a->ac_group, FR_GROUPLEN);
876 group[FR_GROUPLEN] = '\0';
877 printf("%sgroup = %s", coma, group);
881 if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
882 printf("%siface = %s", coma, a->ac_iface);
886 if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
887 printf("%slogtag = %u", coma, a->ac_logtag);
891 if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
894 strncpy(tag, a->ac_nattag, 16);
896 printf("%snattag = %s", coma, tag);
900 if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
901 printf("%sprotocol = %u", coma, a->ac_proto);
905 if ((a->ac_mflag & IPMAC_RESULT) != 0) {
906 printf("%sresult = ", coma);
907 switch (a->ac_result)
925 if ((a->ac_mflag & IPMAC_RULE) != 0) {
926 printf("%srule = %u", coma, a->ac_rule);
930 if ((a->ac_mflag & IPMAC_EVERY) != 0) {
931 if (a->ac_packet > 1) {
932 printf("%severy %d packets", coma, a->ac_packet);
934 } else if (a->ac_packet == 1) {
935 printf("%severy packet", coma);
938 if (a->ac_second > 1) {
939 printf("%severy %d seconds", coma, a->ac_second);
941 } else if (a->ac_second == 1) {
942 printf("%severy second", coma);
947 if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
948 printf("%ssrcip = ", coma);
949 printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk);
953 if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
954 printf("%ssrcport = %hu", coma, ntohs(a->ac_sport));
958 if ((a->ac_mflag & IPMAC_TYPE) != 0) {
959 printf("%stype = ", coma);
975 if ((a->ac_mflag & IPMAC_WITH) != 0) {
976 printf("%swith ", coma);
983 install_saver(name, path)
986 ipmon_saver_int_t *isi;
990 if (find_doing(name) == IPM_DOING)
993 isi = calloc(1, sizeof(*isi));
997 is = calloc(1, sizeof(*is));
1001 is->ims_name = name;
1004 isi->imsi_handle = dlopen(path, RTLD_LAZY);
1007 isi->imsi_handle = dlopen(path, DL_LAZY);
1010 if (isi->imsi_handle == NULL)
1013 snprintf(nbuf, sizeof(nbuf), "%sdup", name);
1014 is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf);
1016 snprintf(nbuf, sizeof(nbuf), "%sdestroy", name);
1017 is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf);
1018 if (is->ims_destroy == NULL)
1021 snprintf(nbuf, sizeof(nbuf), "%smatch", name);
1022 is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf);
1024 snprintf(nbuf, sizeof(nbuf), "%sparse", name);
1025 is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf);
1026 if (is->ims_parse == NULL)
1029 snprintf(nbuf, sizeof(nbuf), "%sprint", name);
1030 is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf);
1031 if (is->ims_print == NULL)
1034 snprintf(nbuf, sizeof(nbuf), "%sstore", name);
1035 is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf);
1036 if (is->ims_store == NULL)
1039 isi->imsi_stor = is;
1040 isi->imsi_next = saverlist;
1046 if (isi->imsi_handle != NULL)
1047 dlclose(isi->imsi_handle);