xref: /illumos-gate/usr/src/cmd/ipf/tools/ipmon_y.y (revision bea83d026ee1bd1b2a2419e1d0232f107a5d7d9b)
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 
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 
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 
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 
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 
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