xref: /freebsd/sbin/ipf/ipmon/ipmon_y.y (revision 78bc019d220e05abb5b12f678f9b4a847019bbcc)
1 /*	$FreeBSD$	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 %{
9 #include "ipf.h"
10 #include <syslog.h>
11 #undef	OPT_NAT
12 #undef	OPT_VERBOSE
13 #include "ipmon_l.h"
14 #include "ipmon.h"
15 
16 #include <dlfcn.h>
17 
18 #define	YYDEBUG	1
19 
20 extern	void	yyerror(char *);
21 extern	int	yyparse(void);
22 extern	int	yylex(void);
23 extern	int	yydebug;
24 extern	FILE	*yyin;
25 extern	int	yylineNum;
26 extern	int	ipmonopts;
27 
28 typedef	struct	opt_s	{
29 	struct	opt_s	*o_next;
30 	int		o_line;
31 	int		o_type;
32 	int		o_num;
33 	char		*o_str;
34 	struct in_addr	o_ip;
35 	int		o_logfac;
36 	int		o_logpri;
37 } opt_t;
38 
39 static	void	build_action(opt_t *, ipmon_doing_t *);
40 static	opt_t	*new_opt(int);
41 static	void	free_action(ipmon_action_t *);
42 static	void	print_action(ipmon_action_t *);
43 static	int	find_doing(char *);
44 static	ipmon_doing_t *build_doing(char *, char *);
45 static	void	print_match(ipmon_action_t *);
46 static	int	install_saver(char *, char *);
47 
48 static	ipmon_action_t	*alist = NULL;
49 
50 ipmon_saver_int_t	*saverlist = NULL;
51 %}
52 
53 %union	{
54 	char	*str;
55 	u_32_t	num;
56 	struct in_addr	addr;
57 	struct opt_s	*opt;
58 	union	i6addr	ip6;
59 	struct ipmon_doing_s	*ipmd;
60 }
61 
62 %token	<num>	YY_NUMBER YY_HEX
63 %token	<str>	YY_STR
64 %token	<ip6>	YY_IPV6
65 %token	YY_COMMENT
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
68 
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
75 %type	<addr> ipv4
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
79 %type	<num> typeopt
80 %type	<ipmd> doopt doing
81 
82 %%
83 file:	action
84 	| file action
85 	;
86 
87 action:	line ';'
88 	| assign ';'
89 	| IPM_COMMENT
90 	| YY_COMMENT
91 	;
92 
93 line:	IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}'
94 						{ build_action($3, $8);
95 						  resetlexer();
96 						}
97 	| IPM_LOADACTION YY_STR YY_STR 	{ if (install_saver($2, $3))
98 						yyerror("install saver");
99 					}
100 	;
101 
102 assign:	YY_STR assigning YY_STR 		{ set_variable($1, $3);
103 						  resetlexer();
104 						  free($1);
105 						  free($3);
106 						  yyvarnext = 0;
107 						}
108 	;
109 
110 assigning:
111 	'='					{ yyvarnext = 1; }
112 	;
113 
114 matching:
115 	matchopt				{ $$ = $1; }
116 	| matchopt ',' matching			{ $1->o_next = $3; $$ = $1; }
117 	;
118 
119 matchopt:
120 	direction				{ $$ = $1; }
121 	| dstip					{ $$ = $1; }
122 	| dstport				{ $$ = $1; }
123 	| every					{ $$ = $1; }
124 	| group					{ $$ = $1; }
125 	| interface				{ $$ = $1; }
126 	| protocol				{ $$ = $1; }
127 	| result				{ $$ = $1; }
128 	| rule					{ $$ = $1; }
129 	| srcip					{ $$ = $1; }
130 	| srcport				{ $$ = $1; }
131 	| logtag				{ $$ = $1; }
132 	| nattag				{ $$ = $1; }
133 	| type					{ $$ = $1; }
134 	;
135 
136 doing:
137 	doopt					{ $$ = $1; }
138 	| doopt ',' doing			{ $1->ipmd_next = $3; $$ = $1; }
139 	;
140 
141 doopt:
142 	YY_STR				{ if (find_doing($1) != IPM_DOING)
143 						yyerror("unknown action");
144 					}
145 	'(' YY_STR ')'			{ $$ = build_doing($1, $4);
146 					  if ($$ == NULL)
147 						yyerror("action building");
148 					}
149 	| YY_STR			{ if (find_doing($1) == IPM_DOING)
150 						$$ = build_doing($1, NULL);
151 					}
152 	;
153 
154 direction:
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; }
159 	;
160 
161 dstip:	IPM_DSTIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_DSTIP);
162 						  $$->o_ip = $3;
163 						  $$->o_num = $5; }
164 	;
165 
166 dstport:
167 	IPM_DSTPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_DSTPORT);
168 						  $$->o_num = $3; }
169 	| IPM_DSTPORT '=' YY_STR		{ $$ = new_opt(IPM_DSTPORT);
170 						  $$->o_str = $3; }
171 	;
172 
173 every:	IPM_EVERY IPM_SECOND			{ $$ = new_opt(IPM_SECOND);
174 						  $$->o_num = 1; }
175 	| IPM_EVERY YY_NUMBER IPM_SECONDS	{ $$ = new_opt(IPM_SECOND);
176 						  $$->o_num = $2; }
177 	| IPM_EVERY IPM_PACKET			{ $$ = new_opt(IPM_PACKET);
178 						  $$->o_num = 1; }
179 	| IPM_EVERY YY_NUMBER IPM_PACKETS	{ $$ = new_opt(IPM_PACKET);
180 						  $$->o_num = $2; }
181 	;
182 
183 group:	IPM_GROUP '=' YY_NUMBER			{ $$ = new_opt(IPM_GROUP);
184 						  $$->o_num = $3; }
185 	| IPM_GROUP '=' YY_STR			{ $$ = new_opt(IPM_GROUP);
186 						  $$->o_str = $3; }
187 	;
188 
189 interface:
190 	IPM_INTERFACE '=' YY_STR		{ $$ = new_opt(IPM_INTERFACE);
191 						  $$->o_str = $3; }
192 	;
193 
194 logtag:	IPM_LOGTAG '=' YY_NUMBER		{ $$ = new_opt(IPM_LOGTAG);
195 						  $$->o_num = $3; }
196 	;
197 
198 nattag:	IPM_NATTAG '=' YY_STR			{ $$ = new_opt(IPM_NATTAG);
199 						  $$->o_str = $3; }
200 	;
201 
202 protocol:
203 	IPM_PROTOCOL '=' YY_NUMBER		{ $$ = new_opt(IPM_PROTOCOL);
204 						  $$->o_num = $3; }
205 	| IPM_PROTOCOL '=' YY_STR		{ $$ = new_opt(IPM_PROTOCOL);
206 						  $$->o_num = getproto($3);
207 						  free($3);
208 						}
209 	;
210 
211 result:	IPM_RESULT '=' YY_STR			{ $$ = new_opt(IPM_RESULT);
212 						  $$->o_str = $3; }
213 	;
214 
215 rule:	IPM_RULE '=' YY_NUMBER			{ $$ = new_opt(IPM_RULE);
216 						  $$->o_num = YY_NUMBER; }
217 	;
218 
219 srcip:	IPM_SRCIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_SRCIP);
220 						  $$->o_ip = $3;
221 						  $$->o_num = $5; }
222 	;
223 
224 srcport:
225 	IPM_SRCPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_SRCPORT);
226 						  $$->o_num = $3; }
227 	| IPM_SRCPORT '=' YY_STR		{ $$ = new_opt(IPM_SRCPORT);
228 						  $$->o_str = $3; }
229 	;
230 
231 type:	IPM_TYPE '=' typeopt			{ $$ = new_opt(IPM_TYPE);
232 						  $$->o_num = $3; }
233 	;
234 
235 typeopt:
236 	IPM_IPF					{ $$ = IPL_MAGIC; }
237 	| IPM_NAT				{ $$ = IPL_MAGIC_NAT; }
238 	| IPM_STATE				{ $$ = IPL_MAGIC_STATE; }
239 	;
240 
241 
242 
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");
246 			return(0);
247 		  }
248 		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
249 		  $$.s_addr = htonl($$.s_addr);
250 		}
251 %%
252 static	struct	wordtab	yywords[] = {
253 	{ "body",	IPM_BODY },
254 	{ "direction",	IPM_DIRECTION },
255 	{ "do",		IPM_DO },
256 	{ "dstip",	IPM_DSTIP },
257 	{ "dstport",	IPM_DSTPORT },
258 	{ "every",	IPM_EVERY },
259 	{ "group",	IPM_GROUP },
260 	{ "in",		IPM_IN },
261 	{ "interface",	IPM_INTERFACE },
262 	{ "ipf",	IPM_IPF },
263 	{ "load_action",IPM_LOADACTION },
264 	{ "logtag",	IPM_LOGTAG },
265 	{ "match",	IPM_MATCH },
266 	{ "nat",	IPM_NAT },
267 	{ "nattag",	IPM_NATTAG },
268 	{ "no",		IPM_NO },
269 	{ "out",	IPM_OUT },
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 },
281 	{ NULL,		0 }
282 };
283 
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 	},
301 	{ 0, 0 }
302 };
303 
304 static opt_t *
305 new_opt(int type)
306 {
307 	opt_t *o;
308 
309 	o = (opt_t *)calloc(1, sizeof(*o));
310 	o->o_type = type;
311 	o->o_line = yylineNum;
312 	o->o_logfac = -1;
313 	o->o_logpri = -1;
314 	return(o);
315 }
316 
317 static void
318 build_action(opt_t *olist, ipmon_doing_t *todo)
319 {
320 	ipmon_action_t *a;
321 	opt_t *o;
322 	int i;
323 
324 	a = (ipmon_action_t *)calloc(1, sizeof(*a));
325 	if (a == NULL)
326 		return;
327 
328 	while ((o = olist) != NULL) {
329 		/*
330 		 * Check to see if the same comparator is being used more than
331 		 * once per matching statement.
332 		 */
333 		for (i = 0; macflags[i][0]; i++)
334 			if (macflags[i][0] == o->o_type)
335 				break;
336 		if (macflags[i][1] & a->ac_mflag) {
337 			fprintf(stderr, "%s redfined on line %d\n",
338 				yykeytostr(o->o_type), yylineNum);
339 			if (o->o_str != NULL)
340 				free(o->o_str);
341 			olist = o->o_next;
342 			free(o);
343 			continue;
344 		}
345 
346 		a->ac_mflag |= macflags[i][1];
347 
348 		switch (o->o_type)
349 		{
350 		case IPM_DIRECTION :
351 			a->ac_direction = o->o_num;
352 			break;
353 		case IPM_DSTIP :
354 			a->ac_dip = o->o_ip.s_addr;
355 			a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
356 			break;
357 		case IPM_DSTPORT :
358 			a->ac_dport = htons(o->o_num);
359 			break;
360 		case IPM_INTERFACE :
361 			a->ac_iface = o->o_str;
362 			o->o_str = NULL;
363 			break;
364 		case IPM_GROUP :
365 			if (o->o_str != NULL)
366 				strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
367 			else
368 				sprintf(a->ac_group, "%d", o->o_num);
369 			break;
370 		case IPM_LOGTAG :
371 			a->ac_logtag = o->o_num;
372 			break;
373 		case IPM_NATTAG :
374 			strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
375 			break;
376 		case IPM_PACKET :
377 			a->ac_packet = o->o_num;
378 			break;
379 		case IPM_PROTOCOL :
380 			a->ac_proto = o->o_num;
381 			break;
382 		case IPM_RULE :
383 			a->ac_rule = o->o_num;
384 			break;
385 		case IPM_RESULT :
386 			if (!strcasecmp(o->o_str, "pass"))
387 				a->ac_result = IPMR_PASS;
388 			else if (!strcasecmp(o->o_str, "block"))
389 				a->ac_result = IPMR_BLOCK;
390 			else if (!strcasecmp(o->o_str, "nomatch"))
391 				a->ac_result = IPMR_NOMATCH;
392 			else if (!strcasecmp(o->o_str, "log"))
393 				a->ac_result = IPMR_LOG;
394 			break;
395 		case IPM_SECOND :
396 			a->ac_second = o->o_num;
397 			break;
398 		case IPM_SRCIP :
399 			a->ac_sip = o->o_ip.s_addr;
400 			a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
401 			break;
402 		case IPM_SRCPORT :
403 			a->ac_sport = htons(o->o_num);
404 			break;
405 		case IPM_TYPE :
406 			a->ac_type = o->o_num;
407 			break;
408 		case IPM_WITH :
409 			break;
410 		default :
411 			break;
412 		}
413 
414 		olist = o->o_next;
415 		if (o->o_str != NULL)
416 			free(o->o_str);
417 		free(o);
418 	}
419 
420 	a->ac_doing = todo;
421 	a->ac_next = alist;
422 	alist = a;
423 
424 	if (ipmonopts & IPMON_VERBOSE)
425 		print_action(a);
426 }
427 
428 
429 int
430 check_action(char *buf, char *log, int opts, int lvl)
431 {
432 	ipmon_action_t *a;
433 	struct timeval tv;
434 	ipmon_doing_t *d;
435 	ipmon_msg_t msg;
436 	ipflog_t *ipf;
437 	tcphdr_t *tcp;
438 	iplog_t *ipl;
439 	int matched;
440 	u_long t1;
441 	ip_t *ip;
442 
443 	matched = 0;
444 	ipl = (iplog_t *)buf;
445 	ipf = (ipflog_t *)(ipl +1);
446 	ip = (ip_t *)(ipf + 1);
447 	tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
448 
449 	msg.imm_data = ipl;
450 	msg.imm_dsize = ipl->ipl_dsize;
451 	msg.imm_when = ipl->ipl_time.tv_sec;
452 	msg.imm_msg = log;
453 	msg.imm_msglen = strlen(log);
454 	msg.imm_loglevel = lvl;
455 
456 	for (a = alist; a != NULL; a = a->ac_next) {
457 		verbose(0, "== checking config rule\n");
458 		if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
459 			if (a->ac_direction == IPM_IN) {
460 				if ((ipf->fl_flags & FR_INQUE) == 0) {
461 					verbose(8, "-- direction not in\n");
462 					continue;
463 				}
464 			} else if (a->ac_direction == IPM_OUT) {
465 				if ((ipf->fl_flags & FR_OUTQUE) == 0) {
466 					verbose(8, "-- direction not out\n");
467 					continue;
468 				}
469 			}
470 		}
471 
472 		if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) {
473 			verbose(8, "-- type mismatch\n");
474 			continue;
475 		}
476 
477 		if ((a->ac_mflag & IPMAC_EVERY) != 0) {
478 			gettimeofday(&tv, NULL);
479 			t1 = tv.tv_sec - a->ac_lastsec;
480 			if (tv.tv_usec <= a->ac_lastusec)
481 				t1--;
482 			if (a->ac_second != 0) {
483 				if (t1 < a->ac_second) {
484 					verbose(8, "-- too soon\n");
485 					continue;
486 				}
487 				a->ac_lastsec = tv.tv_sec;
488 				a->ac_lastusec = tv.tv_usec;
489 			}
490 
491 			if (a->ac_packet != 0) {
492 				if (a->ac_pktcnt == 0)
493 					a->ac_pktcnt++;
494 				else if (a->ac_pktcnt == a->ac_packet) {
495 					a->ac_pktcnt = 0;
496 					verbose(8, "-- packet count\n");
497 					continue;
498 				} else {
499 					a->ac_pktcnt++;
500 					verbose(8, "-- packet count\n");
501 					continue;
502 				}
503 			}
504 		}
505 
506 		if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
507 			if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) {
508 				verbose(8, "-- dstip wrong\n");
509 				continue;
510 			}
511 		}
512 
513 		if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
514 			if (ip->ip_p != IPPROTO_UDP &&
515 			    ip->ip_p != IPPROTO_TCP) {
516 				verbose(8, "-- not port protocol\n");
517 				continue;
518 			}
519 			if (tcp->th_dport != a->ac_dport) {
520 				verbose(8, "-- dport mismatch\n");
521 				continue;
522 			}
523 		}
524 
525 		if ((a->ac_mflag & IPMAC_GROUP) != 0) {
526 			if (strncmp(a->ac_group, ipf->fl_group,
527 				    FR_GROUPLEN) != 0) {
528 				verbose(8, "-- group mismatch\n");
529 				continue;
530 			}
531 		}
532 
533 		if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
534 			if (strcmp(a->ac_iface, ipf->fl_ifname)) {
535 				verbose(8, "-- ifname mismatch\n");
536 				continue;
537 			}
538 		}
539 
540 		if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
541 			if (a->ac_proto != ip->ip_p) {
542 				verbose(8, "-- protocol mismatch\n");
543 				continue;
544 			}
545 		}
546 
547 		if ((a->ac_mflag & IPMAC_RESULT) != 0) {
548 			if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
549 				if (a->ac_result != IPMR_NOMATCH) {
550 					verbose(8, "-- ff-flags mismatch\n");
551 					continue;
552 				}
553 			} else if (FR_ISPASS(ipf->fl_flags)) {
554 				if (a->ac_result != IPMR_PASS) {
555 					verbose(8, "-- pass mismatch\n");
556 					continue;
557 				}
558 			} else if (FR_ISBLOCK(ipf->fl_flags)) {
559 				if (a->ac_result != IPMR_BLOCK) {
560 					verbose(8, "-- block mismatch\n");
561 					continue;
562 				}
563 			} else {	/* Log only */
564 				if (a->ac_result != IPMR_LOG) {
565 					verbose(8, "-- log mismatch\n");
566 					continue;
567 				}
568 			}
569 		}
570 
571 		if ((a->ac_mflag & IPMAC_RULE) != 0) {
572 			if (a->ac_rule != ipf->fl_rule) {
573 				verbose(8, "-- rule mismatch\n");
574 				continue;
575 			}
576 		}
577 
578 		if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
579 			if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) {
580 				verbose(8, "-- srcip mismatch\n");
581 				continue;
582 			}
583 		}
584 
585 		if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
586 			if (ip->ip_p != IPPROTO_UDP &&
587 			    ip->ip_p != IPPROTO_TCP) {
588 				verbose(8, "-- port protocol mismatch\n");
589 				continue;
590 			}
591 			if (tcp->th_sport != a->ac_sport) {
592 				verbose(8, "-- sport mismatch\n");
593 				continue;
594 			}
595 		}
596 
597 		if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
598 			if (a->ac_logtag != ipf->fl_logtag) {
599 				verbose(8, "-- logtag %d != %d\n",
600 					a->ac_logtag, ipf->fl_logtag);
601 				continue;
602 			}
603 		}
604 
605 		if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
606 			if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
607 				    IPFTAG_LEN) != 0) {
608 				verbose(8, "-- nattag mismatch\n");
609 				continue;
610 			}
611 		}
612 
613 		matched = 1;
614 		verbose(8, "++ matched\n");
615 
616 		/*
617 		 * It matched so now perform the saves
618 		 */
619 		for (d = a->ac_doing; d != NULL; d = d->ipmd_next)
620 			(*d->ipmd_store)(d->ipmd_token, &msg);
621 	}
622 
623 	return(matched);
624 }
625 
626 
627 static void
628 free_action(ipmon_action_t *a)
629 {
630 	ipmon_doing_t *d;
631 
632 	while ((d = a->ac_doing) != NULL) {
633 		a->ac_doing = d->ipmd_next;
634 		(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
635 		free(d);
636 	}
637 
638 	if (a->ac_iface != NULL) {
639 		free(a->ac_iface);
640 		a->ac_iface = NULL;
641 	}
642 	a->ac_next = NULL;
643 	free(a);
644 }
645 
646 
647 int
648 load_config(char *file)
649 {
650 	FILE *fp;
651 	char *s;
652 
653 	unload_config();
654 
655 	s = getenv("YYDEBUG");
656 	if (s != NULL)
657 		yydebug = atoi(s);
658 	else
659 		yydebug = 0;
660 
661 	yylineNum = 1;
662 
663 	(void) yysettab(yywords);
664 
665 	fp = fopen(file, "r");
666 	if (!fp) {
667 		perror("load_config:fopen:");
668 		return(-1);
669 	}
670 	yyin = fp;
671 	while (!feof(fp))
672 		yyparse();
673 	fclose(fp);
674 	return(0);
675 }
676 
677 
678 void
679 unload_config(void)
680 {
681 	ipmon_saver_int_t *sav, **imsip;
682 	ipmon_saver_t *is;
683 	ipmon_action_t *a;
684 
685 	while ((a = alist) != NULL) {
686 		alist = a->ac_next;
687 		free_action(a);
688 	}
689 
690 	/*
691 	 * Look for savers that have been added in dynamically from the
692 	 * configuration file.
693 	 */
694 	for (imsip = &saverlist; (sav = *imsip) != NULL; ) {
695 		if (sav->imsi_handle == NULL)
696 			imsip = &sav->imsi_next;
697 		else {
698 			dlclose(sav->imsi_handle);
699 
700 			*imsip = sav->imsi_next;
701 			is = sav->imsi_stor;
702 			free(sav);
703 
704 			free(is->ims_name);
705 			free(is);
706 		}
707 	}
708 }
709 
710 
711 void
712 dump_config(void)
713 {
714 	ipmon_action_t *a;
715 
716 	for (a = alist; a != NULL; a = a->ac_next) {
717 		print_action(a);
718 
719 		printf("#\n");
720 	}
721 }
722 
723 
724 static void
725 print_action(ipmon_action_t *a)
726 {
727 	ipmon_doing_t *d;
728 
729 	printf("match { ");
730 	print_match(a);
731 	printf("; }\n");
732 	printf("do {");
733 	for (d = a->ac_doing; d != NULL; d = d->ipmd_next) {
734 		printf("%s", d->ipmd_saver->ims_name);
735 		if (d->ipmd_saver->ims_print != NULL) {
736 			printf("(\"");
737 			(*d->ipmd_saver->ims_print)(d->ipmd_token);
738 			printf("\")");
739 		}
740 		printf(";");
741 	}
742 	printf("};\n");
743 }
744 
745 
746 void *
747 add_doing(ipmon_saver_t *saver)
748 {
749 	ipmon_saver_int_t *it;
750 
751 	if (find_doing(saver->ims_name) == IPM_DOING)
752 		return(NULL);
753 
754 	it = calloc(1, sizeof(*it));
755 	if (it == NULL)
756 		return(NULL);
757 	it->imsi_stor = saver;
758 	it->imsi_next = saverlist;
759 	saverlist = it;
760 	return(it);
761 }
762 
763 
764 static int
765 find_doing(char *string)
766 {
767 	ipmon_saver_int_t *it;
768 
769 	for (it = saverlist; it != NULL; it = it->imsi_next) {
770 		if (!strcmp(it->imsi_stor->ims_name, string))
771 			return(IPM_DOING);
772 	}
773 	return(0);
774 }
775 
776 
777 static ipmon_doing_t *
778 build_doing(char *target, char *options)
779 {
780 	ipmon_saver_int_t *it;
781 	char *strarray[2];
782 	ipmon_doing_t *d, *d1;
783 	ipmon_action_t *a;
784 	ipmon_saver_t *save;
785 
786 	d = calloc(1, sizeof(*d));
787 	if (d == NULL)
788 		return(NULL);
789 
790 	for (it = saverlist; it != NULL; it = it->imsi_next) {
791 		if (!strcmp(it->imsi_stor->ims_name, target))
792 			break;
793 	}
794 	if (it == NULL) {
795 		free(d);
796 		return(NULL);
797 	}
798 
799 	strarray[0] = options;
800 	strarray[1] = NULL;
801 
802 	d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray);
803 	if (d->ipmd_token == NULL) {
804 		free(d);
805 		return(NULL);
806 	}
807 
808 	save = it->imsi_stor;
809 	d->ipmd_saver = save;
810 	d->ipmd_store = it->imsi_stor->ims_store;
811 
812 	/*
813 	 * Look for duplicate do-things that need to be dup'd
814 	 */
815 	for (a = alist; a != NULL; a = a->ac_next) {
816 		for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) {
817 			if (save != d1->ipmd_saver)
818 				continue;
819 			if (save->ims_match == NULL || save->ims_dup == NULL)
820 				continue;
821 			if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token))
822 				continue;
823 
824 			(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
825 			d->ipmd_token = (*save->ims_dup)(d1->ipmd_token);
826 			break;
827 		}
828 	}
829 
830 	return(d);
831 }
832 
833 
834 static void
835 print_match(ipmon_action_t *a)
836 {
837 	char *coma = "";
838 
839 	if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
840 		printf("direction = ");
841 		if (a->ac_direction == IPM_IN)
842 			printf("in");
843 		else if (a->ac_direction == IPM_OUT)
844 			printf("out");
845 		coma = ", ";
846 	}
847 
848 	if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
849 		printf("%sdstip = ", coma);
850 		printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk);
851 		coma = ", ";
852 	}
853 
854 	if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
855 		printf("%sdstport = %hu", coma, ntohs(a->ac_dport));
856 		coma = ", ";
857 	}
858 
859 	if ((a->ac_mflag & IPMAC_GROUP) != 0) {
860 		char group[FR_GROUPLEN+1];
861 
862 		strncpy(group, a->ac_group, FR_GROUPLEN);
863 		group[FR_GROUPLEN] = '\0';
864 		printf("%sgroup = %s", coma, group);
865 		coma = ", ";
866 	}
867 
868 	if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
869 		printf("%siface = %s", coma, a->ac_iface);
870 		coma = ", ";
871 	}
872 
873 	if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
874 		printf("%slogtag = %u", coma, a->ac_logtag);
875 		coma = ", ";
876 	}
877 
878 	if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
879 		char tag[17];
880 
881 		strncpy(tag, a->ac_nattag, 16);
882 		tag[16] = '\0';
883 		printf("%snattag = %s", coma, tag);
884 		coma = ", ";
885 	}
886 
887 	if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
888 		printf("%sprotocol = %u", coma, a->ac_proto);
889 		coma = ", ";
890 	}
891 
892 	if ((a->ac_mflag & IPMAC_RESULT) != 0) {
893 		printf("%sresult = ", coma);
894 		switch (a->ac_result)
895 		{
896 		case IPMR_LOG :
897 			printf("log");
898 			break;
899 		case IPMR_PASS :
900 			printf("pass");
901 			break;
902 		case IPMR_BLOCK :
903 			printf("block");
904 			break;
905 		case IPMR_NOMATCH :
906 			printf("nomatch");
907 			break;
908 		}
909 		coma = ", ";
910 	}
911 
912 	if ((a->ac_mflag & IPMAC_RULE) != 0) {
913 		printf("%srule = %u", coma, a->ac_rule);
914 		coma = ", ";
915 	}
916 
917 	if ((a->ac_mflag & IPMAC_EVERY) != 0) {
918 		if (a->ac_packet > 1) {
919 			printf("%severy %d packets", coma, a->ac_packet);
920 			coma = ", ";
921 		} else if (a->ac_packet == 1) {
922 			printf("%severy packet", coma);
923 			coma = ", ";
924 		}
925 		if (a->ac_second > 1) {
926 			printf("%severy %d seconds", coma, a->ac_second);
927 			coma = ", ";
928 		} else if (a->ac_second == 1) {
929 			printf("%severy second", coma);
930 			coma = ", ";
931 		}
932 	}
933 
934 	if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
935 		printf("%ssrcip = ", coma);
936 		printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk);
937 		coma = ", ";
938 	}
939 
940 	if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
941 		printf("%ssrcport = %hu", coma, ntohs(a->ac_sport));
942 		coma = ", ";
943 	}
944 
945 	if ((a->ac_mflag & IPMAC_TYPE) != 0) {
946 		printf("%stype = ", coma);
947 		switch (a->ac_type)
948 		{
949 		case IPL_LOGIPF :
950 			printf("ipf");
951 			break;
952 		case IPL_LOGSTATE :
953 			printf("state");
954 			break;
955 		case IPL_LOGNAT :
956 			printf("nat");
957 			break;
958 		}
959 		coma = ", ";
960 	}
961 
962 	if ((a->ac_mflag & IPMAC_WITH) != 0) {
963 		printf("%swith ", coma);
964 		coma = ", ";
965 	}
966 }
967 
968 
969 static int
970 install_saver(char *name, char *path)
971 {
972 	ipmon_saver_int_t *isi;
973 	ipmon_saver_t *is;
974 	char nbuf[80];
975 
976 	if (find_doing(name) == IPM_DOING)
977 		return(-1);
978 
979 	isi = calloc(1, sizeof(*isi));
980 	if (isi == NULL)
981 		return(-1);
982 
983 	is = calloc(1, sizeof(*is));
984 	if (is == NULL)
985 		goto loaderror;
986 
987 	is->ims_name = name;
988 
989 #ifdef RTLD_LAZY
990 	isi->imsi_handle = dlopen(path, RTLD_LAZY);
991 #endif
992 #ifdef DL_LAZY
993 	isi->imsi_handle = dlopen(path, DL_LAZY);
994 #endif
995 
996 	if (isi->imsi_handle == NULL)
997 		goto loaderror;
998 
999 	snprintf(nbuf, sizeof(nbuf), "%sdup", name);
1000 	is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf);
1001 
1002 	snprintf(nbuf, sizeof(nbuf), "%sdestroy", name);
1003 	is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf);
1004 	if (is->ims_destroy == NULL)
1005 		goto loaderror;
1006 
1007 	snprintf(nbuf, sizeof(nbuf), "%smatch", name);
1008 	is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf);
1009 
1010 	snprintf(nbuf, sizeof(nbuf), "%sparse", name);
1011 	is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf);
1012 	if (is->ims_parse == NULL)
1013 		goto loaderror;
1014 
1015 	snprintf(nbuf, sizeof(nbuf), "%sprint", name);
1016 	is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf);
1017 	if (is->ims_print == NULL)
1018 		goto loaderror;
1019 
1020 	snprintf(nbuf, sizeof(nbuf), "%sstore", name);
1021 	is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf);
1022 	if (is->ims_store == NULL)
1023 		goto loaderror;
1024 
1025 	isi->imsi_stor = is;
1026 	isi->imsi_next = saverlist;
1027 	saverlist = isi;
1028 
1029 	return(0);
1030 
1031 loaderror:
1032 	if (isi->imsi_handle != NULL)
1033 		dlclose(isi->imsi_handle);
1034 	free(isi);
1035 	if (is != NULL)
1036 		free(is);
1037 	return(-1);
1038 }
1039