1 /*
2 * Copyright (C) 1993-2005 by Darren Reed.
3 * See the IPFILTER.LICENCE file for details on licencing.
4 */
5
6 %{
7 #include "ipf.h"
8 #include <syslog.h>
9 #undef OPT_NAT
10 #undef OPT_VERBOSE
11 #include "ipmon_l.h"
12 #include "ipmon.h"
13
14 #define YYDEBUG 1
15
16 extern void yyerror __P((char *));
17 extern int yyparse __P((void));
18 extern int yylex __P((void));
19 extern int yydebug;
20 extern FILE *yyin;
21 extern int yylineNum;
22
23 typedef struct opt {
24 struct opt *o_next;
25 int o_line;
26 int o_type;
27 int o_num;
28 char *o_str;
29 struct in_addr o_ip;
30 } opt_t;
31
32 static void build_action __P((struct opt *));
33 static opt_t *new_opt __P((int));
34 static void free_action __P((ipmon_action_t *));
35
36 static ipmon_action_t *alist = NULL;
37 %}
38
39 %union {
40 char *str;
41 u_32_t num;
42 struct in_addr addr;
43 struct opt *opt;
44 union i6addr ip6;
45 }
46
47 %token <num> YY_NUMBER YY_HEX
48 %token <str> YY_STR
49 %token <ip6> YY_IPV6
50 %token YY_COMMENT
51 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
52 %token YY_RANGE_OUT YY_RANGE_IN
53
54 %token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
55 %token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT
56 %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
57 %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
58 %token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT
59 %token IPM_STATE IPM_NATTAG IPM_IPF
60 %type <addr> ipv4
61 %type <opt> direction dstip dstport every execute group interface
62 %type <opt> protocol result rule srcip srcport logtag matching
63 %type <opt> matchopt nattag type doopt doing save syslog nothing
64 %type <num> saveopts saveopt typeopt
65
66 %%
67 file: line
68 | assign
69 | file line
70 | file assign
71 ;
72
73 line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';'
74 { build_action($3); resetlexer(); }
75 | IPM_COMMENT
76 | YY_COMMENT
77 ;
78
79 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
80 resetlexer();
81 free($1);
82 free($3);
83 }
84 ;
85
86 assigning:
87 '=' { yyvarnext = 1; }
88 ;
89
90 matching:
91 matchopt { $$ = $1; }
92 | matchopt ',' matching { $1->o_next = $3; $$ = $1; }
93 ;
94
95 matchopt:
96 direction { $$ = $1; }
97 | dstip { $$ = $1; }
98 | dstport { $$ = $1; }
99 | every { $$ = $1; }
100 | group { $$ = $1; }
101 | interface { $$ = $1; }
102 | protocol { $$ = $1; }
103 | result { $$ = $1; }
104 | rule { $$ = $1; }
105 | srcip { $$ = $1; }
106 | srcport { $$ = $1; }
107 | logtag { $$ = $1; }
108 | nattag { $$ = $1; }
109 | type { $$ = $1; }
110 ;
111
112 doing:
113 doopt { $$ = $1; }
114 | doopt ',' doing { $1->o_next = $3; $$ = $1; }
115 ;
116
117 doopt:
118 execute { $$ = $1; }
119 | save { $$ = $1; }
120 | syslog { $$ = $1; }
121 | nothing { $$ = $1; }
122 ;
123
124 direction:
125 IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION);
126 $$->o_num = IPM_IN; }
127 | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION);
128 $$->o_num = IPM_OUT; }
129 ;
130
131 dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP);
132 $$->o_ip = $3;
133 $$->o_num = $5; }
134 ;
135
136 dstport:
137 IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT);
138 $$->o_num = $3; }
139 | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT);
140 $$->o_str = $3; }
141 ;
142
143 every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND);
144 $$->o_num = 1; }
145 | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND);
146 $$->o_num = $2; }
147 | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET);
148 $$->o_num = 1; }
149 | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET);
150 $$->o_num = $2; }
151 ;
152
153 group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP);
154 $$->o_num = $3; }
155 | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP);
156 $$->o_str = $3; }
157 ;
158
159 interface:
160 IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE);
161 $$->o_str = $3; }
162 ;
163
164 logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG);
165 $$->o_num = $3; }
166 ;
167
168 nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG);
169 $$->o_str = $3; }
170 ;
171
172 protocol:
173 IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL);
174 $$->o_num = $3; }
175 | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL);
176 $$->o_num = getproto($3);
177 free($3);
178 }
179 ;
180
181 result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT);
182 $$->o_str = $3; }
183 ;
184
185 rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE);
186 $$->o_num = YY_NUMBER; }
187 ;
188
189 srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP);
190 $$->o_ip = $3;
191 $$->o_num = $5; }
192 ;
193
194 srcport:
195 IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT);
196 $$->o_num = $3; }
197 | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT);
198 $$->o_str = $3; }
199 ;
200
201 type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE);
202 $$->o_num = $3; }
203 ;
204
205 typeopt:
206 IPM_IPF { $$ = IPL_MAGIC; }
207 | IPM_NAT { $$ = IPL_MAGIC_NAT; }
208 | IPM_STATE { $$ = IPL_MAGIC_STATE; }
209 ;
210
211 execute:
212 IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE);
213 $$->o_str = $2; }
214 ;
215
216 save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE);
217 $$->o_num = $2;
218 $$->o_str = $3; }
219 ;
220
221 saveopts: { $$ = 0; }
222 | saveopt { $$ = $1; }
223 | saveopt ',' saveopts { $$ = $1 | $3; }
224 ;
225
226 saveopt:
227 IPM_RAW { $$ = IPMDO_SAVERAW; }
228 ;
229
230 syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); }
231 ;
232
233 nothing:
234 IPM_NOTHING { $$ = 0; }
235 ;
236
237 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
238 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
239 yyerror("Invalid octet string for IP address");
240 return 0;
241 }
242 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
243 $$.s_addr = htonl($$.s_addr);
244 }
245 %%
246 static struct wordtab yywords[] = {
247 { "body", IPM_BODY },
248 { "direction", IPM_DIRECTION },
249 { "do", IPM_DO },
250 { "dstip", IPM_DSTIP },
251 { "dstport", IPM_DSTPORT },
252 { "every", IPM_EVERY },
253 { "execute", IPM_EXECUTE },
254 { "group", IPM_GROUP },
255 { "in", IPM_IN },
256 { "interface", IPM_INTERFACE },
257 { "ipf", IPM_IPF },
258 { "logtag", IPM_LOGTAG },
259 { "match", IPM_MATCH },
260 { "nat", IPM_NAT },
261 { "nattag", IPM_NATTAG },
262 { "no", IPM_NO },
263 { "nothing", IPM_NOTHING },
264 { "out", IPM_OUT },
265 { "packet", IPM_PACKET },
266 { "packets", IPM_PACKETS },
267 { "protocol", IPM_PROTOCOL },
268 { "result", IPM_RESULT },
269 { "rule", IPM_RULE },
270 { "save", IPM_SAVE },
271 { "raw", IPM_RAW },
272 { "second", IPM_SECOND },
273 { "seconds", IPM_SECONDS },
274 { "srcip", IPM_SRCIP },
275 { "srcport", IPM_SRCPORT },
276 { "state", IPM_STATE },
277 { "syslog", IPM_SYSLOG },
278 { "with", IPM_WITH },
279 { NULL, 0 }
280 };
281
282 static int macflags[17][2] = {
283 { IPM_DIRECTION, IPMAC_DIRECTION },
284 { IPM_DSTIP, IPMAC_DSTIP },
285 { IPM_DSTPORT, IPMAC_DSTPORT },
286 { IPM_GROUP, IPMAC_GROUP },
287 { IPM_INTERFACE, IPMAC_INTERFACE },
288 { IPM_LOGTAG, IPMAC_LOGTAG },
289 { IPM_NATTAG, IPMAC_NATTAG },
290 { IPM_PACKET, IPMAC_EVERY },
291 { IPM_PROTOCOL, IPMAC_PROTOCOL },
292 { IPM_RESULT, IPMAC_RESULT },
293 { IPM_RULE, IPMAC_RULE },
294 { IPM_SECOND, IPMAC_EVERY },
295 { IPM_SRCIP, IPMAC_SRCIP },
296 { IPM_SRCPORT, IPMAC_SRCPORT },
297 { IPM_TYPE, IPMAC_TYPE },
298 { IPM_WITH, IPMAC_WITH },
299 { 0, 0 }
300 };
301
new_opt(type)302 static opt_t *new_opt(type)
303 int type;
304 {
305 opt_t *o;
306
307 o = (opt_t *)malloc(sizeof(*o));
308 if (o == NULL)
309 yyerror("sorry, out of memory");
310 o->o_type = type;
311 o->o_line = yylineNum;
312 o->o_num = 0;
313 o->o_str = (char *)0;
314 o->o_next = NULL;
315 return o;
316 }
317
build_action(olist)318 static void build_action(olist)
319 opt_t *olist;
320 {
321 ipmon_action_t *a;
322 opt_t *o;
323 char c;
324 int i;
325
326 a = (ipmon_action_t *)calloc(1, sizeof(*a));
327 if (a == NULL)
328 return;
329 while ((o = olist) != NULL) {
330 /*
331 * Check to see if the same comparator is being used more than
332 * once per matching statement.
333 */
334 for (i = 0; macflags[i][0]; i++)
335 if (macflags[i][0] == o->o_type)
336 break;
337 if (macflags[i][1] & a->ac_mflag) {
338 fprintf(stderr, "%s redfined on line %d\n",
339 yykeytostr(o->o_type), yylineNum);
340 if (o->o_str != NULL)
341 free(o->o_str);
342 olist = o->o_next;
343 free(o);
344 continue;
345 }
346
347 a->ac_mflag |= macflags[i][1];
348
349 switch (o->o_type)
350 {
351 case IPM_DIRECTION :
352 a->ac_direction = o->o_num;
353 break;
354 case IPM_DSTIP :
355 a->ac_dip = o->o_ip.s_addr;
356 a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
357 break;
358 case IPM_DSTPORT :
359 a->ac_dport = htons(o->o_num);
360 break;
361 case IPM_EXECUTE :
362 a->ac_exec = o->o_str;
363 c = *o->o_str;
364 if (c== '"'|| c == '\'') {
365 if (o->o_str[strlen(o->o_str) - 1] == c) {
366 a->ac_run = strdup(o->o_str + 1);
367 a->ac_run[strlen(a->ac_run) - 1] ='\0';
368 } else
369 a->ac_run = o->o_str;
370 } else
371 a->ac_run = o->o_str;
372 o->o_str = NULL;
373 break;
374 case IPM_INTERFACE :
375 a->ac_iface = o->o_str;
376 o->o_str = NULL;
377 break;
378 case IPM_GROUP :
379 if (o->o_str != NULL)
380 strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
381 else
382 sprintf(a->ac_group, "%d", o->o_num);
383 break;
384 case IPM_LOGTAG :
385 a->ac_logtag = o->o_num;
386 break;
387 case IPM_NATTAG :
388 strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
389 break;
390 case IPM_PACKET :
391 a->ac_packet = o->o_num;
392 break;
393 case IPM_PROTOCOL :
394 a->ac_proto = o->o_num;
395 break;
396 case IPM_RULE :
397 a->ac_rule = o->o_num;
398 break;
399 case IPM_RESULT :
400 if (!strcasecmp(o->o_str, "pass"))
401 a->ac_result = IPMR_PASS;
402 else if (!strcasecmp(o->o_str, "block"))
403 a->ac_result = IPMR_BLOCK;
404 else if (!strcasecmp(o->o_str, "nomatch"))
405 a->ac_result = IPMR_NOMATCH;
406 else if (!strcasecmp(o->o_str, "log"))
407 a->ac_result = IPMR_LOG;
408 break;
409 case IPM_SECOND :
410 a->ac_second = o->o_num;
411 break;
412 case IPM_SRCIP :
413 a->ac_sip = o->o_ip.s_addr;
414 a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
415 break;
416 case IPM_SRCPORT :
417 a->ac_sport = htons(o->o_num);
418 break;
419 case IPM_SAVE :
420 if (a->ac_savefile != NULL) {
421 fprintf(stderr, "%s redfined on line %d\n",
422 yykeytostr(o->o_type), yylineNum);
423 break;
424 }
425 a->ac_savefile = strdup(o->o_str);
426 a->ac_savefp = fopen(o->o_str, "a");
427 a->ac_dflag |= o->o_num & IPMDO_SAVERAW;
428 break;
429 case IPM_SYSLOG :
430 if (a->ac_syslog != 0) {
431 fprintf(stderr, "%s redfined on line %d\n",
432 yykeytostr(o->o_type), yylineNum);
433 break;
434 }
435 a->ac_syslog = 1;
436 break;
437 case IPM_TYPE :
438 a->ac_type = o->o_num;
439 break;
440 case IPM_WITH :
441 break;
442 default :
443 break;
444 }
445
446 olist = o->o_next;
447 if (o->o_str != NULL)
448 free(o->o_str);
449 free(o);
450 }
451 a->ac_next = alist;
452 alist = a;
453 }
454
455
check_action(buf,log,opts,lvl)456 int check_action(buf, log, opts, lvl)
457 char *buf, *log;
458 int opts, lvl;
459 {
460 ipmon_action_t *a;
461 struct timeval tv;
462 ipflog_t *ipf;
463 tcphdr_t *tcp;
464 iplog_t *ipl;
465 int matched;
466 u_long t1;
467 ip_t *ip;
468
469 matched = 0;
470 ipl = (iplog_t *)buf;
471 ipf = (ipflog_t *)(ipl +1);
472 ip = (ip_t *)(ipf + 1);
473 tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
474
475 for (a = alist; a != NULL; a = a->ac_next) {
476 if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
477 if (a->ac_direction == IPM_IN) {
478 if ((ipf->fl_flags & FR_INQUE) == 0)
479 continue;
480 } else if (a->ac_direction == IPM_OUT) {
481 if ((ipf->fl_flags & FR_OUTQUE) == 0)
482 continue;
483 }
484 }
485
486 if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic))
487 continue;
488
489 if ((a->ac_mflag & IPMAC_EVERY) != 0) {
490 gettimeofday(&tv, NULL);
491 t1 = tv.tv_sec - a->ac_lastsec;
492 if (tv.tv_usec <= a->ac_lastusec)
493 t1--;
494 if (a->ac_second != 0) {
495 if (t1 < a->ac_second)
496 continue;
497 a->ac_lastsec = tv.tv_sec;
498 a->ac_lastusec = tv.tv_usec;
499 }
500
501 if (a->ac_packet != 0) {
502 if (a->ac_pktcnt == 0)
503 a->ac_pktcnt++;
504 else if (a->ac_pktcnt == a->ac_packet) {
505 a->ac_pktcnt = 0;
506 continue;
507 } else {
508 a->ac_pktcnt++;
509 continue;
510 }
511 }
512 }
513
514 if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
515 if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip)
516 continue;
517 }
518
519 if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
520 if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
521 continue;
522 if (tcp->th_dport != a->ac_dport)
523 continue;
524 }
525
526 if ((a->ac_mflag & IPMAC_GROUP) != 0) {
527 if (strncmp(a->ac_group, ipf->fl_group,
528 FR_GROUPLEN) != 0)
529 continue;
530 }
531
532 if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
533 if (strcmp(a->ac_iface, ipf->fl_ifname))
534 continue;
535 }
536
537 if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
538 if (a->ac_proto != ip->ip_p)
539 continue;
540 }
541
542 if ((a->ac_mflag & IPMAC_RESULT) != 0) {
543 if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
544 if (a->ac_result != IPMR_NOMATCH)
545 continue;
546 } else if (FR_ISPASS(ipf->fl_flags)) {
547 if (a->ac_result != IPMR_PASS)
548 continue;
549 } else if (FR_ISBLOCK(ipf->fl_flags)) {
550 if (a->ac_result != IPMR_BLOCK)
551 continue;
552 } else { /* Log only */
553 if (a->ac_result != IPMR_LOG)
554 continue;
555 }
556 }
557
558 if ((a->ac_mflag & IPMAC_RULE) != 0) {
559 if (a->ac_rule != ipf->fl_rule)
560 continue;
561 }
562
563 if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
564 if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip)
565 continue;
566 }
567
568 if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
569 if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP)
570 continue;
571 if (tcp->th_sport != a->ac_sport)
572 continue;
573 }
574
575 if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
576 if (a->ac_logtag != ipf->fl_logtag)
577 continue;
578 }
579
580 if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
581 if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
582 IPFTAG_LEN) != 0)
583 continue;
584 }
585
586 matched = 1;
587
588 /*
589 * It matched so now execute the command
590 */
591 if (a->ac_syslog != 0) {
592 syslog(lvl, "%s", log);
593 }
594
595 if (a->ac_savefp != NULL) {
596 if (a->ac_dflag & IPMDO_SAVERAW)
597 fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp);
598 else
599 fputs(log, a->ac_savefp);
600 }
601
602 if (a->ac_exec != NULL) {
603 switch (fork())
604 {
605 case 0 :
606 {
607 FILE *pi;
608
609 pi = popen(a->ac_run, "w");
610 if (pi != NULL) {
611 fprintf(pi, "%s\n", log);
612 if ((opts & OPT_HEXHDR) != 0) {
613 dumphex(pi, 0, buf,
614 sizeof(*ipl) +
615 sizeof(*ipf));
616 }
617 if ((opts & OPT_HEXBODY) != 0) {
618 dumphex(pi, 0, (char *)ip,
619 ipf->fl_hlen +
620 ipf->fl_plen);
621 }
622 pclose(pi);
623 }
624 exit(1);
625 }
626 case -1 :
627 break;
628 default :
629 break;
630 }
631 }
632 }
633
634 return matched;
635 }
636
637
free_action(a)638 static void free_action(a)
639 ipmon_action_t *a;
640 {
641 if (a->ac_savefile != NULL) {
642 free(a->ac_savefile);
643 a->ac_savefile = NULL;
644 }
645 if (a->ac_savefp != NULL) {
646 fclose(a->ac_savefp);
647 a->ac_savefp = NULL;
648 }
649 if (a->ac_exec != NULL) {
650 free(a->ac_exec);
651 if (a->ac_run == a->ac_exec)
652 a->ac_run = NULL;
653 a->ac_exec = NULL;
654 }
655 if (a->ac_run != NULL) {
656 free(a->ac_run);
657 a->ac_run = NULL;
658 }
659 if (a->ac_iface != NULL) {
660 free(a->ac_iface);
661 a->ac_iface = NULL;
662 }
663 a->ac_next = NULL;
664 free(a);
665 }
666
667
load_config(file)668 int load_config(file)
669 char *file;
670 {
671 ipmon_action_t *a;
672 FILE *fp;
673 char *s;
674
675 s = getenv("YYDEBUG");
676 if (s != NULL)
677 yydebug = atoi(s);
678 else
679 yydebug = 0;
680
681 while ((a = alist) != NULL) {
682 alist = a->ac_next;
683 free_action(a);
684 }
685
686 yylineNum = 1;
687
688 (void) yysettab(yywords);
689
690 fp = fopen(file, "r");
691 if (!fp) {
692 perror("load_config:fopen:");
693 return -1;
694 }
695 yyin = fp;
696 while (!feof(fp))
697 yyparse();
698 fclose(fp);
699 return 0;
700 }
701