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
19extern	void	yyerror(char *);
20extern	int	yyparse(void);
21extern	int	yylex(void);
22extern	int	yydebug;
23extern	FILE	*yyin;
24extern	int	yylineNum;
25extern	int	ipmonopts;
26
27typedef	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
38static	void	build_action(opt_t *, ipmon_doing_t *);
39static	opt_t	*new_opt(int);
40static	void	free_action(ipmon_action_t *);
41static	void	print_action(ipmon_action_t *);
42static	int	find_doing(char *);
43static	ipmon_doing_t *build_doing(char *, char *);
44static	void	print_match(ipmon_action_t *);
45static	int	install_saver(char *, char *);
46
47static	ipmon_action_t	*alist = NULL;
48
49ipmon_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%%
82file:	action
83	| file action
84	;
85
86action:	line ';'
87	| assign ';'
88	| IPM_COMMENT
89	| YY_COMMENT
90	;
91
92line:	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
101assign:	YY_STR assigning YY_STR 		{ set_variable($1, $3);
102						  resetlexer();
103						  free($1);
104						  free($3);
105						  yyvarnext = 0;
106						}
107	;
108
109assigning:
110	'='					{ yyvarnext = 1; }
111	;
112
113matching:
114	matchopt				{ $$ = $1; }
115	| matchopt ',' matching			{ $1->o_next = $3; $$ = $1; }
116	;
117
118matchopt:
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
135doing:
136	doopt					{ $$ = $1; }
137	| doopt ',' doing			{ $1->ipmd_next = $3; $$ = $1; }
138	;
139
140doopt:
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
153direction:
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
160dstip:	IPM_DSTIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_DSTIP);
161						  $$->o_ip = $3;
162						  $$->o_num = $5; }
163	;
164
165dstport:
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
172every:	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
182group:	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
188interface:
189	IPM_INTERFACE '=' YY_STR		{ $$ = new_opt(IPM_INTERFACE);
190						  $$->o_str = $3; }
191	;
192
193logtag:	IPM_LOGTAG '=' YY_NUMBER		{ $$ = new_opt(IPM_LOGTAG);
194						  $$->o_num = $3; }
195	;
196
197nattag:	IPM_NATTAG '=' YY_STR			{ $$ = new_opt(IPM_NATTAG);
198						  $$->o_str = $3; }
199	;
200
201protocol:
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
210result:	IPM_RESULT '=' YY_STR			{ $$ = new_opt(IPM_RESULT);
211						  $$->o_str = $3; }
212	;
213
214rule:	IPM_RULE '=' YY_NUMBER			{ $$ = new_opt(IPM_RULE);
215						  $$->o_num = YY_NUMBER; }
216	;
217
218srcip:	IPM_SRCIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_SRCIP);
219						  $$->o_ip = $3;
220						  $$->o_num = $5; }
221	;
222
223srcport:
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
230type:	IPM_TYPE '=' typeopt			{ $$ = new_opt(IPM_TYPE);
231						  $$->o_num = $3; }
232	;
233
234typeopt:
235	IPM_IPF					{ $$ = IPL_MAGIC; }
236	| IPM_NAT				{ $$ = IPL_MAGIC_NAT; }
237	| IPM_STATE				{ $$ = IPL_MAGIC_STATE; }
238	;
239
240
241
242ipv4:   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%%
251static	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
283static 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
303static opt_t *
304new_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
316static void
317build_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
428int
429check_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
626static void
627free_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
646int
647load_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
677void
678unload_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
710void
711dump_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
723static void
724print_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
745void *
746add_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
763static int
764find_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
776static ipmon_doing_t *
777build_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
833static void
834print_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
968static int
969install_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
1030loaderror:
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