1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3170268Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5170268Sdarrenr *
6170268Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7170268Sdarrenr */
8145510Sdarrenr%{
9145510Sdarrenr#include "ipf.h"
10145510Sdarrenr#include <syslog.h>
11145510Sdarrenr#undef	OPT_NAT
12145510Sdarrenr#undef	OPT_VERBOSE
13145510Sdarrenr#include "ipmon_l.h"
14145510Sdarrenr#include "ipmon.h"
15145510Sdarrenr
16255332Scy#include <dlfcn.h>
17255332Scy
18145510Sdarrenr#define	YYDEBUG	1
19145510Sdarrenr
20145510Sdarrenrextern	void	yyerror __P((char *));
21145510Sdarrenrextern	int	yyparse __P((void));
22145510Sdarrenrextern	int	yylex __P((void));
23145510Sdarrenrextern	int	yydebug;
24145510Sdarrenrextern	FILE	*yyin;
25145510Sdarrenrextern	int	yylineNum;
26255332Scyextern	int	ipmonopts;
27145510Sdarrenr
28255332Scytypedef	struct	opt_s	{
29255332Scy	struct	opt_s	*o_next;
30145510Sdarrenr	int		o_line;
31145510Sdarrenr	int		o_type;
32145510Sdarrenr	int		o_num;
33145510Sdarrenr	char		*o_str;
34145510Sdarrenr	struct in_addr	o_ip;
35255332Scy	int		o_logfac;
36255332Scy	int		o_logpri;
37145510Sdarrenr} opt_t;
38145510Sdarrenr
39255332Scystatic	void	build_action __P((opt_t *, ipmon_doing_t *));
40145510Sdarrenrstatic	opt_t	*new_opt __P((int));
41145510Sdarrenrstatic	void	free_action __P((ipmon_action_t *));
42255332Scystatic	void	print_action __P((ipmon_action_t *));
43255332Scystatic	int	find_doing __P((char *));
44255332Scystatic	ipmon_doing_t *build_doing __P((char *, char *));
45255332Scystatic	void	print_match __P((ipmon_action_t *));
46255332Scystatic	int	install_saver __P((char *, char *));
47145510Sdarrenr
48145510Sdarrenrstatic	ipmon_action_t	*alist = NULL;
49255332Scy
50255332Scyipmon_saver_int_t	*saverlist = NULL;
51145510Sdarrenr%}
52145510Sdarrenr
53145510Sdarrenr%union	{
54145510Sdarrenr	char	*str;
55145510Sdarrenr	u_32_t	num;
56145510Sdarrenr	struct in_addr	addr;
57255332Scy	struct opt_s	*opt;
58145510Sdarrenr	union	i6addr	ip6;
59255332Scy	struct ipmon_doing_s	*ipmd;
60145510Sdarrenr}
61145510Sdarrenr
62145510Sdarrenr%token	<num>	YY_NUMBER YY_HEX
63145510Sdarrenr%token	<str>	YY_STR
64145510Sdarrenr%token	<ip6>	YY_IPV6
65255332Scy%token	YY_COMMENT
66145510Sdarrenr%token	YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
67145510Sdarrenr%token	YY_RANGE_OUT YY_RANGE_IN
68145510Sdarrenr
69145510Sdarrenr%token	IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
70255332Scy%token	IPM_EVERY IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT IPM_LOADACTION
71145510Sdarrenr%token	IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
72145510Sdarrenr%token	IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
73255332Scy%token	IPM_DO IPM_DOING IPM_TYPE IPM_NAT
74145510Sdarrenr%token	IPM_STATE IPM_NATTAG IPM_IPF
75145510Sdarrenr%type	<addr> ipv4
76255332Scy%type	<opt> direction dstip dstport every group interface
77145510Sdarrenr%type	<opt> protocol result rule srcip srcport logtag matching
78255332Scy%type	<opt> matchopt nattag type
79255332Scy%type	<num> typeopt
80255332Scy%type	<ipmd> doopt doing
81145510Sdarrenr
82145510Sdarrenr%%
83255332Scyfile:	action
84255332Scy	| file action
85145510Sdarrenr	;
86145510Sdarrenr
87255332Scyaction:	line ';'
88255332Scy	| assign ';'
89145510Sdarrenr	| IPM_COMMENT
90145510Sdarrenr	| YY_COMMENT
91145510Sdarrenr	;
92145510Sdarrenr
93255332Scyline:	IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}'
94255332Scy						{ build_action($3, $8);
95145510Sdarrenr						  resetlexer();
96255332Scy						}
97255332Scy	| IPM_LOADACTION YY_STR YY_STR 	{ if (install_saver($2, $3))
98255332Scy						yyerror("install saver");
99255332Scy					}
100255332Scy	;
101255332Scy
102255332Scyassign:	YY_STR assigning YY_STR 		{ set_variable($1, $3);
103255332Scy						  resetlexer();
104145510Sdarrenr						  free($1);
105145510Sdarrenr						  free($3);
106170268Sdarrenr						  yyvarnext = 0;
107255332Scy						}
108145510Sdarrenr	;
109145510Sdarrenr
110145510Sdarrenrassigning:
111145510Sdarrenr	'='					{ yyvarnext = 1; }
112145510Sdarrenr	;
113145510Sdarrenr
114145510Sdarrenrmatching:
115145510Sdarrenr	matchopt				{ $$ = $1; }
116145510Sdarrenr	| matchopt ',' matching			{ $1->o_next = $3; $$ = $1; }
117145510Sdarrenr	;
118145510Sdarrenr
119145510Sdarrenrmatchopt:
120145510Sdarrenr	direction				{ $$ = $1; }
121145510Sdarrenr	| dstip					{ $$ = $1; }
122145510Sdarrenr	| dstport				{ $$ = $1; }
123145510Sdarrenr	| every					{ $$ = $1; }
124145510Sdarrenr	| group					{ $$ = $1; }
125145510Sdarrenr	| interface				{ $$ = $1; }
126145510Sdarrenr	| protocol				{ $$ = $1; }
127145510Sdarrenr	| result				{ $$ = $1; }
128145510Sdarrenr	| rule					{ $$ = $1; }
129145510Sdarrenr	| srcip					{ $$ = $1; }
130145510Sdarrenr	| srcport				{ $$ = $1; }
131145510Sdarrenr	| logtag				{ $$ = $1; }
132145510Sdarrenr	| nattag				{ $$ = $1; }
133145510Sdarrenr	| type					{ $$ = $1; }
134145510Sdarrenr	;
135145510Sdarrenr
136145510Sdarrenrdoing:
137145510Sdarrenr	doopt					{ $$ = $1; }
138255332Scy	| doopt ',' doing			{ $1->ipmd_next = $3; $$ = $1; }
139145510Sdarrenr	;
140145510Sdarrenr
141145510Sdarrenrdoopt:
142255332Scy	YY_STR				{ if (find_doing($1) != IPM_DOING)
143255332Scy						yyerror("unknown action");
144255332Scy					}
145255332Scy	'(' YY_STR ')'			{ $$ = build_doing($1, $4);
146255332Scy					  if ($$ == NULL)
147255332Scy						yyerror("action building");
148255332Scy					}
149255332Scy	| YY_STR			{ if (find_doing($1) == IPM_DOING)
150255332Scy						$$ = build_doing($1, NULL);
151255332Scy					}
152145510Sdarrenr	;
153145510Sdarrenr
154145510Sdarrenrdirection:
155145510Sdarrenr	IPM_DIRECTION '=' IPM_IN		{ $$ = new_opt(IPM_DIRECTION);
156145510Sdarrenr						  $$->o_num = IPM_IN; }
157145510Sdarrenr	| IPM_DIRECTION '=' IPM_OUT		{ $$ = new_opt(IPM_DIRECTION);
158145510Sdarrenr						  $$->o_num = IPM_OUT; }
159145510Sdarrenr	;
160145510Sdarrenr
161145510Sdarrenrdstip:	IPM_DSTIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_DSTIP);
162145510Sdarrenr						  $$->o_ip = $3;
163145510Sdarrenr						  $$->o_num = $5; }
164145510Sdarrenr	;
165145510Sdarrenr
166145510Sdarrenrdstport:
167145510Sdarrenr	IPM_DSTPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_DSTPORT);
168145510Sdarrenr						  $$->o_num = $3; }
169145510Sdarrenr	| IPM_DSTPORT '=' YY_STR		{ $$ = new_opt(IPM_DSTPORT);
170145510Sdarrenr						  $$->o_str = $3; }
171145510Sdarrenr	;
172145510Sdarrenr
173145510Sdarrenrevery:	IPM_EVERY IPM_SECOND			{ $$ = new_opt(IPM_SECOND);
174145510Sdarrenr						  $$->o_num = 1; }
175145510Sdarrenr	| IPM_EVERY YY_NUMBER IPM_SECONDS	{ $$ = new_opt(IPM_SECOND);
176145510Sdarrenr						  $$->o_num = $2; }
177145510Sdarrenr	| IPM_EVERY IPM_PACKET			{ $$ = new_opt(IPM_PACKET);
178145510Sdarrenr						  $$->o_num = 1; }
179145510Sdarrenr	| IPM_EVERY YY_NUMBER IPM_PACKETS	{ $$ = new_opt(IPM_PACKET);
180145510Sdarrenr						  $$->o_num = $2; }
181145510Sdarrenr	;
182145510Sdarrenr
183145510Sdarrenrgroup:	IPM_GROUP '=' YY_NUMBER			{ $$ = new_opt(IPM_GROUP);
184145510Sdarrenr						  $$->o_num = $3; }
185145510Sdarrenr	| IPM_GROUP '=' YY_STR			{ $$ = new_opt(IPM_GROUP);
186145510Sdarrenr						  $$->o_str = $3; }
187145510Sdarrenr	;
188145510Sdarrenr
189145510Sdarrenrinterface:
190145510Sdarrenr	IPM_INTERFACE '=' YY_STR		{ $$ = new_opt(IPM_INTERFACE);
191145510Sdarrenr						  $$->o_str = $3; }
192145510Sdarrenr	;
193145510Sdarrenr
194145510Sdarrenrlogtag:	IPM_LOGTAG '=' YY_NUMBER		{ $$ = new_opt(IPM_LOGTAG);
195145510Sdarrenr						  $$->o_num = $3; }
196145510Sdarrenr	;
197145510Sdarrenr
198145510Sdarrenrnattag:	IPM_NATTAG '=' YY_STR			{ $$ = new_opt(IPM_NATTAG);
199145510Sdarrenr						  $$->o_str = $3; }
200145510Sdarrenr	;
201145510Sdarrenr
202145510Sdarrenrprotocol:
203145510Sdarrenr	IPM_PROTOCOL '=' YY_NUMBER		{ $$ = new_opt(IPM_PROTOCOL);
204145510Sdarrenr						  $$->o_num = $3; }
205145510Sdarrenr	| IPM_PROTOCOL '=' YY_STR		{ $$ = new_opt(IPM_PROTOCOL);
206145510Sdarrenr						  $$->o_num = getproto($3);
207145510Sdarrenr						  free($3);
208145510Sdarrenr						}
209145510Sdarrenr	;
210145510Sdarrenr
211145510Sdarrenrresult:	IPM_RESULT '=' YY_STR			{ $$ = new_opt(IPM_RESULT);
212145510Sdarrenr						  $$->o_str = $3; }
213145510Sdarrenr	;
214145510Sdarrenr
215145510Sdarrenrrule:	IPM_RULE '=' YY_NUMBER			{ $$ = new_opt(IPM_RULE);
216145510Sdarrenr						  $$->o_num = YY_NUMBER; }
217145510Sdarrenr	;
218145510Sdarrenr
219145510Sdarrenrsrcip:	IPM_SRCIP '=' ipv4 '/' YY_NUMBER	{ $$ = new_opt(IPM_SRCIP);
220145510Sdarrenr						  $$->o_ip = $3;
221145510Sdarrenr						  $$->o_num = $5; }
222145510Sdarrenr	;
223145510Sdarrenr
224145510Sdarrenrsrcport:
225145510Sdarrenr	IPM_SRCPORT '=' YY_NUMBER		{ $$ = new_opt(IPM_SRCPORT);
226145510Sdarrenr						  $$->o_num = $3; }
227145510Sdarrenr	| IPM_SRCPORT '=' YY_STR		{ $$ = new_opt(IPM_SRCPORT);
228145510Sdarrenr						  $$->o_str = $3; }
229145510Sdarrenr	;
230145510Sdarrenr
231145510Sdarrenrtype:	IPM_TYPE '=' typeopt			{ $$ = new_opt(IPM_TYPE);
232145510Sdarrenr						  $$->o_num = $3; }
233145510Sdarrenr	;
234145510Sdarrenr
235145510Sdarrenrtypeopt:
236145510Sdarrenr	IPM_IPF					{ $$ = IPL_MAGIC; }
237145510Sdarrenr	| IPM_NAT				{ $$ = IPL_MAGIC_NAT; }
238145510Sdarrenr	| IPM_STATE				{ $$ = IPL_MAGIC_STATE; }
239145510Sdarrenr	;
240145510Sdarrenr
241145510Sdarrenr
242145510Sdarrenr
243145510Sdarrenripv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
244145510Sdarrenr		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
245145510Sdarrenr			yyerror("Invalid octet string for IP address");
246145510Sdarrenr			return 0;
247145510Sdarrenr		  }
248145510Sdarrenr		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
249145510Sdarrenr		  $$.s_addr = htonl($$.s_addr);
250145510Sdarrenr		}
251145510Sdarrenr%%
252145510Sdarrenrstatic	struct	wordtab	yywords[] = {
253145510Sdarrenr	{ "body",	IPM_BODY },
254145510Sdarrenr	{ "direction",	IPM_DIRECTION },
255145510Sdarrenr	{ "do",		IPM_DO },
256145510Sdarrenr	{ "dstip",	IPM_DSTIP },
257145510Sdarrenr	{ "dstport",	IPM_DSTPORT },
258145510Sdarrenr	{ "every",	IPM_EVERY },
259145510Sdarrenr	{ "group",	IPM_GROUP },
260145510Sdarrenr	{ "in",		IPM_IN },
261145510Sdarrenr	{ "interface",	IPM_INTERFACE },
262145510Sdarrenr	{ "ipf",	IPM_IPF },
263255332Scy	{ "load_action",IPM_LOADACTION },
264145510Sdarrenr	{ "logtag",	IPM_LOGTAG },
265145510Sdarrenr	{ "match",	IPM_MATCH },
266145510Sdarrenr	{ "nat",	IPM_NAT },
267145510Sdarrenr	{ "nattag",	IPM_NATTAG },
268145510Sdarrenr	{ "no",		IPM_NO },
269145510Sdarrenr	{ "out",	IPM_OUT },
270145510Sdarrenr	{ "packet",	IPM_PACKET },
271145510Sdarrenr	{ "packets",	IPM_PACKETS },
272145510Sdarrenr	{ "protocol",	IPM_PROTOCOL },
273145510Sdarrenr	{ "result",	IPM_RESULT },
274145510Sdarrenr	{ "rule",	IPM_RULE },
275145510Sdarrenr	{ "second",	IPM_SECOND },
276145510Sdarrenr	{ "seconds",	IPM_SECONDS },
277145510Sdarrenr	{ "srcip",	IPM_SRCIP },
278145510Sdarrenr	{ "srcport",	IPM_SRCPORT },
279145510Sdarrenr	{ "state",	IPM_STATE },
280145510Sdarrenr	{ "with",	IPM_WITH },
281145510Sdarrenr	{ NULL,		0 }
282145510Sdarrenr};
283145510Sdarrenr
284145510Sdarrenrstatic int macflags[17][2] = {
285145510Sdarrenr	{ IPM_DIRECTION,	IPMAC_DIRECTION	},
286145510Sdarrenr	{ IPM_DSTIP,		IPMAC_DSTIP	},
287145510Sdarrenr	{ IPM_DSTPORT,		IPMAC_DSTPORT	},
288145510Sdarrenr	{ IPM_GROUP,		IPMAC_GROUP	},
289145510Sdarrenr	{ IPM_INTERFACE,	IPMAC_INTERFACE	},
290145510Sdarrenr	{ IPM_LOGTAG,		IPMAC_LOGTAG 	},
291145510Sdarrenr	{ IPM_NATTAG,		IPMAC_NATTAG 	},
292145510Sdarrenr	{ IPM_PACKET,		IPMAC_EVERY	},
293145510Sdarrenr	{ IPM_PROTOCOL,		IPMAC_PROTOCOL	},
294145510Sdarrenr	{ IPM_RESULT,		IPMAC_RESULT	},
295145510Sdarrenr	{ IPM_RULE,		IPMAC_RULE	},
296145510Sdarrenr	{ IPM_SECOND,		IPMAC_EVERY	},
297145510Sdarrenr	{ IPM_SRCIP,		IPMAC_SRCIP	},
298145510Sdarrenr	{ IPM_SRCPORT,		IPMAC_SRCPORT	},
299145510Sdarrenr	{ IPM_TYPE,		IPMAC_TYPE 	},
300145510Sdarrenr	{ IPM_WITH,		IPMAC_WITH 	},
301145510Sdarrenr	{ 0, 0 }
302145510Sdarrenr};
303145510Sdarrenr
304255332Scystatic opt_t *
305255332Scynew_opt(type)
306255332Scy	int type;
307145510Sdarrenr{
308145510Sdarrenr	opt_t *o;
309145510Sdarrenr
310255332Scy	o = (opt_t *)calloc(1, sizeof(*o));
311145510Sdarrenr	o->o_type = type;
312145510Sdarrenr	o->o_line = yylineNum;
313255332Scy	o->o_logfac = -1;
314255332Scy	o->o_logpri = -1;
315145510Sdarrenr	return o;
316145510Sdarrenr}
317145510Sdarrenr
318255332Scystatic void
319255332Scybuild_action(olist, todo)
320255332Scy	opt_t *olist;
321255332Scy	ipmon_doing_t *todo;
322145510Sdarrenr{
323145510Sdarrenr	ipmon_action_t *a;
324145510Sdarrenr	opt_t *o;
325145510Sdarrenr	int i;
326145510Sdarrenr
327145510Sdarrenr	a = (ipmon_action_t *)calloc(1, sizeof(*a));
328145510Sdarrenr	if (a == NULL)
329145510Sdarrenr		return;
330255332Scy
331145510Sdarrenr	while ((o = olist) != NULL) {
332145510Sdarrenr		/*
333145510Sdarrenr		 * Check to see if the same comparator is being used more than
334145510Sdarrenr		 * once per matching statement.
335145510Sdarrenr		 */
336145510Sdarrenr		for (i = 0; macflags[i][0]; i++)
337145510Sdarrenr			if (macflags[i][0] == o->o_type)
338145510Sdarrenr				break;
339145510Sdarrenr		if (macflags[i][1] & a->ac_mflag) {
340145510Sdarrenr			fprintf(stderr, "%s redfined on line %d\n",
341145510Sdarrenr				yykeytostr(o->o_type), yylineNum);
342145510Sdarrenr			if (o->o_str != NULL)
343145510Sdarrenr				free(o->o_str);
344145510Sdarrenr			olist = o->o_next;
345145510Sdarrenr			free(o);
346145510Sdarrenr			continue;
347145510Sdarrenr		}
348145510Sdarrenr
349145510Sdarrenr		a->ac_mflag |= macflags[i][1];
350145510Sdarrenr
351145510Sdarrenr		switch (o->o_type)
352145510Sdarrenr		{
353145510Sdarrenr		case IPM_DIRECTION :
354145510Sdarrenr			a->ac_direction = o->o_num;
355145510Sdarrenr			break;
356145510Sdarrenr		case IPM_DSTIP :
357145510Sdarrenr			a->ac_dip = o->o_ip.s_addr;
358145510Sdarrenr			a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
359145510Sdarrenr			break;
360145510Sdarrenr		case IPM_DSTPORT :
361145510Sdarrenr			a->ac_dport = htons(o->o_num);
362145510Sdarrenr			break;
363145510Sdarrenr		case IPM_INTERFACE :
364145510Sdarrenr			a->ac_iface = o->o_str;
365145510Sdarrenr			o->o_str = NULL;
366145510Sdarrenr			break;
367255332Scy		case IPM_GROUP :
368145510Sdarrenr			if (o->o_str != NULL)
369145510Sdarrenr				strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
370145510Sdarrenr			else
371145510Sdarrenr				sprintf(a->ac_group, "%d", o->o_num);
372145510Sdarrenr			break;
373145510Sdarrenr		case IPM_LOGTAG :
374145510Sdarrenr			a->ac_logtag = o->o_num;
375145510Sdarrenr			break;
376145510Sdarrenr		case IPM_NATTAG :
377145510Sdarrenr			strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
378145510Sdarrenr			break;
379145510Sdarrenr		case IPM_PACKET :
380145510Sdarrenr			a->ac_packet = o->o_num;
381145510Sdarrenr			break;
382145510Sdarrenr		case IPM_PROTOCOL :
383145510Sdarrenr			a->ac_proto = o->o_num;
384145510Sdarrenr			break;
385145510Sdarrenr		case IPM_RULE :
386145510Sdarrenr			a->ac_rule = o->o_num;
387145510Sdarrenr			break;
388145510Sdarrenr		case IPM_RESULT :
389145510Sdarrenr			if (!strcasecmp(o->o_str, "pass"))
390145510Sdarrenr				a->ac_result = IPMR_PASS;
391145510Sdarrenr			else if (!strcasecmp(o->o_str, "block"))
392145510Sdarrenr				a->ac_result = IPMR_BLOCK;
393145510Sdarrenr			else if (!strcasecmp(o->o_str, "nomatch"))
394145510Sdarrenr				a->ac_result = IPMR_NOMATCH;
395145510Sdarrenr			else if (!strcasecmp(o->o_str, "log"))
396145510Sdarrenr				a->ac_result = IPMR_LOG;
397145510Sdarrenr			break;
398145510Sdarrenr		case IPM_SECOND :
399145510Sdarrenr			a->ac_second = o->o_num;
400145510Sdarrenr			break;
401145510Sdarrenr		case IPM_SRCIP :
402145510Sdarrenr			a->ac_sip = o->o_ip.s_addr;
403145510Sdarrenr			a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
404145510Sdarrenr			break;
405145510Sdarrenr		case IPM_SRCPORT :
406145510Sdarrenr			a->ac_sport = htons(o->o_num);
407145510Sdarrenr			break;
408145510Sdarrenr		case IPM_TYPE :
409145510Sdarrenr			a->ac_type = o->o_num;
410145510Sdarrenr			break;
411145510Sdarrenr		case IPM_WITH :
412145510Sdarrenr			break;
413145510Sdarrenr		default :
414145510Sdarrenr			break;
415145510Sdarrenr		}
416145510Sdarrenr
417145510Sdarrenr		olist = o->o_next;
418145510Sdarrenr		if (o->o_str != NULL)
419145510Sdarrenr			free(o->o_str);
420145510Sdarrenr		free(o);
421145510Sdarrenr	}
422255332Scy
423255332Scy	a->ac_doing = todo;
424145510Sdarrenr	a->ac_next = alist;
425145510Sdarrenr	alist = a;
426255332Scy
427255332Scy	if (ipmonopts & IPMON_VERBOSE)
428255332Scy		print_action(a);
429145510Sdarrenr}
430145510Sdarrenr
431145510Sdarrenr
432255332Scyint
433255332Scycheck_action(buf, log, opts, lvl)
434255332Scy	char *buf, *log;
435255332Scy	int opts, lvl;
436145510Sdarrenr{
437145510Sdarrenr	ipmon_action_t *a;
438145510Sdarrenr	struct timeval tv;
439255332Scy	ipmon_doing_t *d;
440255332Scy	ipmon_msg_t msg;
441145510Sdarrenr	ipflog_t *ipf;
442145510Sdarrenr	tcphdr_t *tcp;
443145510Sdarrenr	iplog_t *ipl;
444145510Sdarrenr	int matched;
445145510Sdarrenr	u_long t1;
446145510Sdarrenr	ip_t *ip;
447145510Sdarrenr
448145510Sdarrenr	matched = 0;
449145510Sdarrenr	ipl = (iplog_t *)buf;
450145510Sdarrenr	ipf = (ipflog_t *)(ipl +1);
451145510Sdarrenr	ip = (ip_t *)(ipf + 1);
452145510Sdarrenr	tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
453145510Sdarrenr
454255332Scy	msg.imm_data = ipl;
455255332Scy	msg.imm_dsize = ipl->ipl_dsize;
456255332Scy	msg.imm_when = ipl->ipl_time.tv_sec;
457255332Scy	msg.imm_msg = log;
458255332Scy	msg.imm_msglen = strlen(log);
459255332Scy	msg.imm_loglevel = lvl;
460255332Scy
461145510Sdarrenr	for (a = alist; a != NULL; a = a->ac_next) {
462255332Scy		verbose(0, "== checking config rule\n");
463145510Sdarrenr		if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
464145510Sdarrenr			if (a->ac_direction == IPM_IN) {
465255332Scy				if ((ipf->fl_flags & FR_INQUE) == 0) {
466255332Scy					verbose(8, "-- direction not in\n");
467145510Sdarrenr					continue;
468255332Scy				}
469145510Sdarrenr			} else if (a->ac_direction == IPM_OUT) {
470255332Scy				if ((ipf->fl_flags & FR_OUTQUE) == 0) {
471255332Scy					verbose(8, "-- direction not out\n");
472145510Sdarrenr					continue;
473255332Scy				}
474145510Sdarrenr			}
475145510Sdarrenr		}
476145510Sdarrenr
477255332Scy		if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) {
478255332Scy			verbose(8, "-- type mismatch\n");
479145510Sdarrenr			continue;
480255332Scy		}
481145510Sdarrenr
482145510Sdarrenr		if ((a->ac_mflag & IPMAC_EVERY) != 0) {
483145510Sdarrenr			gettimeofday(&tv, NULL);
484145510Sdarrenr			t1 = tv.tv_sec - a->ac_lastsec;
485145510Sdarrenr			if (tv.tv_usec <= a->ac_lastusec)
486145510Sdarrenr				t1--;
487145510Sdarrenr			if (a->ac_second != 0) {
488255332Scy				if (t1 < a->ac_second) {
489255332Scy					verbose(8, "-- too soon\n");
490145510Sdarrenr					continue;
491255332Scy				}
492145510Sdarrenr				a->ac_lastsec = tv.tv_sec;
493145510Sdarrenr				a->ac_lastusec = tv.tv_usec;
494145510Sdarrenr			}
495145510Sdarrenr
496145510Sdarrenr			if (a->ac_packet != 0) {
497145510Sdarrenr				if (a->ac_pktcnt == 0)
498145510Sdarrenr					a->ac_pktcnt++;
499145510Sdarrenr				else if (a->ac_pktcnt == a->ac_packet) {
500145510Sdarrenr					a->ac_pktcnt = 0;
501255332Scy					verbose(8, "-- packet count\n");
502145510Sdarrenr					continue;
503145510Sdarrenr				} else {
504145510Sdarrenr					a->ac_pktcnt++;
505255332Scy					verbose(8, "-- packet count\n");
506145510Sdarrenr					continue;
507145510Sdarrenr				}
508145510Sdarrenr			}
509145510Sdarrenr		}
510145510Sdarrenr
511145510Sdarrenr		if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
512255332Scy			if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) {
513255332Scy				verbose(8, "-- dstip wrong\n");
514145510Sdarrenr				continue;
515255332Scy			}
516145510Sdarrenr		}
517145510Sdarrenr
518145510Sdarrenr		if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
519255332Scy			if (ip->ip_p != IPPROTO_UDP &&
520255332Scy			    ip->ip_p != IPPROTO_TCP) {
521255332Scy				verbose(8, "-- not port protocol\n");
522145510Sdarrenr				continue;
523255332Scy			}
524255332Scy			if (tcp->th_dport != a->ac_dport) {
525255332Scy				verbose(8, "-- dport mismatch\n");
526145510Sdarrenr				continue;
527255332Scy			}
528145510Sdarrenr		}
529145510Sdarrenr
530145510Sdarrenr		if ((a->ac_mflag & IPMAC_GROUP) != 0) {
531145510Sdarrenr			if (strncmp(a->ac_group, ipf->fl_group,
532255332Scy				    FR_GROUPLEN) != 0) {
533255332Scy				verbose(8, "-- group mismatch\n");
534145510Sdarrenr				continue;
535255332Scy			}
536145510Sdarrenr		}
537145510Sdarrenr
538145510Sdarrenr		if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
539255332Scy			if (strcmp(a->ac_iface, ipf->fl_ifname)) {
540255332Scy				verbose(8, "-- ifname mismatch\n");
541145510Sdarrenr				continue;
542255332Scy			}
543145510Sdarrenr		}
544145510Sdarrenr
545145510Sdarrenr		if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
546255332Scy			if (a->ac_proto != ip->ip_p) {
547255332Scy				verbose(8, "-- protocol mismatch\n");
548145510Sdarrenr				continue;
549255332Scy			}
550145510Sdarrenr		}
551145510Sdarrenr
552145510Sdarrenr		if ((a->ac_mflag & IPMAC_RESULT) != 0) {
553145510Sdarrenr			if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
554255332Scy				if (a->ac_result != IPMR_NOMATCH) {
555255332Scy					verbose(8, "-- ff-flags mismatch\n");
556145510Sdarrenr					continue;
557255332Scy				}
558145510Sdarrenr			} else if (FR_ISPASS(ipf->fl_flags)) {
559255332Scy				if (a->ac_result != IPMR_PASS) {
560255332Scy					verbose(8, "-- pass mismatch\n");
561145510Sdarrenr					continue;
562255332Scy				}
563145510Sdarrenr			} else if (FR_ISBLOCK(ipf->fl_flags)) {
564255332Scy				if (a->ac_result != IPMR_BLOCK) {
565255332Scy					verbose(8, "-- block mismatch\n");
566145510Sdarrenr					continue;
567255332Scy				}
568145510Sdarrenr			} else {	/* Log only */
569255332Scy				if (a->ac_result != IPMR_LOG) {
570255332Scy					verbose(8, "-- log mismatch\n");
571145510Sdarrenr					continue;
572255332Scy				}
573145510Sdarrenr			}
574145510Sdarrenr		}
575145510Sdarrenr
576145510Sdarrenr		if ((a->ac_mflag & IPMAC_RULE) != 0) {
577255332Scy			if (a->ac_rule != ipf->fl_rule) {
578255332Scy				verbose(8, "-- rule mismatch\n");
579145510Sdarrenr				continue;
580255332Scy			}
581145510Sdarrenr		}
582145510Sdarrenr
583145510Sdarrenr		if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
584255332Scy			if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) {
585255332Scy				verbose(8, "-- srcip mismatch\n");
586145510Sdarrenr				continue;
587255332Scy			}
588145510Sdarrenr		}
589145510Sdarrenr
590145510Sdarrenr		if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
591255332Scy			if (ip->ip_p != IPPROTO_UDP &&
592255332Scy			    ip->ip_p != IPPROTO_TCP) {
593255332Scy				verbose(8, "-- port protocol mismatch\n");
594145510Sdarrenr				continue;
595255332Scy			}
596255332Scy			if (tcp->th_sport != a->ac_sport) {
597255332Scy				verbose(8, "-- sport mismatch\n");
598145510Sdarrenr				continue;
599255332Scy			}
600145510Sdarrenr		}
601145510Sdarrenr
602145510Sdarrenr		if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
603255332Scy			if (a->ac_logtag != ipf->fl_logtag) {
604255332Scy				verbose(8, "-- logtag %d != %d\n",
605255332Scy					a->ac_logtag, ipf->fl_logtag);
606145510Sdarrenr				continue;
607255332Scy			}
608145510Sdarrenr		}
609145510Sdarrenr
610145510Sdarrenr		if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
611145510Sdarrenr			if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
612255332Scy				    IPFTAG_LEN) != 0) {
613255332Scy				verbose(8, "-- nattag mismatch\n");
614145510Sdarrenr				continue;
615255332Scy			}
616145510Sdarrenr		}
617145510Sdarrenr
618145510Sdarrenr		matched = 1;
619255332Scy		verbose(8, "++ matched\n");
620145510Sdarrenr
621145510Sdarrenr		/*
622255332Scy		 * It matched so now perform the saves
623145510Sdarrenr		 */
624255332Scy		for (d = a->ac_doing; d != NULL; d = d->ipmd_next)
625255332Scy			(*d->ipmd_store)(d->ipmd_token, &msg);
626145510Sdarrenr	}
627145510Sdarrenr
628145510Sdarrenr	return matched;
629145510Sdarrenr}
630145510Sdarrenr
631145510Sdarrenr
632255332Scystatic void
633255332Scyfree_action(a)
634255332Scy	ipmon_action_t *a;
635145510Sdarrenr{
636255332Scy	ipmon_doing_t *d;
637255332Scy
638255332Scy	while ((d = a->ac_doing) != NULL) {
639255332Scy		a->ac_doing = d->ipmd_next;
640255332Scy		(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
641255332Scy		free(d);
642145510Sdarrenr	}
643255332Scy
644145510Sdarrenr	if (a->ac_iface != NULL) {
645145510Sdarrenr		free(a->ac_iface);
646145510Sdarrenr		a->ac_iface = NULL;
647145510Sdarrenr	}
648145510Sdarrenr	a->ac_next = NULL;
649145510Sdarrenr	free(a);
650145510Sdarrenr}
651145510Sdarrenr
652145510Sdarrenr
653255332Scyint
654255332Scyload_config(file)
655255332Scy	char *file;
656145510Sdarrenr{
657145510Sdarrenr	FILE *fp;
658145510Sdarrenr	char *s;
659145510Sdarrenr
660255332Scy	unload_config();
661255332Scy
662145510Sdarrenr	s = getenv("YYDEBUG");
663145510Sdarrenr	if (s != NULL)
664145510Sdarrenr		yydebug = atoi(s);
665145510Sdarrenr	else
666145510Sdarrenr		yydebug = 0;
667145510Sdarrenr
668145510Sdarrenr	yylineNum = 1;
669145510Sdarrenr
670145510Sdarrenr	(void) yysettab(yywords);
671145510Sdarrenr
672145510Sdarrenr	fp = fopen(file, "r");
673145510Sdarrenr	if (!fp) {
674145510Sdarrenr		perror("load_config:fopen:");
675145510Sdarrenr		return -1;
676145510Sdarrenr	}
677145510Sdarrenr	yyin = fp;
678145510Sdarrenr	while (!feof(fp))
679145510Sdarrenr		yyparse();
680145510Sdarrenr	fclose(fp);
681145510Sdarrenr	return 0;
682145510Sdarrenr}
683255332Scy
684255332Scy
685255332Scyvoid
686255332Scyunload_config()
687255332Scy{
688255332Scy	ipmon_saver_int_t *sav, **imsip;
689255332Scy	ipmon_saver_t *is;
690255332Scy	ipmon_action_t *a;
691255332Scy
692255332Scy	while ((a = alist) != NULL) {
693255332Scy		alist = a->ac_next;
694255332Scy		free_action(a);
695255332Scy	}
696255332Scy
697255332Scy	/*
698255332Scy	 * Look for savers that have been added in dynamically from the
699255332Scy	 * configuration file.
700255332Scy	 */
701255332Scy	for (imsip = &saverlist; (sav = *imsip) != NULL; ) {
702255332Scy		if (sav->imsi_handle == NULL)
703255332Scy			imsip = &sav->imsi_next;
704255332Scy		else {
705255332Scy			dlclose(sav->imsi_handle);
706255332Scy
707255332Scy			*imsip = sav->imsi_next;
708255332Scy			is = sav->imsi_stor;
709255332Scy			free(sav);
710255332Scy
711255332Scy			free(is->ims_name);
712255332Scy			free(is);
713255332Scy		}
714255332Scy	}
715255332Scy}
716255332Scy
717255332Scy
718255332Scyvoid
719255332Scydump_config()
720255332Scy{
721255332Scy	ipmon_action_t *a;
722255332Scy
723255332Scy	for (a = alist; a != NULL; a = a->ac_next) {
724255332Scy		print_action(a);
725255332Scy
726255332Scy		printf("#\n");
727255332Scy	}
728255332Scy}
729255332Scy
730255332Scy
731255332Scystatic void
732255332Scyprint_action(a)
733255332Scy	ipmon_action_t *a;
734255332Scy{
735255332Scy	ipmon_doing_t *d;
736255332Scy
737255332Scy	printf("match { ");
738255332Scy	print_match(a);
739255332Scy	printf("; }\n");
740255332Scy	printf("do {");
741255332Scy	for (d = a->ac_doing; d != NULL; d = d->ipmd_next) {
742255332Scy		printf("%s", d->ipmd_saver->ims_name);
743255332Scy		if (d->ipmd_saver->ims_print != NULL) {
744255332Scy			printf("(\"");
745255332Scy			(*d->ipmd_saver->ims_print)(d->ipmd_token);
746255332Scy			printf("\")");
747255332Scy		}
748255332Scy		printf(";");
749255332Scy	}
750255332Scy	printf("};\n");
751255332Scy}
752255332Scy
753255332Scy
754255332Scyvoid *
755255332Scyadd_doing(saver)
756255332Scy	ipmon_saver_t *saver;
757255332Scy{
758255332Scy	ipmon_saver_int_t *it;
759255332Scy
760255332Scy	if (find_doing(saver->ims_name) == IPM_DOING)
761255332Scy		return NULL;
762255332Scy
763255332Scy	it = calloc(1, sizeof(*it));
764255332Scy	if (it == NULL)
765255332Scy		return NULL;
766255332Scy	it->imsi_stor = saver;
767255332Scy	it->imsi_next = saverlist;
768255332Scy	saverlist = it;
769255332Scy	return it;
770255332Scy}
771255332Scy
772255332Scy
773255332Scystatic int
774255332Scyfind_doing(string)
775255332Scy	char *string;
776255332Scy{
777255332Scy	ipmon_saver_int_t *it;
778255332Scy
779255332Scy	for (it = saverlist; it != NULL; it = it->imsi_next) {
780255332Scy		if (!strcmp(it->imsi_stor->ims_name, string))
781255332Scy			return IPM_DOING;
782255332Scy	}
783255332Scy	return 0;
784255332Scy}
785255332Scy
786255332Scy
787255332Scystatic ipmon_doing_t *
788255332Scybuild_doing(target, options)
789255332Scy	char *target;
790255332Scy	char *options;
791255332Scy{
792255332Scy	ipmon_saver_int_t *it;
793255332Scy	char *strarray[2];
794255332Scy	ipmon_doing_t *d, *d1;
795255332Scy	ipmon_action_t *a;
796255332Scy	ipmon_saver_t *save;
797255332Scy
798255332Scy	d = calloc(1, sizeof(*d));
799255332Scy	if (d == NULL)
800255332Scy		return NULL;
801255332Scy
802255332Scy	for (it = saverlist; it != NULL; it = it->imsi_next) {
803255332Scy		if (!strcmp(it->imsi_stor->ims_name, target))
804255332Scy			break;
805255332Scy	}
806255332Scy	if (it == NULL) {
807255332Scy		free(d);
808255332Scy		return NULL;
809255332Scy	}
810255332Scy
811255332Scy	strarray[0] = options;
812255332Scy	strarray[1] = NULL;
813255332Scy
814255332Scy	d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray);
815255332Scy	if (d->ipmd_token == NULL) {
816255332Scy		free(d);
817255332Scy		return NULL;
818255332Scy	}
819255332Scy
820255332Scy	save = it->imsi_stor;
821255332Scy	d->ipmd_saver = save;
822255332Scy	d->ipmd_store = it->imsi_stor->ims_store;
823255332Scy
824255332Scy	/*
825255332Scy	 * Look for duplicate do-things that need to be dup'd
826255332Scy	 */
827255332Scy	for (a = alist; a != NULL; a = a->ac_next) {
828255332Scy		for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) {
829255332Scy			if (save != d1->ipmd_saver)
830255332Scy				continue;
831255332Scy			if (save->ims_match == NULL || save->ims_dup == NULL)
832255332Scy				continue;
833255332Scy			if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token))
834255332Scy				continue;
835255332Scy
836255332Scy			(*d->ipmd_saver->ims_destroy)(d->ipmd_token);
837255332Scy			d->ipmd_token = (*save->ims_dup)(d1->ipmd_token);
838255332Scy			break;
839255332Scy		}
840255332Scy	}
841255332Scy
842255332Scy	return d;
843255332Scy}
844255332Scy
845255332Scy
846255332Scystatic void
847255332Scyprint_match(a)
848255332Scy	ipmon_action_t *a;
849255332Scy{
850255332Scy	char *coma = "";
851255332Scy
852255332Scy	if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
853255332Scy		printf("direction = ");
854255332Scy		if (a->ac_direction == IPM_IN)
855255332Scy			printf("in");
856255332Scy		else if (a->ac_direction == IPM_OUT)
857255332Scy			printf("out");
858255332Scy		coma = ", ";
859255332Scy	}
860255332Scy
861255332Scy	if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
862255332Scy		printf("%sdstip = ", coma);
863255332Scy		printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk);
864255332Scy		coma = ", ";
865255332Scy	}
866255332Scy
867255332Scy	if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
868255332Scy		printf("%sdstport = %hu", coma, ntohs(a->ac_dport));
869255332Scy		coma = ", ";
870255332Scy	}
871255332Scy
872255332Scy	if ((a->ac_mflag & IPMAC_GROUP) != 0) {
873255332Scy		char group[FR_GROUPLEN+1];
874255332Scy
875255332Scy		strncpy(group, a->ac_group, FR_GROUPLEN);
876255332Scy		group[FR_GROUPLEN] = '\0';
877255332Scy		printf("%sgroup = %s", coma, group);
878255332Scy		coma = ", ";
879255332Scy	}
880255332Scy
881255332Scy	if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
882255332Scy		printf("%siface = %s", coma, a->ac_iface);
883255332Scy		coma = ", ";
884255332Scy	}
885255332Scy
886255332Scy	if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
887255332Scy		printf("%slogtag = %u", coma, a->ac_logtag);
888255332Scy		coma = ", ";
889255332Scy	}
890255332Scy
891255332Scy	if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
892255332Scy		char tag[17];
893255332Scy
894255332Scy		strncpy(tag, a->ac_nattag, 16);
895255332Scy		tag[16] = '\0';
896255332Scy		printf("%snattag = %s", coma, tag);
897255332Scy		coma = ", ";
898255332Scy	}
899255332Scy
900255332Scy	if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
901255332Scy		printf("%sprotocol = %u", coma, a->ac_proto);
902255332Scy		coma = ", ";
903255332Scy	}
904255332Scy
905255332Scy	if ((a->ac_mflag & IPMAC_RESULT) != 0) {
906255332Scy		printf("%sresult = ", coma);
907255332Scy		switch (a->ac_result)
908255332Scy		{
909255332Scy		case IPMR_LOG :
910255332Scy			printf("log");
911255332Scy			break;
912255332Scy		case IPMR_PASS :
913255332Scy			printf("pass");
914255332Scy			break;
915255332Scy		case IPMR_BLOCK :
916255332Scy			printf("block");
917255332Scy			break;
918255332Scy		case IPMR_NOMATCH :
919255332Scy			printf("nomatch");
920255332Scy			break;
921255332Scy		}
922255332Scy		coma = ", ";
923255332Scy	}
924255332Scy
925255332Scy	if ((a->ac_mflag & IPMAC_RULE) != 0) {
926255332Scy		printf("%srule = %u", coma, a->ac_rule);
927255332Scy		coma = ", ";
928255332Scy	}
929255332Scy
930255332Scy	if ((a->ac_mflag & IPMAC_EVERY) != 0) {
931255332Scy		if (a->ac_packet > 1) {
932255332Scy			printf("%severy %d packets", coma, a->ac_packet);
933255332Scy			coma = ", ";
934255332Scy		} else if (a->ac_packet == 1) {
935255332Scy			printf("%severy packet", coma);
936255332Scy			coma = ", ";
937255332Scy		}
938255332Scy		if (a->ac_second > 1) {
939255332Scy			printf("%severy %d seconds", coma, a->ac_second);
940255332Scy			coma = ", ";
941255332Scy		} else if (a->ac_second == 1) {
942255332Scy			printf("%severy second", coma);
943255332Scy			coma = ", ";
944255332Scy		}
945255332Scy	}
946255332Scy
947255332Scy	if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
948255332Scy		printf("%ssrcip = ", coma);
949255332Scy		printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk);
950255332Scy		coma = ", ";
951255332Scy	}
952255332Scy
953255332Scy	if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
954255332Scy		printf("%ssrcport = %hu", coma, ntohs(a->ac_sport));
955255332Scy		coma = ", ";
956255332Scy	}
957255332Scy
958255332Scy	if ((a->ac_mflag & IPMAC_TYPE) != 0) {
959255332Scy		printf("%stype = ", coma);
960255332Scy		switch (a->ac_type)
961255332Scy		{
962255332Scy		case IPL_LOGIPF :
963255332Scy			printf("ipf");
964255332Scy			break;
965255332Scy		case IPL_LOGSTATE :
966255332Scy			printf("state");
967255332Scy			break;
968255332Scy		case IPL_LOGNAT :
969255332Scy			printf("nat");
970255332Scy			break;
971255332Scy		}
972255332Scy		coma = ", ";
973255332Scy	}
974255332Scy
975255332Scy	if ((a->ac_mflag & IPMAC_WITH) != 0) {
976255332Scy		printf("%swith ", coma);
977255332Scy		coma = ", ";
978255332Scy	}
979255332Scy}
980255332Scy
981255332Scy
982255332Scystatic int
983255332Scyinstall_saver(name, path)
984255332Scy	char *name, *path;
985255332Scy{
986255332Scy	ipmon_saver_int_t *isi;
987255332Scy	ipmon_saver_t *is;
988255332Scy	char nbuf[80];
989255332Scy
990255332Scy	if (find_doing(name) == IPM_DOING)
991255332Scy		return -1;
992255332Scy
993255332Scy	isi = calloc(1, sizeof(*isi));
994255332Scy	if (isi == NULL)
995255332Scy		return -1;
996255332Scy
997255332Scy	is = calloc(1, sizeof(*is));
998255332Scy	if (is == NULL)
999255332Scy		goto loaderror;
1000255332Scy
1001255332Scy	is->ims_name = name;
1002255332Scy
1003255332Scy#ifdef RTLD_LAZY
1004255332Scy	isi->imsi_handle = dlopen(path, RTLD_LAZY);
1005255332Scy#endif
1006255332Scy#ifdef DL_LAZY
1007255332Scy	isi->imsi_handle = dlopen(path, DL_LAZY);
1008255332Scy#endif
1009255332Scy
1010255332Scy	if (isi->imsi_handle == NULL)
1011255332Scy		goto loaderror;
1012255332Scy
1013255332Scy	snprintf(nbuf, sizeof(nbuf), "%sdup", name);
1014255332Scy	is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf);
1015255332Scy
1016255332Scy	snprintf(nbuf, sizeof(nbuf), "%sdestroy", name);
1017255332Scy	is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf);
1018255332Scy	if (is->ims_destroy == NULL)
1019255332Scy		goto loaderror;
1020255332Scy
1021255332Scy	snprintf(nbuf, sizeof(nbuf), "%smatch", name);
1022255332Scy	is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf);
1023255332Scy
1024255332Scy	snprintf(nbuf, sizeof(nbuf), "%sparse", name);
1025255332Scy	is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf);
1026255332Scy	if (is->ims_parse == NULL)
1027255332Scy		goto loaderror;
1028255332Scy
1029255332Scy	snprintf(nbuf, sizeof(nbuf), "%sprint", name);
1030255332Scy	is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf);
1031255332Scy	if (is->ims_print == NULL)
1032255332Scy		goto loaderror;
1033255332Scy
1034255332Scy	snprintf(nbuf, sizeof(nbuf), "%sstore", name);
1035255332Scy	is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf);
1036255332Scy	if (is->ims_store == NULL)
1037255332Scy		goto loaderror;
1038255332Scy
1039255332Scy	isi->imsi_stor = is;
1040255332Scy	isi->imsi_next = saverlist;
1041255332Scy	saverlist = isi;
1042255332Scy
1043255332Scy	return 0;
1044255332Scy
1045255332Scyloaderror:
1046255332Scy	if (isi->imsi_handle != NULL)
1047255332Scy		dlclose(isi->imsi_handle);
1048255332Scy	free(isi);
1049255332Scy	if (is != NULL)
1050255332Scy		free(is);
1051255332Scy	return -1;
1052255332Scy}
1053