1%{
2/*
3 * Copyright (C) 2003 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 *
7 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
8 * Use is subject to license terms.
9 */
10
11#pragma ident	"%Z%%M%	%I%	%E% SMI"
12
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/param.h>
16#include <sys/socket.h>
17#if defined(BSD) && (BSD >= 199306)
18# include <sys/cdefs.h>
19#endif
20#include <sys/ioctl.h>
21
22#include <net/if.h>
23#if __FreeBSD_version >= 300000
24# include <net/if_var.h>
25#endif
26#include <netinet/in.h>
27
28#include <arpa/inet.h>
29
30#include <stdio.h>
31#include <fcntl.h>
32#include <stdlib.h>
33#include <string.h>
34#include <netdb.h>
35#include <ctype.h>
36#include <unistd.h>
37
38#include "ipf.h"
39#include "netinet/ip_lookup.h"
40#include "netinet/ip_pool.h"
41#include "netinet/ip_htable.h"
42#include "ippool_l.h"
43#include "kmem.h"
44
45#define	YYDEBUG	1
46
47extern	int	yyparse __P((void));
48extern	int	yydebug;
49extern	FILE	*yyin;
50
51static	iphtable_t	ipht;
52static	iphtent_t	iphte;
53static	ip_pool_t	iplo;
54static	ioctlfunc_t	poolioctl = NULL;
55static	char		poolname[FR_GROUPLEN];
56static	int		set_ipv6_addr = 0;
57
58%}
59
60%union	{
61	char	*str;
62	u_32_t	num;
63	struct	in_addr	addr;
64	struct	alist_s	*alist;
65	union   i6addr	adrmsk[2];
66	iphtent_t	*ipe;
67	ip_pool_node_t	*ipp;
68	union	i6addr	ip6;
69}
70
71%token  <num>   YY_NUMBER YY_HEX
72%token  <str>   YY_STR
73%token	  YY_COMMENT
74%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
75%token	  YY_RANGE_OUT YY_RANGE_IN
76%token  <ip6>   YY_IPV6
77
78%token	IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT
79%token	IPT_TABLE IPT_GROUPMAP IPT_HASH
80%token	IPT_ROLE IPT_TYPE IPT_TREE
81%token	IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME
82%type	<num> role table inout
83%type	<ipp> ipftree range addrlist
84%type	<adrmsk> addrmask
85%type	<ipe> ipfgroup ipfhash hashlist hashentry
86%type	<ipe> groupentry setgrouplist grouplist
87%type	<ip6> ipaddr mask ipv4
88%type	<str> number setgroup
89
90%%
91file:	line
92	| assign
93	| file line
94	| file assign
95	;
96
97line:	table role ipftree eol		{ iplo.ipo_unit = $2;
98					  iplo.ipo_list = $3;
99					  load_pool(&iplo, poolioctl);
100					  resetlexer();
101					}
102	| table role ipfhash eol	{ ipht.iph_unit = $2;
103					  ipht.iph_type = IPHASH_LOOKUP;
104					  load_hash(&ipht, $3, poolioctl);
105					  resetlexer();
106					}
107	| groupmap role number ipfgroup eol
108					{ ipht.iph_unit = $2;
109					  strncpy(ipht.iph_name, $3,
110						  sizeof(ipht.iph_name));
111					  ipht.iph_type = IPHASH_GROUPMAP;
112					  load_hash(&ipht, $4, poolioctl);
113					  resetlexer();
114					}
115	| YY_COMMENT
116	;
117
118eol:	';'
119	;
120
121assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
122					  resetlexer();
123					  free($1);
124					  free($3);
125					}
126	;
127
128assigning:
129	'='				{ yyvarnext = 1; }
130	;
131
132table:	IPT_TABLE		{ bzero((char *)&ipht, sizeof(ipht));
133				  bzero((char *)&iphte, sizeof(iphte));
134				  bzero((char *)&iplo, sizeof(iplo));
135				  *ipht.iph_name = '\0';
136				  iplo.ipo_flags = IPHASH_ANON;
137				  iplo.ipo_name[0] = '\0';
138				}
139	;
140
141groupmap:
142	IPT_GROUPMAP inout	{ bzero((char *)&ipht, sizeof(ipht));
143				  bzero((char *)&iphte, sizeof(iphte));
144				  *ipht.iph_name = '\0';
145				  ipht.iph_unit = IPHASH_GROUPMAP;
146				  ipht.iph_flags = $2;
147				}
148	;
149
150inout:	IPT_IN				{ $$ = FR_INQUE; }
151	| IPT_OUT			{ $$ = FR_OUTQUE; }
152	;
153role:
154	IPT_ROLE '=' IPT_IPF		{ $$ = IPL_LOGIPF; }
155	| IPT_ROLE '=' IPT_NAT		{ $$ = IPL_LOGNAT; }
156	| IPT_ROLE '=' IPT_AUTH		{ $$ = IPL_LOGAUTH; }
157	| IPT_ROLE '=' IPT_COUNT	{ $$ = IPL_LOGCOUNT; }
158	;
159
160ipftree:
161	IPT_TYPE '=' IPT_TREE number start addrlist end
162					{ strncpy(iplo.ipo_name, $4,
163						  sizeof(iplo.ipo_name));
164					  $$ = $6;
165					}
166	;
167
168ipfhash:
169	IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
170					{ strncpy(ipht.iph_name, $4,
171						  sizeof(ipht.iph_name));
172					  $$ = $7;
173					}
174	;
175
176ipfgroup:
177	setgroup hashopts start grouplist end
178					{ iphtent_t *e;
179					  for (e = $4; e != NULL;
180					       e = e->ipe_next)
181						if (e->ipe_group[0] == '\0')
182							strncpy(e->ipe_group,
183								$1,
184								FR_GROUPLEN);
185					  $$ = $4;
186					}
187	| hashopts start setgrouplist end		{ $$ = $3; }
188	;
189
190number:	IPT_NUM '=' YY_NUMBER			{ snprintf(poolname, FR_GROUPLEN, "%u", $3);
191						  $$ = poolname;
192						}
193	| IPT_NAME '=' YY_STR			{ $$ = $3; }
194	|					{ $$ = ""; }
195	;
196
197setgroup:
198	IPT_GROUP '=' YY_STR		{ char tmp[FR_GROUPLEN+1];
199					  strncpy(tmp, $3, FR_GROUPLEN);
200					  $$ = strdup(tmp);
201					}
202	| IPT_GROUP '=' YY_NUMBER	{ char tmp[FR_GROUPLEN+1];
203					  snprintf(tmp, FR_GROUPLEN, "%u", $3);
204					  $$ = strdup(tmp);
205					}
206	;
207
208hashopts:
209	| size
210	| seed
211	| size seed
212	;
213
214addrlist:
215	';'				{ $$ = NULL; }
216	| range next addrlist		{ $1->ipn_next = $3; $$ = $1; }
217	| range next			{ $$ = $1; }
218	| range
219	;
220
221grouplist:
222	';'				{ $$ = NULL; }
223	| groupentry next grouplist	{ $$ = $1; $1->ipe_next = $3; }
224	| addrmask next grouplist	{ $$ = calloc(1, sizeof(iphtent_t));
225					  if ($$ == NULL)
226						yyerror("sorry, out of memory");
227					  if  (set_ipv6_addr)
228					  	$$->ipe_family = AF_INET6;
229					  else
230						$$->ipe_family = AF_INET;
231					  bcopy((char *)&($1[0]),
232						(char *)&($$->ipe_addr),
233						sizeof($$->ipe_addr));
234					  bcopy((char *)&($1[1]),
235						(char *)&($$->ipe_mask),
236						sizeof($$->ipe_mask));
237					  set_ipv6_addr = 0;
238					  $$->ipe_next = $3;
239					}
240	| groupentry next		{ $$ = $1; }
241	| addrmask next			{ $$ = calloc(1, sizeof(iphtent_t));
242					  if ($$ == NULL)
243						yyerror("sorry, out of memory");
244					  if  (set_ipv6_addr)
245					  	$$->ipe_family = AF_INET6;
246					  else
247						$$->ipe_family = AF_INET;
248					  bcopy((char *)&($1[0]),
249						(char *)&($$->ipe_addr),
250						sizeof($$->ipe_addr));
251					  bcopy((char *)&($1[1]),
252						(char *)&($$->ipe_mask),
253						sizeof($$->ipe_mask));
254					  set_ipv6_addr = 0;
255					}
256	;
257
258setgrouplist:
259	';'				{ $$ = NULL; }
260	| groupentry next		{ $$ = $1; }
261	| groupentry next setgrouplist	{ $1->ipe_next = $3; $$ = $1; }
262	;
263
264groupentry:
265	addrmask ',' setgroup		{ $$ = calloc(1, sizeof(iphtent_t));
266					  if ($$ == NULL)
267						yyerror("sorry, out of memory");
268					  if  (set_ipv6_addr)
269					  	$$->ipe_family = AF_INET6;
270					  else
271						$$->ipe_family = AF_INET;
272					  bcopy((char *)&($1[0]),
273						(char *)&($$->ipe_addr),
274						sizeof($$->ipe_addr));
275					  bcopy((char *)&($1[1]),
276						(char *)&($$->ipe_mask),
277						sizeof($$->ipe_mask));
278					  set_ipv6_addr = 0;
279					  strncpy($$->ipe_group, $3,
280						  FR_GROUPLEN);
281					  free($3);
282					}
283	;
284
285range:	addrmask	{ $$ = calloc(1, sizeof(*$$));
286			  if ($$ == NULL)
287				yyerror("sorry, out of memory");
288			  $$->ipn_info = 0;
289			  $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
290			  $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
291			  if (set_ipv6_addr) {
292				  $$->ipn_addr.adf_family = AF_INET6;
293				  $$->ipn_addr.adf_addr = $1[0];
294				  $$->ipn_mask.adf_addr = $1[1];
295
296			  } else {
297				  $$->ipn_addr.adf_family = AF_INET;
298				  $$->ipn_addr.adf_addr.in4.s_addr = $1[0].in4.s_addr;
299				  $$->ipn_mask.adf_addr.in4.s_addr = $1[1].in4.s_addr;
300			  }
301			  set_ipv6_addr = 0;
302			}
303	| '!' addrmask	{ $$ = calloc(1, sizeof(*$$));
304			  if ($$ == NULL)
305				yyerror("sorry, out of memory");
306			  $$->ipn_info = 1;
307			  $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
308			  $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
309			  if (set_ipv6_addr) {
310				  $$->ipn_addr.adf_family = AF_INET6;
311				  $$->ipn_addr.adf_addr = $2[0];
312				  $$->ipn_mask.adf_addr = $2[1];
313			  } else {
314				  $$->ipn_addr.adf_family = AF_INET;
315				  $$->ipn_addr.adf_addr.in4.s_addr = $2[0].in4.s_addr;
316				  $$->ipn_mask.adf_addr.in4.s_addr = $2[1].in4.s_addr;
317			  }
318			  set_ipv6_addr = 0;
319			}
320
321hashlist:
322	';'				{ $$ = NULL; }
323	| hashentry next		{ $$ = $1; }
324	| hashentry next hashlist	{ $1->ipe_next = $3; $$ = $1; }
325	;
326
327hashentry:
328	addrmask			{ $$ = calloc(1, sizeof(iphtent_t));
329					  if ($$ == NULL)
330						yyerror("sorry, out of memory");
331					  if  (set_ipv6_addr)
332					  	$$->ipe_family = AF_INET6;
333					  else
334						$$->ipe_family = AF_INET;
335					  bcopy((char *)&($1[0]),
336						(char *)&($$->ipe_addr),
337						sizeof($$->ipe_addr));
338					  bcopy((char *)&($1[1]),
339						(char *)&($$->ipe_mask),
340						sizeof($$->ipe_mask));
341					}
342	;
343
344addrmask:
345	ipaddr '/' mask		{ $$[0] = $1; $$[1] = $3;
346				  yyexpectaddr = 0;
347				}
348	| ipaddr		{ $$[0] = $1;
349				  yyexpectaddr = 0;
350				  if (set_ipv6_addr)
351				  	fill6bits(128, (u_32_t *)$$[1].in6.s6_addr);
352				  else
353				  	$$[1].in4.s_addr = 0xffffffff;
354				}
355	;
356
357ipaddr:	ipv4			{ $$ = $1; }
358	| YY_NUMBER		{ $$.in4.s_addr = htonl($1); }
359	| YY_IPV6		{ set_ipv6_addr = 1;
360				  bcopy(&$1, &$$, sizeof($$));
361				  yyexpectaddr = 0; }
362	| YY_STR		{ if (gethost($1, &$$, 0) == -1)
363					yyerror("Unknown hostname");
364				}
365	;
366
367mask:	YY_NUMBER		{ if (set_ipv6_addr)
368					ntomask(6, $1, (u_32_t *)$$.in6.s6_addr);
369				  else
370				  	ntomask(4, $1, (u_32_t *)&$$.in4.s_addr); }
371	| ipv4			{ $$ = $1; }
372	;
373
374start:	'{'			{ yyexpectaddr = 1; }
375	;
376
377end:	'}'			{ yyexpectaddr = 0; }
378	;
379
380next:	','			{ yyexpectaddr = 1; }
381	| ';'			{ yyexpectaddr = 1; }
382	;
383
384size:	IPT_SIZE '=' YY_NUMBER	{ ipht.iph_size = $3; }
385	;
386
387seed:	IPT_SEED '=' YY_NUMBER	{ ipht.iph_seed = $3; }
388	;
389
390ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
391		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
392			yyerror("Invalid octet string for IP address");
393			return 0;
394		  }
395		  $$.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
396		  $$.in4.s_addr = htonl($$.in4.s_addr);
397		}
398	;
399%%
400static	wordtab_t	yywords[] = {
401	{ "auth",	IPT_AUTH },
402	{ "count",	IPT_COUNT },
403	{ "group",	IPT_GROUP },
404	{ "group-map",	IPT_GROUPMAP },
405	{ "hash",	IPT_HASH },
406	{ "in",		IPT_IN },
407	{ "ipf",	IPT_IPF },
408	{ "name",	IPT_NAME },
409	{ "nat",	IPT_NAT },
410	{ "number",	IPT_NUM },
411	{ "out",	IPT_OUT },
412	{ "role",	IPT_ROLE },
413	{ "seed",	IPT_SEED },
414	{ "size",	IPT_SIZE },
415	{ "table",	IPT_TABLE },
416	{ "tree",	IPT_TREE },
417	{ "type",	IPT_TYPE },
418	{ NULL,		0 }
419};
420
421
422int ippool_parsefile(fd, filename, iocfunc)
423int fd;
424char *filename;
425ioctlfunc_t iocfunc;
426{
427	FILE *fp = NULL;
428	char *s;
429
430	yylineNum = 1;
431	(void) yysettab(yywords);
432
433	s = getenv("YYDEBUG");
434	if (s)
435		yydebug = atoi(s);
436	else
437		yydebug = 0;
438
439	if (strcmp(filename, "-")) {
440		fp = fopen(filename, "r");
441		if (!fp) {
442			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
443				STRERROR(errno));
444			return -1;
445		}
446	} else
447		fp = stdin;
448
449	while (ippool_parsesome(fd, fp, iocfunc) == 1)
450		;
451	if (fp != NULL)
452		fclose(fp);
453	return 0;
454}
455
456
457int ippool_parsesome(fd, fp, iocfunc)
458int fd;
459FILE *fp;
460ioctlfunc_t iocfunc;
461{
462	char *s;
463	int i;
464
465	poolioctl = iocfunc;
466
467	if (feof(fp))
468		return 0;
469	i = fgetc(fp);
470	if (i == EOF)
471		return 0;
472	if (ungetc(i, fp) == EOF)
473		return 0;
474	if (feof(fp))
475		return 0;
476	s = getenv("YYDEBUG");
477	if (s)
478		yydebug = atoi(s);
479	else
480		yydebug = 0;
481
482	yyin = fp;
483	yyparse();
484	return 1;
485}
486