Home | History | Annotate | Line # | Download | only in tools
      1 /*	$NetBSD: ipmon_y.y,v 1.2 2012/10/21 22:57:48 christos Exp $	*/
      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 __P((char *));
     21 extern	int	yyparse __P((void));
     22 extern	int	yylex __P((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 __P((opt_t *, ipmon_doing_t *));
     40 static	opt_t	*new_opt __P((int));
     41 static	void	free_action __P((ipmon_action_t *));
     42 static	void	print_action __P((ipmon_action_t *));
     43 static	int	find_doing __P((char *));
     44 static	ipmon_doing_t *build_doing __P((char *, char *));
     45 static	void	print_match __P((ipmon_action_t *));
     46 static	int	install_saver __P((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 	const 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 = (char *)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