xref: /freebsd/sbin/ipf/ipmon/ipmon_y.y (revision 963f5dc7a30624e95d72fb7f87b8892651164e46)
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(type)
306 	int type;
307 {
308 	opt_t *o;
309 
310 	o = (opt_t *)calloc(1, sizeof(*o));
311 	o->o_type = type;
312 	o->o_line = yylineNum;
313 	o->o_logfac = -1;
314 	o->o_logpri = -1;
315 	return o;
316 }
317 
318 static void
319 build_action(olist, todo)
320 	opt_t *olist;
321 	ipmon_doing_t *todo;
322 {
323 	ipmon_action_t *a;
324 	opt_t *o;
325 	int i;
326 
327 	a = (ipmon_action_t *)calloc(1, sizeof(*a));
328 	if (a == NULL)
329 		return;
330 
331 	while ((o = olist) != NULL) {
332 		/*
333 		 * Check to see if the same comparator is being used more than
334 		 * once per matching statement.
335 		 */
336 		for (i = 0; macflags[i][0]; i++)
337 			if (macflags[i][0] == o->o_type)
338 				break;
339 		if (macflags[i][1] & a->ac_mflag) {
340 			fprintf(stderr, "%s redfined on line %d\n",
341 				yykeytostr(o->o_type), yylineNum);
342 			if (o->o_str != NULL)
343 				free(o->o_str);
344 			olist = o->o_next;
345 			free(o);
346 			continue;
347 		}
348 
349 		a->ac_mflag |= macflags[i][1];
350 
351 		switch (o->o_type)
352 		{
353 		case IPM_DIRECTION :
354 			a->ac_direction = o->o_num;
355 			break;
356 		case IPM_DSTIP :
357 			a->ac_dip = o->o_ip.s_addr;
358 			a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
359 			break;
360 		case IPM_DSTPORT :
361 			a->ac_dport = htons(o->o_num);
362 			break;
363 		case IPM_INTERFACE :
364 			a->ac_iface = o->o_str;
365 			o->o_str = NULL;
366 			break;
367 		case IPM_GROUP :
368 			if (o->o_str != NULL)
369 				strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
370 			else
371 				sprintf(a->ac_group, "%d", o->o_num);
372 			break;
373 		case IPM_LOGTAG :
374 			a->ac_logtag = o->o_num;
375 			break;
376 		case IPM_NATTAG :
377 			strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
378 			break;
379 		case IPM_PACKET :
380 			a->ac_packet = o->o_num;
381 			break;
382 		case IPM_PROTOCOL :
383 			a->ac_proto = o->o_num;
384 			break;
385 		case IPM_RULE :
386 			a->ac_rule = o->o_num;
387 			break;
388 		case IPM_RESULT :
389 			if (!strcasecmp(o->o_str, "pass"))
390 				a->ac_result = IPMR_PASS;
391 			else if (!strcasecmp(o->o_str, "block"))
392 				a->ac_result = IPMR_BLOCK;
393 			else if (!strcasecmp(o->o_str, "nomatch"))
394 				a->ac_result = IPMR_NOMATCH;
395 			else if (!strcasecmp(o->o_str, "log"))
396 				a->ac_result = IPMR_LOG;
397 			break;
398 		case IPM_SECOND :
399 			a->ac_second = o->o_num;
400 			break;
401 		case IPM_SRCIP :
402 			a->ac_sip = o->o_ip.s_addr;
403 			a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
404 			break;
405 		case IPM_SRCPORT :
406 			a->ac_sport = htons(o->o_num);
407 			break;
408 		case IPM_TYPE :
409 			a->ac_type = o->o_num;
410 			break;
411 		case IPM_WITH :
412 			break;
413 		default :
414 			break;
415 		}
416 
417 		olist = o->o_next;
418 		if (o->o_str != NULL)
419 			free(o->o_str);
420 		free(o);
421 	}
422 
423 	a->ac_doing = todo;
424 	a->ac_next = alist;
425 	alist = a;
426 
427 	if (ipmonopts & IPMON_VERBOSE)
428 		print_action(a);
429 }
430 
431 
432 int
433 check_action(buf, log, opts, lvl)
434 	char *buf, *log;
435 	int opts, lvl;
436 {
437 	ipmon_action_t *a;
438 	struct timeval tv;
439 	ipmon_doing_t *d;
440 	ipmon_msg_t msg;
441 	ipflog_t *ipf;
442 	tcphdr_t *tcp;
443 	iplog_t *ipl;
444 	int matched;
445 	u_long t1;
446 	ip_t *ip;
447 
448 	matched = 0;
449 	ipl = (iplog_t *)buf;
450 	ipf = (ipflog_t *)(ipl +1);
451 	ip = (ip_t *)(ipf + 1);
452 	tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
453 
454 	msg.imm_data = ipl;
455 	msg.imm_dsize = ipl->ipl_dsize;
456 	msg.imm_when = ipl->ipl_time.tv_sec;
457 	msg.imm_msg = log;
458 	msg.imm_msglen = strlen(log);
459 	msg.imm_loglevel = lvl;
460 
461 	for (a = alist; a != NULL; a = a->ac_next) {
462 		verbose(0, "== checking config rule\n");
463 		if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
464 			if (a->ac_direction == IPM_IN) {
465 				if ((ipf->fl_flags & FR_INQUE) == 0) {
466 					verbose(8, "-- direction not in\n");
467 					continue;
468 				}
469 			} else if (a->ac_direction == IPM_OUT) {
470 				if ((ipf->fl_flags & FR_OUTQUE) == 0) {
471 					verbose(8, "-- direction not out\n");
472 					continue;
473 				}
474 			}
475 		}
476 
477 		if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) {
478 			verbose(8, "-- type mismatch\n");
479 			continue;
480 		}
481 
482 		if ((a->ac_mflag & IPMAC_EVERY) != 0) {
483 			gettimeofday(&tv, NULL);
484 			t1 = tv.tv_sec - a->ac_lastsec;
485 			if (tv.tv_usec <= a->ac_lastusec)
486 				t1--;
487 			if (a->ac_second != 0) {
488 				if (t1 < a->ac_second) {
489 					verbose(8, "-- too soon\n");
490 					continue;
491 				}
492 				a->ac_lastsec = tv.tv_sec;
493 				a->ac_lastusec = tv.tv_usec;
494 			}
495 
496 			if (a->ac_packet != 0) {
497 				if (a->ac_pktcnt == 0)
498 					a->ac_pktcnt++;
499 				else if (a->ac_pktcnt == a->ac_packet) {
500 					a->ac_pktcnt = 0;
501 					verbose(8, "-- packet count\n");
502 					continue;
503 				} else {
504 					a->ac_pktcnt++;
505 					verbose(8, "-- packet count\n");
506 					continue;
507 				}
508 			}
509 		}
510 
511 		if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
512 			if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) {
513 				verbose(8, "-- dstip wrong\n");
514 				continue;
515 			}
516 		}
517 
518 		if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
519 			if (ip->ip_p != IPPROTO_UDP &&
520 			    ip->ip_p != IPPROTO_TCP) {
521 				verbose(8, "-- not port protocol\n");
522 				continue;
523 			}
524 			if (tcp->th_dport != a->ac_dport) {
525 				verbose(8, "-- dport mismatch\n");
526 				continue;
527 			}
528 		}
529 
530 		if ((a->ac_mflag & IPMAC_GROUP) != 0) {
531 			if (strncmp(a->ac_group, ipf->fl_group,
532 				    FR_GROUPLEN) != 0) {
533 				verbose(8, "-- group mismatch\n");
534 				continue;
535 			}
536 		}
537 
538 		if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
539 			if (strcmp(a->ac_iface, ipf->fl_ifname)) {
540 				verbose(8, "-- ifname mismatch\n");
541 				continue;
542 			}
543 		}
544 
545 		if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
546 			if (a->ac_proto != ip->ip_p) {
547 				verbose(8, "-- protocol mismatch\n");
548 				continue;
549 			}
550 		}
551 
552 		if ((a->ac_mflag & IPMAC_RESULT) != 0) {
553 			if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
554 				if (a->ac_result != IPMR_NOMATCH) {
555 					verbose(8, "-- ff-flags mismatch\n");
556 					continue;
557 				}
558 			} else if (FR_ISPASS(ipf->fl_flags)) {
559 				if (a->ac_result != IPMR_PASS) {
560 					verbose(8, "-- pass mismatch\n");
561 					continue;
562 				}
563 			} else if (FR_ISBLOCK(ipf->fl_flags)) {
564 				if (a->ac_result != IPMR_BLOCK) {
565 					verbose(8, "-- block mismatch\n");
566 					continue;
567 				}
568 			} else {	/* Log only */
569 				if (a->ac_result != IPMR_LOG) {
570 					verbose(8, "-- log mismatch\n");
571 					continue;
572 				}
573 			}
574 		}
575 
576 		if ((a->ac_mflag & IPMAC_RULE) != 0) {
577 			if (a->ac_rule != ipf->fl_rule) {
578 				verbose(8, "-- rule mismatch\n");
579 				continue;
580 			}
581 		}
582 
583 		if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
584 			if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) {
585 				verbose(8, "-- srcip mismatch\n");
586 				continue;
587 			}
588 		}
589 
590 		if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
591 			if (ip->ip_p != IPPROTO_UDP &&
592 			    ip->ip_p != IPPROTO_TCP) {
593 				verbose(8, "-- port protocol mismatch\n");
594 				continue;
595 			}
596 			if (tcp->th_sport != a->ac_sport) {
597 				verbose(8, "-- sport mismatch\n");
598 				continue;
599 			}
600 		}
601 
602 		if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
603 			if (a->ac_logtag != ipf->fl_logtag) {
604 				verbose(8, "-- logtag %d != %d\n",
605 					a->ac_logtag, ipf->fl_logtag);
606 				continue;
607 			}
608 		}
609 
610 		if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
611 			if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
612 				    IPFTAG_LEN) != 0) {
613 				verbose(8, "-- nattag mismatch\n");
614 				continue;
615 			}
616 		}
617 
618 		matched = 1;
619 		verbose(8, "++ matched\n");
620 
621 		/*
622 		 * It matched so now perform the saves
623 		 */
624 		for (d = a->ac_doing; d != NULL; d = d->ipmd_next)
625 			(*d->ipmd_store)(d->ipmd_token, &msg);
626 	}
627 
628 	return matched;
629 }
630 
631 
632 static void
633 free_action(a)
634 	ipmon_action_t *a;
635 {
636 	ipmon_doing_t *d;
637 
638 	while ((d = a->ac_doing) != NULL) {
639 		a->ac_doing = d->ipmd_next;
640 		(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
641 		free(d);
642 	}
643 
644 	if (a->ac_iface != NULL) {
645 		free(a->ac_iface);
646 		a->ac_iface = NULL;
647 	}
648 	a->ac_next = NULL;
649 	free(a);
650 }
651 
652 
653 int
654 load_config(file)
655 	char *file;
656 {
657 	FILE *fp;
658 	char *s;
659 
660 	unload_config();
661 
662 	s = getenv("YYDEBUG");
663 	if (s != NULL)
664 		yydebug = atoi(s);
665 	else
666 		yydebug = 0;
667 
668 	yylineNum = 1;
669 
670 	(void) yysettab(yywords);
671 
672 	fp = fopen(file, "r");
673 	if (!fp) {
674 		perror("load_config:fopen:");
675 		return -1;
676 	}
677 	yyin = fp;
678 	while (!feof(fp))
679 		yyparse();
680 	fclose(fp);
681 	return 0;
682 }
683 
684 
685 void
686 unload_config()
687 {
688 	ipmon_saver_int_t *sav, **imsip;
689 	ipmon_saver_t *is;
690 	ipmon_action_t *a;
691 
692 	while ((a = alist) != NULL) {
693 		alist = a->ac_next;
694 		free_action(a);
695 	}
696 
697 	/*
698 	 * Look for savers that have been added in dynamically from the
699 	 * configuration file.
700 	 */
701 	for (imsip = &saverlist; (sav = *imsip) != NULL; ) {
702 		if (sav->imsi_handle == NULL)
703 			imsip = &sav->imsi_next;
704 		else {
705 			dlclose(sav->imsi_handle);
706 
707 			*imsip = sav->imsi_next;
708 			is = sav->imsi_stor;
709 			free(sav);
710 
711 			free(is->ims_name);
712 			free(is);
713 		}
714 	}
715 }
716 
717 
718 void
719 dump_config()
720 {
721 	ipmon_action_t *a;
722 
723 	for (a = alist; a != NULL; a = a->ac_next) {
724 		print_action(a);
725 
726 		printf("#\n");
727 	}
728 }
729 
730 
731 static void
732 print_action(a)
733 	ipmon_action_t *a;
734 {
735 	ipmon_doing_t *d;
736 
737 	printf("match { ");
738 	print_match(a);
739 	printf("; }\n");
740 	printf("do {");
741 	for (d = a->ac_doing; d != NULL; d = d->ipmd_next) {
742 		printf("%s", d->ipmd_saver->ims_name);
743 		if (d->ipmd_saver->ims_print != NULL) {
744 			printf("(\"");
745 			(*d->ipmd_saver->ims_print)(d->ipmd_token);
746 			printf("\")");
747 		}
748 		printf(";");
749 	}
750 	printf("};\n");
751 }
752 
753 
754 void *
755 add_doing(saver)
756 	ipmon_saver_t *saver;
757 {
758 	ipmon_saver_int_t *it;
759 
760 	if (find_doing(saver->ims_name) == IPM_DOING)
761 		return NULL;
762 
763 	it = calloc(1, sizeof(*it));
764 	if (it == NULL)
765 		return NULL;
766 	it->imsi_stor = saver;
767 	it->imsi_next = saverlist;
768 	saverlist = it;
769 	return it;
770 }
771 
772 
773 static int
774 find_doing(string)
775 	char *string;
776 {
777 	ipmon_saver_int_t *it;
778 
779 	for (it = saverlist; it != NULL; it = it->imsi_next) {
780 		if (!strcmp(it->imsi_stor->ims_name, string))
781 			return IPM_DOING;
782 	}
783 	return 0;
784 }
785 
786 
787 static ipmon_doing_t *
788 build_doing(target, options)
789 	char *target;
790 	char *options;
791 {
792 	ipmon_saver_int_t *it;
793 	char *strarray[2];
794 	ipmon_doing_t *d, *d1;
795 	ipmon_action_t *a;
796 	ipmon_saver_t *save;
797 
798 	d = calloc(1, sizeof(*d));
799 	if (d == NULL)
800 		return NULL;
801 
802 	for (it = saverlist; it != NULL; it = it->imsi_next) {
803 		if (!strcmp(it->imsi_stor->ims_name, target))
804 			break;
805 	}
806 	if (it == NULL) {
807 		free(d);
808 		return NULL;
809 	}
810 
811 	strarray[0] = options;
812 	strarray[1] = NULL;
813 
814 	d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray);
815 	if (d->ipmd_token == NULL) {
816 		free(d);
817 		return NULL;
818 	}
819 
820 	save = it->imsi_stor;
821 	d->ipmd_saver = save;
822 	d->ipmd_store = it->imsi_stor->ims_store;
823 
824 	/*
825 	 * Look for duplicate do-things that need to be dup'd
826 	 */
827 	for (a = alist; a != NULL; a = a->ac_next) {
828 		for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) {
829 			if (save != d1->ipmd_saver)
830 				continue;
831 			if (save->ims_match == NULL || save->ims_dup == NULL)
832 				continue;
833 			if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token))
834 				continue;
835 
836 			(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
837 			d->ipmd_token = (*save->ims_dup)(d1->ipmd_token);
838 			break;
839 		}
840 	}
841 
842 	return d;
843 }
844 
845 
846 static void
847 print_match(a)
848 	ipmon_action_t *a;
849 {
850 	char *coma = "";
851 
852 	if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
853 		printf("direction = ");
854 		if (a->ac_direction == IPM_IN)
855 			printf("in");
856 		else if (a->ac_direction == IPM_OUT)
857 			printf("out");
858 		coma = ", ";
859 	}
860 
861 	if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
862 		printf("%sdstip = ", coma);
863 		printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk);
864 		coma = ", ";
865 	}
866 
867 	if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
868 		printf("%sdstport = %hu", coma, ntohs(a->ac_dport));
869 		coma = ", ";
870 	}
871 
872 	if ((a->ac_mflag & IPMAC_GROUP) != 0) {
873 		char group[FR_GROUPLEN+1];
874 
875 		strncpy(group, a->ac_group, FR_GROUPLEN);
876 		group[FR_GROUPLEN] = '\0';
877 		printf("%sgroup = %s", coma, group);
878 		coma = ", ";
879 	}
880 
881 	if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
882 		printf("%siface = %s", coma, a->ac_iface);
883 		coma = ", ";
884 	}
885 
886 	if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
887 		printf("%slogtag = %u", coma, a->ac_logtag);
888 		coma = ", ";
889 	}
890 
891 	if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
892 		char tag[17];
893 
894 		strncpy(tag, a->ac_nattag, 16);
895 		tag[16] = '\0';
896 		printf("%snattag = %s", coma, tag);
897 		coma = ", ";
898 	}
899 
900 	if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
901 		printf("%sprotocol = %u", coma, a->ac_proto);
902 		coma = ", ";
903 	}
904 
905 	if ((a->ac_mflag & IPMAC_RESULT) != 0) {
906 		printf("%sresult = ", coma);
907 		switch (a->ac_result)
908 		{
909 		case IPMR_LOG :
910 			printf("log");
911 			break;
912 		case IPMR_PASS :
913 			printf("pass");
914 			break;
915 		case IPMR_BLOCK :
916 			printf("block");
917 			break;
918 		case IPMR_NOMATCH :
919 			printf("nomatch");
920 			break;
921 		}
922 		coma = ", ";
923 	}
924 
925 	if ((a->ac_mflag & IPMAC_RULE) != 0) {
926 		printf("%srule = %u", coma, a->ac_rule);
927 		coma = ", ";
928 	}
929 
930 	if ((a->ac_mflag & IPMAC_EVERY) != 0) {
931 		if (a->ac_packet > 1) {
932 			printf("%severy %d packets", coma, a->ac_packet);
933 			coma = ", ";
934 		} else if (a->ac_packet == 1) {
935 			printf("%severy packet", coma);
936 			coma = ", ";
937 		}
938 		if (a->ac_second > 1) {
939 			printf("%severy %d seconds", coma, a->ac_second);
940 			coma = ", ";
941 		} else if (a->ac_second == 1) {
942 			printf("%severy second", coma);
943 			coma = ", ";
944 		}
945 	}
946 
947 	if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
948 		printf("%ssrcip = ", coma);
949 		printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk);
950 		coma = ", ";
951 	}
952 
953 	if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
954 		printf("%ssrcport = %hu", coma, ntohs(a->ac_sport));
955 		coma = ", ";
956 	}
957 
958 	if ((a->ac_mflag & IPMAC_TYPE) != 0) {
959 		printf("%stype = ", coma);
960 		switch (a->ac_type)
961 		{
962 		case IPL_LOGIPF :
963 			printf("ipf");
964 			break;
965 		case IPL_LOGSTATE :
966 			printf("state");
967 			break;
968 		case IPL_LOGNAT :
969 			printf("nat");
970 			break;
971 		}
972 		coma = ", ";
973 	}
974 
975 	if ((a->ac_mflag & IPMAC_WITH) != 0) {
976 		printf("%swith ", coma);
977 		coma = ", ";
978 	}
979 }
980 
981 
982 static int
983 install_saver(name, path)
984 	char *name, *path;
985 {
986 	ipmon_saver_int_t *isi;
987 	ipmon_saver_t *is;
988 	char nbuf[80];
989 
990 	if (find_doing(name) == IPM_DOING)
991 		return -1;
992 
993 	isi = calloc(1, sizeof(*isi));
994 	if (isi == NULL)
995 		return -1;
996 
997 	is = calloc(1, sizeof(*is));
998 	if (is == NULL)
999 		goto loaderror;
1000 
1001 	is->ims_name = name;
1002 
1003 #ifdef RTLD_LAZY
1004 	isi->imsi_handle = dlopen(path, RTLD_LAZY);
1005 #endif
1006 #ifdef DL_LAZY
1007 	isi->imsi_handle = dlopen(path, DL_LAZY);
1008 #endif
1009 
1010 	if (isi->imsi_handle == NULL)
1011 		goto loaderror;
1012 
1013 	snprintf(nbuf, sizeof(nbuf), "%sdup", name);
1014 	is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf);
1015 
1016 	snprintf(nbuf, sizeof(nbuf), "%sdestroy", name);
1017 	is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf);
1018 	if (is->ims_destroy == NULL)
1019 		goto loaderror;
1020 
1021 	snprintf(nbuf, sizeof(nbuf), "%smatch", name);
1022 	is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf);
1023 
1024 	snprintf(nbuf, sizeof(nbuf), "%sparse", name);
1025 	is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf);
1026 	if (is->ims_parse == NULL)
1027 		goto loaderror;
1028 
1029 	snprintf(nbuf, sizeof(nbuf), "%sprint", name);
1030 	is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf);
1031 	if (is->ims_print == NULL)
1032 		goto loaderror;
1033 
1034 	snprintf(nbuf, sizeof(nbuf), "%sstore", name);
1035 	is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf);
1036 	if (is->ims_store == NULL)
1037 		goto loaderror;
1038 
1039 	isi->imsi_stor = is;
1040 	isi->imsi_next = saverlist;
1041 	saverlist = isi;
1042 
1043 	return 0;
1044 
1045 loaderror:
1046 	if (isi->imsi_handle != NULL)
1047 		dlclose(isi->imsi_handle);
1048 	free(isi);
1049 	if (is != NULL)
1050 		free(is);
1051 	return -1;
1052 }
1053