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