ipmon_y.y revision 255332
12061Sjkh/*	$FreeBSD: head/contrib/ipfilter/tools/ipmon_y.y 255332 2013-09-06 23:11:19Z cy $	*/
212483Speter
32061Sjkh/*
42061Sjkh * Copyright (C) 2012 by Darren Reed.
58854Srgrimes *
62061Sjkh * See the IPFILTER.LICENCE file for details on licencing.
72061Sjkh */
83197Scsgr%{
93197Scsgr#include "ipf.h"
102061Sjkh#include <syslog.h>
1112483Speter#undef	OPT_NAT
122160Scsgr#undef	OPT_VERBOSE
132834Swollman#include "ipmon_l.h"
142061Sjkh#include "ipmon.h"
152061Sjkh
162160Scsgr#include <dlfcn.h>
171594Srgrimes
182061Sjkh#define	YYDEBUG	1
192061Sjkh
201594Srgrimesextern	void	yyerror __P((char *));
217407Srgrimesextern	int	yyparse __P((void));
227407Srgrimesextern	int	yylex __P((void));
237108Sphkextern	int	yydebug;
247108Sphkextern	FILE	*yyin;
257108Sphkextern	int	yylineNum;
267407Srgrimesextern	int	ipmonopts;
277407Srgrimes
287407Srgrimestypedef	struct	opt_s	{
297108Sphk	struct	opt_s	*o_next;
302061Sjkh	int		o_line;
312061Sjkh	int		o_type;
322061Sjkh	int		o_num;
332061Sjkh	char		*o_str;
342061Sjkh	struct in_addr	o_ip;
352061Sjkh	int		o_logfac;
362061Sjkh	int		o_logpri;
372061Sjkh} opt_t;
382061Sjkh
392061Sjkhstatic	void	build_action __P((opt_t *, ipmon_doing_t *));
402061Sjkhstatic	opt_t	*new_opt __P((int));
412061Sjkhstatic	void	free_action __P((ipmon_action_t *));
423197Scsgrstatic	void	print_action __P((ipmon_action_t *));
432626Scsgrstatic	int	find_doing __P((char *));
442626Scsgrstatic	ipmon_doing_t *build_doing __P((char *, char *));
452061Sjkhstatic	void	print_match __P((ipmon_action_t *));
462061Sjkhstatic	int	install_saver __P((char *, char *));
472061Sjkh
482061Sjkhstatic	ipmon_action_t	*alist = NULL;
492061Sjkh
502061Sjkhipmon_saver_int_t	*saverlist = NULL;
512061Sjkh%}
522061Sjkh
532061Sjkh%union	{
542061Sjkh	char	*str;
552061Sjkh	u_32_t	num;
562061Sjkh	struct in_addr	addr;
572061Sjkh	struct opt_s	*opt;
582061Sjkh	union	i6addr	ip6;
592061Sjkh	struct ipmon_doing_s	*ipmd;
602061Sjkh}
612061Sjkh
622061Sjkh%token	<num>	YY_NUMBER YY_HEX
632834Swollman%token	<str>	YY_STR
642834Swollman%token	<ip6>	YY_IPV6
652834Swollman%token	YY_COMMENT
662834Swollman%token	YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
672834Swollman%token	YY_RANGE_OUT YY_RANGE_IN
682834Swollman
691594Srgrimes%token	IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
704486Sphk%token	IPM_EVERY IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT IPM_LOADACTION
714486Sphk%token	IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
724486Sphk%token	IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
734486Sphk%token	IPM_DO IPM_DOING IPM_TYPE IPM_NAT
744486Sphk%token	IPM_STATE IPM_NATTAG IPM_IPF
752061Sjkh%type	<addr> ipv4
762061Sjkh%type	<opt> direction dstip dstport every group interface
772061Sjkh%type	<opt> protocol result rule srcip srcport logtag matching
782061Sjkh%type	<opt> matchopt nattag type
792061Sjkh%type	<num> typeopt
802061Sjkh%type	<ipmd> doopt doing
812061Sjkh
822061Sjkh%%
832061Sjkhfile:	action
842061Sjkh	| file action
852061Sjkh	;
862061Sjkh
872061Sjkhaction:	line ';'
882061Sjkh	| assign ';'
892061Sjkh	| IPM_COMMENT
9012483Speter	| YY_COMMENT
9112483Speter	;
9212483Speter
9312483Speterline:	IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}'
9412483Speter						{ build_action($3, $8);
9512483Speter						  resetlexer();
962061Sjkh						}
972061Sjkh	| IPM_LOADACTION YY_STR YY_STR 	{ if (install_saver($2, $3))
988854Srgrimes						yyerror("install saver");
992061Sjkh					}
1002061Sjkh	;
10112483Speter
1022061Sjkhassign:	YY_STR assigning YY_STR 		{ set_variable($1, $3);
10312483Speter						  resetlexer();
1042061Sjkh						  free($1);
1052061Sjkh						  free($3);
1062061Sjkh						  yyvarnext = 0;
1072061Sjkh						}
1082061Sjkh	;
1092061Sjkh
1102061Sjkhassigning:
11112483Speter	'='					{ yyvarnext = 1; }
11212483Speter	;
11312483Speter
11412483Spetermatching:
11512483Speter	matchopt				{ $$ = $1; }
11612483Speter	| matchopt ',' matching			{ $1->o_next = $3; $$ = $1; }
11712483Speter	;
11812483Speter
1193030Srgrimesmatchopt:
1202061Sjkh	direction				{ $$ = $1; }
1213030Srgrimes	| dstip					{ $$ = $1; }
1222061Sjkh	| dstport				{ $$ = $1; }
1236722Sphk	| every					{ $$ = $1; }
1242061Sjkh	| group					{ $$ = $1; }
1252302Spaul	| interface				{ $$ = $1; }
1262302Spaul	| protocol				{ $$ = $1; }
1272302Spaul	| result				{ $$ = $1; }
1282302Spaul	| rule					{ $$ = $1; }
1292302Spaul	| srcip					{ $$ = $1; }
1302302Spaul	| srcport				{ $$ = $1; }
13110760Sache	| logtag				{ $$ = $1; }
13210760Sache	| nattag				{ $$ = $1; }
1332302Spaul	| type					{ $$ = $1; }
13410760Sache	;
13510760Sache
13610760Sachedoing:
13710760Sache	doopt					{ $$ = $1; }
1382302Spaul	| doopt ',' doing			{ $1->ipmd_next = $3; $$ = $1; }
1392302Spaul	;
1402302Spaul
1412302Spauldoopt:
1422302Spaul	YY_STR				{ if (find_doing($1) != IPM_DOING)
1432302Spaul						yyerror("unknown action");
1442302Spaul					}
1452061Sjkh	'(' YY_STR ')'			{ $$ = build_doing($1, $4);
1462061Sjkh					  if ($$ == NULL)
1472061Sjkh						yyerror("action building");
1482061Sjkh					}
1492061Sjkh	| YY_STR			{ if (find_doing($1) == IPM_DOING)
1502061Sjkh						$$ = build_doing($1, NULL);
1512061Sjkh					}
1522061Sjkh	;
1532061Sjkh
1542061Sjkhdirection:
1552061Sjkh	IPM_DIRECTION '=' IPM_IN		{ $$ = new_opt(IPM_DIRECTION);
1562061Sjkh						  $$->o_num = IPM_IN; }
1572061Sjkh	| IPM_DIRECTION '=' IPM_OUT		{ $$ = new_opt(IPM_DIRECTION);
1582061Sjkh						  $$->o_num = IPM_OUT; }
1592061Sjkh	;
1602061Sjkh
1612061Sjkhdstip:	IPM_DSTIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_DSTIP);
1622061Sjkh						  $$->o_ip = $3;
1632061Sjkh						  $$->o_num = $5; }
1642061Sjkh	;
1652061Sjkh
1662061Sjkhdstport:
1672061Sjkh	IPM_DSTPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_DSTPORT);
1682061Sjkh						  $$->o_num = $3; }
1692061Sjkh	| IPM_DSTPORT '=' YY_STR		{ $$ = new_opt(IPM_DSTPORT);
1702061Sjkh						  $$->o_str = $3; }
1713626Swollman	;
1723626Swollman
1733626Swollmanevery:	IPM_EVERY IPM_SECOND			{ $$ = new_opt(IPM_SECOND);
1743626Swollman						  $$->o_num = 1; }
1753626Swollman	| IPM_EVERY YY_NUMBER IPM_SECONDS	{ $$ = new_opt(IPM_SECOND);
1763626Swollman						  $$->o_num = $2; }
1773626Swollman	| IPM_EVERY IPM_PACKET			{ $$ = new_opt(IPM_PACKET);
1783626Swollman						  $$->o_num = 1; }
1793626Swollman	| IPM_EVERY YY_NUMBER IPM_PACKETS	{ $$ = new_opt(IPM_PACKET);
1803626Swollman						  $$->o_num = $2; }
1813626Swollman	;
1827059Sroberto
1833626Swollmangroup:	IPM_GROUP '=' YY_NUMBER			{ $$ = new_opt(IPM_GROUP);
1843626Swollman						  $$->o_num = $3; }
1853626Swollman	| IPM_GROUP '=' YY_STR			{ $$ = new_opt(IPM_GROUP);
1863626Swollman						  $$->o_str = $3; }
1873626Swollman	;
1883626Swollman
1893626Swollmaninterface:
1903626Swollman	IPM_INTERFACE '=' YY_STR		{ $$ = new_opt(IPM_INTERFACE);
1913626Swollman						  $$->o_str = $3; }
1923626Swollman	;
1933626Swollman
1943626Swollmanlogtag:	IPM_LOGTAG '=' YY_NUMBER		{ $$ = new_opt(IPM_LOGTAG);
1953626Swollman						  $$->o_num = $3; }
1963626Swollman	;
1973626Swollman
1983626Swollmannattag:	IPM_NATTAG '=' YY_STR			{ $$ = new_opt(IPM_NATTAG);
1993626Swollman						  $$->o_str = $3; }
2003626Swollman	;
2017446Ssos
2023626Swollmanprotocol:
2033626Swollman	IPM_PROTOCOL '=' YY_NUMBER		{ $$ = new_opt(IPM_PROTOCOL);
2043626Swollman						  $$->o_num = $3; }
2053626Swollman	| IPM_PROTOCOL '=' YY_STR		{ $$ = new_opt(IPM_PROTOCOL);
2063626Swollman						  $$->o_num = getproto($3);
2073626Swollman						  free($3);
2083626Swollman						}
2092061Sjkh	;
2102061Sjkh
2112061Sjkhresult:	IPM_RESULT '=' YY_STR			{ $$ = new_opt(IPM_RESULT);
2122061Sjkh						  $$->o_str = $3; }
2132061Sjkh	;
2142061Sjkh
2152061Sjkhrule:	IPM_RULE '=' YY_NUMBER			{ $$ = new_opt(IPM_RULE);
2162061Sjkh						  $$->o_num = YY_NUMBER; }
2172061Sjkh	;
2182061Sjkh
2192061Sjkhsrcip:	IPM_SRCIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_SRCIP);
2202061Sjkh						  $$->o_ip = $3;
2217130Srgrimes						  $$->o_num = $5; }
2227130Srgrimes	;
2237130Srgrimes
2242061Sjkhsrcport:
2252061Sjkh	IPM_SRCPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_SRCPORT);
2264249Sache						  $$->o_num = $3; }
2272685Srgrimes	| IPM_SRCPORT '=' YY_STR		{ $$ = new_opt(IPM_SRCPORT);
2286927Snate						  $$->o_str = $3; }
2292685Srgrimes	;
2303518Sache
2313197Scsgrtype:	IPM_TYPE '=' typeopt			{ $$ = new_opt(IPM_TYPE);
2323197Scsgr						  $$->o_num = $3; }
23312166Sjkh	;
2343197Scsgr
2352061Sjkhtypeopt:
2362061Sjkh	IPM_IPF					{ $$ = IPL_MAGIC; }
2372061Sjkh	| IPM_NAT				{ $$ = IPL_MAGIC_NAT; }
2382883Sphk	| IPM_STATE				{ $$ = IPL_MAGIC_STATE; }
2393429Sache	;
2403429Sache
2417281Srgrimes
2423242Spaul
2433242Spaulipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
2447171Sats		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
2452061Sjkh			yyerror("Invalid octet string for IP address");
2463213Spst			return 0;
2474942Sache		  }
2485749Swollman		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
2495772Swollman		  $$.s_addr = htonl($$.s_addr);
2505865Sache		}
2515866Sache%%
2522061Sjkhstatic	struct	wordtab	yywords[] = {
2535366Snate	{ "body",	IPM_BODY },
2545366Snate	{ "direction",	IPM_DIRECTION },
2556934Sse	{ "do",		IPM_DO },
2565366Snate	{ "dstip",	IPM_DSTIP },
2575366Snate	{ "dstport",	IPM_DSTPORT },
2587292Srgrimes	{ "every",	IPM_EVERY },
2597292Srgrimes	{ "group",	IPM_GROUP },
2605366Snate	{ "in",		IPM_IN },
2615366Snate	{ "interface",	IPM_INTERFACE },
2625366Snate	{ "ipf",	IPM_IPF },
2635366Snate	{ "load_action",IPM_LOADACTION },
2645366Snate	{ "logtag",	IPM_LOGTAG },
2655366Snate	{ "match",	IPM_MATCH },
2665772Swollman	{ "nat",	IPM_NAT },
2675772Swollman	{ "nattag",	IPM_NATTAG },
2685728Swollman	{ "no",		IPM_NO },
2695728Swollman	{ "out",	IPM_OUT },
2705728Swollman	{ "packet",	IPM_PACKET },
2715728Swollman	{ "packets",	IPM_PACKETS },
2725728Swollman	{ "protocol",	IPM_PROTOCOL },
2735366Snate	{ "result",	IPM_RESULT },
2742061Sjkh	{ "rule",	IPM_RULE },
2752061Sjkh	{ "second",	IPM_SECOND },
2762061Sjkh	{ "seconds",	IPM_SECONDS },
2772061Sjkh	{ "srcip",	IPM_SRCIP },
2782061Sjkh	{ "srcport",	IPM_SRCPORT },
2792061Sjkh	{ "state",	IPM_STATE },
2802061Sjkh	{ "with",	IPM_WITH },
2812061Sjkh	{ NULL,		0 }
2822061Sjkh};
2838295Srgrimes
2848295Srgrimesstatic int macflags[17][2] = {
28511772Snate	{ IPM_DIRECTION,	IPMAC_DIRECTION	},
2868295Srgrimes	{ IPM_DSTIP,		IPMAC_DSTIP	},
2878489Srgrimes	{ IPM_DSTPORT,		IPMAC_DSTPORT	},
2888489Srgrimes	{ IPM_GROUP,		IPMAC_GROUP	},
28911772Snate	{ IPM_INTERFACE,	IPMAC_INTERFACE	},
2908489Srgrimes	{ IPM_LOGTAG,		IPMAC_LOGTAG 	},
2918489Srgrimes	{ IPM_NATTAG,		IPMAC_NATTAG 	},
2928489Srgrimes	{ IPM_PACKET,		IPMAC_EVERY	},
29311772Snate	{ IPM_PROTOCOL,		IPMAC_PROTOCOL	},
2948489Srgrimes	{ IPM_RESULT,		IPMAC_RESULT	},
2958295Srgrimes	{ IPM_RULE,		IPMAC_RULE	},
2962468Spaul	{ IPM_SECOND,		IPMAC_EVERY	},
2972061Sjkh	{ IPM_SRCIP,		IPMAC_SRCIP	},
2982273Spaul	{ IPM_SRCPORT,		IPMAC_SRCPORT	},
2992061Sjkh	{ IPM_TYPE,		IPMAC_TYPE 	},
3008295Srgrimes	{ IPM_WITH,		IPMAC_WITH 	},
3012160Scsgr	{ 0, 0 }
3022160Scsgr};
3032160Scsgr
3042160Scsgrstatic opt_t *
3052279Spaulnew_opt(type)
3064054Spst	int type;
3074054Spst{
3082061Sjkh	opt_t *o;
3092061Sjkh
3102279Spaul	o = (opt_t *)calloc(1, sizeof(*o));
31111772Snate	o->o_type = type;
3122468Spaul	o->o_line = yylineNum;
3132468Spaul	o->o_logfac = -1;
31411772Snate	o->o_logpri = -1;
3153197Scsgr	return o;
3162626Scsgr}
3172626Scsgr
31810838Sjkhstatic void
3192626Scsgrbuild_action(olist, todo)
3202626Scsgr	opt_t *olist;
3218304Srgrimes	ipmon_doing_t *todo;
3228304Srgrimes{
32311772Snate	ipmon_action_t *a;
3248304Srgrimes	opt_t *o;
3252061Sjkh	int i;
32611806Sphk
3272061Sjkh	a = (ipmon_action_t *)calloc(1, sizeof(*a));
32812106Sjfieber	if (a == NULL)
3292061Sjkh		return;
3302061Sjkh
3312273Spaul	while ((o = olist) != NULL) {
3322061Sjkh		/*
3332061Sjkh		 * Check to see if the same comparator is being used more than
3342061Sjkh		 * once per matching statement.
33511769Sphk		 */
33611769Sphk		for (i = 0; macflags[i][0]; i++)
33712106Sjfieber			if (macflags[i][0] == o->o_type)
33812106Sjfieber				break;
33912106Sjfieber		if (macflags[i][1] & a->ac_mflag) {
34012106Sjfieber			fprintf(stderr, "%s redfined on line %d\n",
34110479Sdg				yykeytostr(o->o_type), yylineNum);
34210479Sdg			if (o->o_str != NULL)
3432061Sjkh				free(o->o_str);
3441594Srgrimes			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
432int
433check_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
632static void
633free_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
653int
654load_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
685void
686unload_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
718void
719dump_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
731static void
732print_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
754void *
755add_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
773static int
774find_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
787static ipmon_doing_t *
788build_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
846static void
847print_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
982static int
983install_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
1045loaderror:
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