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