xref: /netbsd/external/bsd/ipf/dist/tools/ipnat_y.y (revision 9f0aeb89)
1 /*	$NetBSD: ipnat_y.y,v 1.4 2014/06/29 08:58:01 darrenr Exp $	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 %{
9 #ifdef  __FreeBSD__
10 # ifndef __FreeBSD_cc_version
11 #  include <osreldate.h>
12 # else
13 #  if __FreeBSD_cc_version < 430000
14 #   include <osreldate.h>
15 #  endif
16 # endif
17 #endif
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
24 #include <strings.h>
25 #endif
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/file.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <sys/time.h>
36 #include <syslog.h>
37 #include <net/if.h>
38 #if __FreeBSD_version >= 300000
39 # include <net/if_var.h>
40 #endif
41 #include <netdb.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #include "ipf.h"
45 #include "netinet/ipl.h"
46 #include "ipnat_l.h"
47 
48 #define	YYDEBUG	1
49 
50 extern	void	yyerror __P((char *));
51 extern	int	yyparse __P((void));
52 extern	int	yylex __P((void));
53 extern	int	yydebug;
54 extern	FILE	*yyin;
55 extern	int	yylineNum;
56 
57 static	ipnat_t		*nattop = NULL;
58 static	ipnat_t		*nat = NULL;
59 static	int		natfd = -1;
60 static	ioctlfunc_t	natioctlfunc = NULL;
61 static	addfunc_t	nataddfunc = NULL;
62 static	int		suggest_port = 0;
63 static	proxyrule_t	*prules = NULL;
64 static	int		parser_error = 0;
65 
66 static	void	newnatrule __P((void));
67 static	void	setnatproto __P((int));
68 static	void	setmapifnames __P((void));
69 static	void	setrdrifnames __P((void));
70 static	void	proxy_setconfig __P((int));
71 static	void	proxy_unsetconfig __P((void));
72 static	namelist_t *proxy_dns_add_pass __P((char *, char *));
73 static	namelist_t *proxy_dns_add_block __P((char *, char *));
74 static	void	proxy_addconfig __P((char *, int, char *, namelist_t *));
75 static	void	proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
76 				      char *, namelist_t *));
77 static	void	proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
78 static	void	setmapifnames __P((void));
79 static	void	setrdrifnames __P((void));
80 static	void	setifname __P((ipnat_t **, int, char *));
81 static	int	addname __P((ipnat_t **, char *));
82 %}
83 %union	{
84 	char	*str;
85 	u_32_t	num;
86 	struct {
87 		i6addr_t	a;
88 		int		f;
89 	} ipa;
90 	frentry_t	fr;
91 	frtuc_t	*frt;
92 	u_short	port;
93 	struct	{
94 		int	p1;
95 		int	p2;
96 		int	pc;
97 	} pc;
98 	struct	{
99 		i6addr_t	a;
100 		i6addr_t	m;
101 		int	t;		/* Address type */
102 		int	u;
103 		int	f;		/* Family */
104 		int	v;		/* IP version */
105 		int	s;		/* 0 = number, 1 = text */
106 		int	n;		/* number */
107 	} ipp;
108 	union	i6addr	ip6;
109 	namelist_t	*names;
110 };
111 
112 %token  <num>   YY_NUMBER YY_HEX
113 %token  <str>   YY_STR
114 %token	  YY_COMMENT
115 %token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
116 %token	  YY_RANGE_OUT YY_RANGE_IN
117 %token  <ip6>   YY_IPV6
118 
119 %token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
120 %token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
121 %token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
122 %token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
123 %token	IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
124 %token	IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
125 %token	IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
126 %token	IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
127 %type	<port> portspec
128 %type	<num> hexnumber compare range proto
129 %type	<num> saddr daddr sobject dobject mapfrom rdrfrom dip
130 %type	<ipa> hostname ipv4 ipaddr
131 %type	<ipp> addr rhsaddr rhdaddr erhdaddr
132 %type	<pc> portstuff portpair comaports srcports dstports
133 %type	<names> dnslines dnsline
134 %%
135 file:	line
136 	| assign
137 	| file line
138 	| file assign
139 	| file pconf ';'
140 	;
141 
142 line:	xx rule		{ int err;
143 			  while ((nat = nattop) != NULL) {
144 				if (nat->in_v[0] == 0)
145 					nat->in_v[0] = 4;
146 				if (nat->in_v[1] == 0)
147 					nat->in_v[1] = nat->in_v[0];
148 				nattop = nat->in_next;
149 				err = (*nataddfunc)(natfd, natioctlfunc, nat);
150 				free(nat);
151 				if (err != 0) {
152 					parser_error = err;
153 					break;
154 				}
155 			  }
156 			  if (parser_error == 0 && prules != NULL) {
157 				proxy_loadrules(natfd, natioctlfunc, prules);
158 				prules = NULL;
159 			  }
160 			  resetlexer();
161 			}
162 	| YY_COMMENT
163 	;
164 
165 assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
166 					  resetlexer();
167 					  free($1);
168 					  free($3);
169 					  yyvarnext = 0;
170 					}
171 	;
172 
173 assigning:
174 	'='				{ yyvarnext = 1; }
175 	;
176 
177 xx:					{ newnatrule(); }
178 	;
179 
180 rule:	map eol
181 	| mapblock eol
182 	| redir eol
183 	| rewrite ';'
184 	| divert ';'
185 	;
186 
187 no:	IPNY_NO				{ nat->in_flags |= IPN_NO; }
188 	;
189 
190 eol:	| ';'
191 	;
192 
193 map:	mapit ifnames addr tlate rhsaddr proxy mapoptions
194 				{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
195 					yyerror("3.address family mismatch");
196 				  if (nat->in_v[0] == 0 && $5.v != 0)
197 					nat->in_v[0] = $5.v;
198 				  else if (nat->in_v[0] == 0 && $3.v != 0)
199 					nat->in_v[0] = $3.v;
200 				  if (nat->in_v[1] == 0 && $5.v != 0)
201 					nat->in_v[1] = $5.v;
202 				  else if (nat->in_v[1] == 0 && $3.v != 0)
203 					nat->in_v[1] = $3.v;
204 				  nat->in_osrcatype = $3.t;
205 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
206 					sizeof($3.a));
207 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
208 					sizeof($3.a));
209 				  nat->in_nsrcatype = $5.t;
210 				  nat->in_nsrcafunc = $5.u;
211 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
212 					sizeof($5.a));
213 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
214 					sizeof($5.a));
215 
216 				  setmapifnames();
217 				}
218 	| mapit ifnames addr tlate rhsaddr mapport mapoptions
219 				{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
220 					yyerror("4.address family mismatch");
221 				  if (nat->in_v[1] == 0 && $5.v != 0)
222 					nat->in_v[1] = $5.v;
223 				  else if (nat->in_v[0] == 0 && $3.v != 0)
224 					nat->in_v[0] = $3.v;
225 				  if (nat->in_v[0] == 0 && $5.v != 0)
226 					nat->in_v[0] = $5.v;
227 				  else if (nat->in_v[1] == 0 && $3.v != 0)
228 					nat->in_v[1] = $3.v;
229 				  nat->in_osrcatype = $3.t;
230 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
231 					sizeof($3.a));
232 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
233 					sizeof($3.a));
234 				  nat->in_nsrcatype = $5.t;
235 				  nat->in_nsrcafunc = $5.u;
236 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
237 					sizeof($5.a));
238 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
239 					sizeof($5.a));
240 
241 				  setmapifnames();
242 				}
243 	| no mapit ifnames addr setproto ';'
244 				{ if (nat->in_v[0] == 0)
245 					nat->in_v[0] = $4.v;
246 				  nat->in_osrcatype = $4.t;
247 				  bcopy(&$4.a, &nat->in_osrc.na_addr[0],
248 					sizeof($4.a));
249 				  bcopy(&$4.m, &nat->in_osrc.na_addr[1],
250 					sizeof($4.a));
251 
252 				  setmapifnames();
253 				}
254 	| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
255 				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
256 					yyerror("5.address family mismatch");
257 				  if (nat->in_v[0] == 0 && $5.v != 0)
258 					nat->in_v[0] = $5.v;
259 				  else if (nat->in_v[0] == 0 && $3 != 0)
260 					nat->in_v[0] = ftov($3);
261 				  if (nat->in_v[1] == 0 && $5.v != 0)
262 					nat->in_v[1] = $5.v;
263 				  else if (nat->in_v[1] == 0 && $3 != 0)
264 					nat->in_v[1] = ftov($3);
265 				  nat->in_nsrcatype = $5.t;
266 				  nat->in_nsrcafunc = $5.u;
267 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
268 					sizeof($5.a));
269 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
270 					sizeof($5.a));
271 
272 				  setmapifnames();
273 				}
274 	| no mapit ifnames mapfrom setproto ';'
275 				{ nat->in_v[0] = ftov($4);
276 				  setmapifnames();
277 				}
278 	| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
279 				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
280 					yyerror("6.address family mismatch");
281 				  if (nat->in_v[0] == 0 && $5.v != 0)
282 					nat->in_v[0] = $5.v;
283 				  else if (nat->in_v[0] == 0 && $3 != 0)
284 					nat->in_v[0] = ftov($3);
285 				  if (nat->in_v[1] == 0 && $5.v != 0)
286 					nat->in_v[1] = $5.v;
287 				  else if (nat->in_v[1] == 0 && $3 != 0)
288 					nat->in_v[1] = ftov($3);
289 				  nat->in_nsrcatype = $5.t;
290 				  nat->in_nsrcafunc = $5.u;
291 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
292 					sizeof($5.a));
293 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
294 					sizeof($5.a));
295 
296 				  setmapifnames();
297 				}
298 	;
299 
300 mapblock:
301 	mapblockit ifnames addr tlate addr ports mapoptions
302 				{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
303 					yyerror("7.address family mismatch");
304 				  if (nat->in_v[0] == 0 && $5.v != 0)
305 					nat->in_v[0] = $5.v;
306 				  else if (nat->in_v[0] == 0 && $3.v != 0)
307 					nat->in_v[0] = $3.v;
308 				  if (nat->in_v[1] == 0 && $5.v != 0)
309 					nat->in_v[1] = $5.v;
310 				  else if (nat->in_v[1] == 0 && $3.v != 0)
311 					nat->in_v[1] = $3.v;
312 				  nat->in_osrcatype = $3.t;
313 				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
314 					sizeof($3.a));
315 				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
316 					sizeof($3.a));
317 				  nat->in_nsrcatype = $5.t;
318 				  nat->in_nsrcafunc = $5.u;
319 				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
320 					sizeof($5.a));
321 				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
322 					sizeof($5.a));
323 
324 				  setmapifnames();
325 				}
326 	| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
327 				{ if (nat->in_v[0] == 0)
328 					nat->in_v[0] = $5.v;
329 				  if (nat->in_v[1] == 0)
330 					nat->in_v[1] = $5.v;
331 				  nat->in_osrcatype = $5.t;
332 				  bcopy(&$5.a, &nat->in_osrc.na_addr[0],
333 					sizeof($5.a));
334 				  bcopy(&$5.m, &nat->in_osrc.na_addr[1],
335 					sizeof($5.a));
336 
337 				  setmapifnames();
338 				}
339 	;
340 
341 redir:	rdrit ifnames addr dport tlate dip nport setproto rdroptions
342 				{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
343 					yyerror("21.address family mismatch");
344 				  if (nat->in_v[0] == 0) {
345 					if ($3.v != AF_UNSPEC)
346 						nat->in_v[0] = ftov($3.f);
347 					  else
348 						nat->in_v[0] = ftov($6);
349 				  }
350 				  nat->in_odstatype = $3.t;
351 				  bcopy(&$3.a, &nat->in_odst.na_addr[0],
352 					sizeof($3.a));
353 				  bcopy(&$3.m, &nat->in_odst.na_addr[1],
354 					sizeof($3.a));
355 
356 				  setrdrifnames();
357 				}
358 	| no rdrit ifnames addr dport setproto ';'
359 				{ if (nat->in_v[0] == 0)
360 					nat->in_v[0] = ftov($4.f);
361 				  nat->in_odstatype = $4.t;
362 				  bcopy(&$4.a, &nat->in_odst.na_addr[0],
363 					sizeof($4.a));
364 				  bcopy(&$4.m, &nat->in_odst.na_addr[1],
365 					sizeof($4.a));
366 
367 				  setrdrifnames();
368 				}
369 	| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
370 				{ if ($5 != 0 && $3 != 0 && $5 != $3)
371 					yyerror("20.address family mismatch");
372 				  if (nat->in_v[0] == 0) {
373 					  if ($3 != AF_UNSPEC)
374 						nat->in_v[0] = ftov($3);
375 					  else
376 						nat->in_v[0] = ftov($5);
377 				  }
378 				  setrdrifnames();
379 				}
380 	| no rdrit ifnames rdrfrom setproto ';'
381 				{ nat->in_v[0] = ftov($4);
382 
383 				  setrdrifnames();
384 				}
385 	;
386 
387 rewrite:
388 	IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
389 				{ if (nat->in_v[0] == 0)
390 					nat->in_v[0] = ftov($4);
391 				  if (nat->in_redir & NAT_MAP)
392 					setmapifnames();
393 				  else
394 					setrdrifnames();
395 				  nat->in_redir |= NAT_REWRITE;
396 				}
397 	;
398 
399 divert:	IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
400 				{ if (nat->in_v[0] == 0)
401 					nat->in_v[0] = ftov($4);
402 				  if (nat->in_redir & NAT_MAP) {
403 					setmapifnames();
404 					nat->in_pr[0] = IPPROTO_UDP;
405 				  } else {
406 					setrdrifnames();
407 					nat->in_pr[1] = IPPROTO_UDP;
408 				  }
409 				  nat->in_flags &= ~IPN_TCP;
410 				}
411 	;
412 
413 tlate:	IPNY_TLATE		{ yyexpectaddr = 1; }
414 	;
415 
416 pconf:	IPNY_PROXY		{ yysetdict(proxies); }
417 	IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
418 				{ proxy_setconfig(IPNY_DNS); }
419 	dnslines ';' '}'
420 				{ proxy_addconfig("dns", $5, $7, $10);
421 				  proxy_unsetconfig();
422 				}
423 	;
424 
425 dnslines:
426 	dnsline 		{ $$ = $1; }
427 	| dnslines ';' dnsline	{ $$ = $1; $1->na_next = $3; }
428 	;
429 
430 dnsline:
431 	IPNY_ALLOW YY_STR	{ $$ = proxy_dns_add_pass(NULL, $2); }
432 	| IPNY_DENY YY_STR	{ $$ = proxy_dns_add_block(NULL, $2); }
433 	| IPNY_ALLOW '.' YY_STR	{ $$ = proxy_dns_add_pass(".", $3); }
434 	| IPNY_DENY '.' YY_STR	{ $$ = proxy_dns_add_block(".", $3); }
435 	;
436 
437 oninout:
438 	inout IPNY_ON ifnames	{ ; }
439 	;
440 
441 inout:	IPNY_IN			{ nat->in_redir = NAT_REDIRECT; }
442 	| IPNY_OUT		{ nat->in_redir = NAT_MAP; }
443 	;
444 
445 rwrproto:
446 	| IPNY_PROTO setproto
447 	;
448 
449 newdst:	src rhsaddr srcports dst erhdaddr dstports
450 				{ nat->in_nsrc.na_addr[0] = $2.a;
451 				  nat->in_nsrc.na_addr[1] = $2.m;
452 				  nat->in_nsrc.na_atype = $2.t;
453 				  if ($2.t == FRI_LOOKUP) {
454 					nat->in_nsrc.na_type = $2.u;
455 					nat->in_nsrc.na_subtype = $2.s;
456 					nat->in_nsrc.na_num = $2.n;
457 				  }
458 				  nat->in_nsports[0] = $3.p1;
459 				  nat->in_nsports[1] = $3.p2;
460 				  nat->in_ndst.na_addr[0] = $5.a;
461 				  nat->in_ndst.na_addr[1] = $5.m;
462 				  nat->in_ndst.na_atype = $5.t;
463 				  if ($5.t == FRI_LOOKUP) {
464 					nat->in_ndst.na_type = $5.u;
465 					nat->in_ndst.na_subtype = $5.s;
466 					nat->in_ndst.na_num = $5.n;
467 				  }
468 				  nat->in_ndports[0] = $6.p1;
469 				  nat->in_ndports[1] = $6.p2;
470 				}
471 	;
472 
473 divdst:	src addr ',' portspec dst addr ',' portspec IPNY_UDP
474 				{ nat->in_nsrc.na_addr[0] = $2.a;
475 				  if ($2.m.in4.s_addr != 0xffffffff)
476 					yyerror("divert must have /32 dest");
477 				  nat->in_nsrc.na_addr[1] = $2.m;
478 				  nat->in_nsports[0] = $4;
479 				  nat->in_nsports[1] = $4;
480 
481 				  nat->in_ndst.na_addr[0] = $6.a;
482 				  nat->in_ndst.na_addr[1] = $6.m;
483 				  if ($6.m.in4.s_addr != 0xffffffff)
484 					yyerror("divert must have /32 dest");
485 				  nat->in_ndports[0] = $8;
486 				  nat->in_ndports[1] = $8;
487 
488 				  nat->in_redir |= NAT_DIVERTUDP;
489 				}
490 	;
491 
492 src:	IPNY_SRC		{ yyexpectaddr = 1; }
493 	;
494 
495 dst:	IPNY_DST		{ yyexpectaddr = 1; }
496 	;
497 
498 srcports:
499 	comaports		{ $$.p1 = $1.p1;
500 				  $$.p2 = $1.p2;
501 				}
502 	| IPNY_PORT '=' portspec
503 				{ $$.p1 = $3;
504 				  $$.p2 = $3;
505 				  nat->in_flags |= IPN_FIXEDSPORT;
506 				}
507 	;
508 
509 dstports:
510 	comaports		{ $$.p1 = $1.p1;
511 				  $$.p2 = $1.p2;
512 				}
513 	| IPNY_PORT '=' portspec
514 				{ $$.p1 = $3;
515 				  $$.p2 = $3;
516 				  nat->in_flags |= IPN_FIXEDDPORT;
517 				}
518 	;
519 
520 comaports:
521 				{ $$.p1 = 0;
522 				  $$.p2 = 0;
523 				}
524 	| ','			{ if (!(nat->in_flags & IPN_TCPUDP))
525 					yyerror("must be TCP/UDP for ports");
526 				}
527 	portpair		{ $$.p1 = $3.p1;
528 				  $$.p2 = $3.p2;
529 				}
530 	;
531 
532 proxy:	| IPNY_PROXY port portspec YY_STR '/' proto
533 			{ int pos;
534 			  pos = addname(&nat, $4);
535 			  nat->in_plabel = pos;
536 			  if (nat->in_dcmp == 0) {
537 				nat->in_odport = $3;
538 			  } else if ($3 != nat->in_odport) {
539 				yyerror("proxy port numbers not consistant");
540 			  }
541 			  nat->in_ndport = $3;
542 			  setnatproto($6);
543 			  free($4);
544 			}
545 	| IPNY_PROXY port YY_STR YY_STR '/' proto
546 			{ int pnum, pos;
547 			  pos = addname(&nat, $4);
548 			  nat->in_plabel = pos;
549 			  pnum = getportproto($3, $6);
550 			  if (pnum == -1)
551 				yyerror("invalid port number");
552 			  nat->in_odport = ntohs(pnum);
553 			  nat->in_ndport = ntohs(pnum);
554 			  setnatproto($6);
555 			  free($3);
556 			  free($4);
557 			}
558 	| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
559 			{ int pos;
560 			  pos = addname(&nat, $4);
561 			  nat->in_plabel = pos;
562 			  if (nat->in_dcmp == 0) {
563 				nat->in_odport = $3;
564 			  } else if ($3 != nat->in_odport) {
565 				yyerror("proxy port numbers not consistant");
566 			  }
567 			  nat->in_ndport = $3;
568 			  setnatproto($6);
569 			  nat->in_pconfig = addname(&nat, $8);
570 			  free($4);
571 			  free($8);
572 			}
573 	| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
574 			{ int pnum, pos;
575 			  pos = addname(&nat, $4);
576 			  nat->in_plabel = pos;
577 			  pnum = getportproto($3, $6);
578 			  if (pnum == -1)
579 				yyerror("invalid port number");
580 			  nat->in_odport = ntohs(pnum);
581 			  nat->in_ndport = ntohs(pnum);
582 			  setnatproto($6);
583 			  pos = addname(&nat, $8);
584 			  nat->in_pconfig = pos;
585 			  free($3);
586 			  free($4);
587 			  free($8);
588 			}
589 	;
590 setproto:
591 	| proto				{ if (nat->in_pr[0] != 0 ||
592 					      nat->in_pr[1] != 0 ||
593 					      nat->in_flags & IPN_TCPUDP)
594 						yyerror("protocol set twice");
595 					  setnatproto($1);
596 					}
597 	| IPNY_TCPUDP			{ if (nat->in_pr[0] != 0 ||
598 					      nat->in_pr[1] != 0 ||
599 					      nat->in_flags & IPN_TCPUDP)
600 						yyerror("protocol set twice");
601 					  nat->in_flags |= IPN_TCPUDP;
602 					  nat->in_pr[0] = 0;
603 					  nat->in_pr[1] = 0;
604 					}
605 	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_pr[0] != 0 ||
606 					      nat->in_pr[1] != 0 ||
607 					      nat->in_flags & IPN_TCPUDP)
608 						yyerror("protocol set twice");
609 					  nat->in_flags |= IPN_TCPUDP;
610 					  nat->in_pr[0] = 0;
611 					  nat->in_pr[1] = 0;
612 					}
613 	;
614 
615 rhsaddr:
616 	addr				{ $$ = $1;
617 					  yyexpectaddr = 0;
618 					}
619 	| hostname '-' { yyexpectaddr = 1; } hostname
620 					{ $$.t = FRI_RANGE;
621 					  if ($1.f != $4.f)
622 						yyerror("8.address family "
623 							"mismatch");
624 					  $$.f = $1.f;
625 					  $$.v = ftov($1.f);
626 					  $$.a = $1.a;
627 					  $$.m = $4.a;
628 					  nat->in_flags |= IPN_SIPRANGE;
629 					  yyexpectaddr = 0;
630 					}
631 	| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
632 					{ $$.t = FRI_RANGE;
633 					  if ($2.f != $5.f)
634 						yyerror("9.address family "
635 							"mismatch");
636 					  $$.f = $2.f;
637 					  $$.v = ftov($2.f);
638 					  $$.a = $2.a;
639 					  $$.m = $5.a;
640 					  nat->in_flags |= IPN_SIPRANGE;
641 					  yyexpectaddr = 0;
642 					}
643 	;
644 
645 dip:
646 	hostname ',' { yyexpectaddr = 1; } hostname
647 				{ nat->in_flags |= IPN_SPLIT;
648 				  if ($1.f != $4.f)
649 					yyerror("10.address family "
650 						"mismatch");
651 				  $$ = $1.f;
652 				  nat->in_ndstip6 = $1.a;
653 				  nat->in_ndstmsk6 = $4.a;
654 				  nat->in_ndstatype = FRI_SPLIT;
655 				  yyexpectaddr = 0;
656 				}
657 	| rhdaddr		{ int bits;
658 				  nat->in_ndstip6 = $1.a;
659 				  nat->in_ndstmsk6 = $1.m;
660 				  nat->in_ndst.na_atype = $1.t;
661 				  yyexpectaddr = 0;
662 				  if ($1.f == AF_INET)
663 					bits = count4bits($1.m.in4.s_addr);
664 				  else
665 					bits = count6bits($1.m.i6);
666 				  if (($1.f == AF_INET) && (bits != 0) &&
667 				      (bits != 32)) {
668 					yyerror("dest ip bitmask not /32");
669 				  } else if (($1.f == AF_INET6) &&
670 					     (bits != 0) && (bits != 128)) {
671 					yyerror("dest ip bitmask not /128");
672 				  }
673 				  $$ = $1.f;
674 				}
675 	;
676 
677 rhdaddr:
678 	addr				{ $$ = $1;
679 					  yyexpectaddr = 0;
680 					}
681 	| hostname '-' hostname		{ bzero(&$$, sizeof($$));
682 					  $$.t = FRI_RANGE;
683 					  if ($1.f != 0 && $3.f != 0 &&
684 					      $1.f != $3.f)
685 						yyerror("11.address family "
686 							"mismatch");
687 					  $$.a = $1.a;
688 					  $$.m = $3.a;
689 					  nat->in_flags |= IPN_DIPRANGE;
690 					  yyexpectaddr = 0;
691 					}
692 	| IPNY_RANGE hostname '-' hostname
693 					{ bzero(&$$, sizeof($$));
694 					  $$.t = FRI_RANGE;
695 					  if ($2.f != 0 && $4.f != 0 &&
696 					      $2.f != $4.f)
697 						yyerror("12.address family "
698 							"mismatch");
699 					  $$.a = $2.a;
700 					  $$.m = $4.a;
701 					  nat->in_flags |= IPN_DIPRANGE;
702 					  yyexpectaddr = 0;
703 					}
704 	;
705 
706 erhdaddr:
707 	rhdaddr				{ $$ = $1; }
708 	| IPNY_DSTLIST '/' YY_NUMBER	{ $$.t = FRI_LOOKUP;
709 					  $$.u = IPLT_DSTLIST;
710 					  $$.s = 0;
711 					  $$.n = $3;
712 					}
713 	| IPNY_DSTLIST '/' YY_STR	{ $$.t = FRI_LOOKUP;
714 					  $$.u = IPLT_DSTLIST;
715 					  $$.s = 1;
716 					  $$.n = addname(&nat, $3);
717 					}
718 	;
719 
720 port:	IPNY_PORT			{ suggest_port = 1; }
721 	;
722 
723 portspec:
724 	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
725 						yyerror("invalid port number");
726 					  else
727 						$$ = $1;
728 					}
729 	| YY_STR			{ if (getport(NULL, $1,
730 						      &($$), NULL) == -1)
731 						yyerror("invalid port number");
732 					  $$ = ntohs($$);
733 					}
734 	;
735 
736 portpair:
737 	portspec			{ $$.p1 = $1; $$.p2 = $1; }
738 	| portspec '-' portspec		{ $$.p1 = $1; $$.p2 = $3; }
739 	| portspec ':' portspec		{ $$.p1 = $1; $$.p2 = $3; }
740 	;
741 
742 dport:	| port portpair			{ nat->in_odport = $2.p1;
743 					  if ($2.p2 == 0)
744 						nat->in_dtop = $2.p1;
745 					  else
746 						nat->in_dtop = $2.p2;
747 					}
748 	;
749 
750 nport:	| port portpair			{ nat->in_dpmin = $2.p1;
751 					  nat->in_dpnext = $2.p1;
752 					  nat->in_dpmax = $2.p2;
753 					  nat->in_ndport = $2.p1;
754 					  if (nat->in_dtop == 0)
755 						nat->in_dtop = $2.p2;
756 					}
757 	| port '=' portspec		{ nat->in_dpmin = $3;
758 					  nat->in_dpnext = $3;
759 					  nat->in_ndport = $3;
760 					  if (nat->in_dtop == 0)
761 						nat->in_dtop = nat->in_odport;
762 					  nat->in_flags |= IPN_FIXEDDPORT;
763 					}
764 	;
765 
766 ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_spmin = $2; }
767 	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
768 	;
769 
770 mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
771 	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
772 	;
773 
774 rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
775 	;
776 
777 mapblockit:
778 	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
779 	;
780 
781 mapfrom:
782 	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
783 						yyerror("13.address family "
784 							"mismatch");
785 					  $$ = $2;
786 					}
787 	| from sobject '!' to dobject
788 					{ if ($2 != 0 && $5 != 0 && $2 != $5)
789 						yyerror("14.address family "
790 							"mismatch");
791 					  nat->in_flags |= IPN_NOTDST;
792 					  $$ = $2;
793 					}
794 	| from sobject to '!' dobject
795 					{ if ($2 != 0 && $5 != 0 && $2 != $5)
796 						yyerror("15.address family "
797 							"mismatch");
798 					  nat->in_flags |= IPN_NOTDST;
799 					  $$ = $2;
800 					}
801 	;
802 
803 rdrfrom:
804 	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
805 						yyerror("16.address family "
806 							"mismatch");
807 					  $$ = $2;
808 					}
809 	| '!' from sobject to dobject
810 					{ if ($3 != 0 && $5 != 0 && $3 != $5)
811 						yyerror("17.address family "
812 							"mismatch");
813 					  nat->in_flags |= IPN_NOTSRC;
814 					  $$ = $3;
815 					}
816 	| from '!' sobject to dobject
817 					{ if ($3 != 0 && $5 != 0 && $3 != $5)
818 						yyerror("18.address family "
819 							"mismatch");
820 					  nat->in_flags |= IPN_NOTSRC;
821 					  $$ = $3;
822 					}
823 	;
824 
825 from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER;
826 					  yyexpectaddr = 1;
827 					}
828 	;
829 
830 to:	IPNY_TO				{ yyexpectaddr = 1; }
831 	;
832 
833 ifnames:
834 	ifname family			{ yyexpectaddr = 1; }
835 	| ifname ',' otherifname family	{ yyexpectaddr = 1; }
836 	;
837 
838 ifname:	YY_STR				{ setifname(&nat, 0, $1);
839 					  free($1);
840 					}
841 	;
842 
843 family:	| IPNY_INET			{ nat->in_v[0] = 4; nat->in_v[1] = 4; }
844 	| IPNY_INET6			{ nat->in_v[0] = 6; nat->in_v[1] = 6; }
845 	;
846 
847 otherifname:
848 	YY_STR				{ setifname(&nat, 1, $1);
849 					  free($1);
850 					}
851 	;
852 
853 mapport:
854 	IPNY_PORTMAP tcpudp portpair sequential
855 					{ nat->in_spmin = $3.p1;
856 					  nat->in_spmax = $3.p2;
857 					}
858 	| IPNY_PORTMAP portpair tcpudp sequential
859 					{ nat->in_spmin = $2.p1;
860 					  nat->in_spmax = $2.p2;
861 					}
862 	| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
863 					{ nat->in_flags |= IPN_AUTOPORTMAP;
864 					  nat->in_spmin = 1024;
865 					  nat->in_spmax = 65535;
866 					}
867 	| IPNY_ICMPIDMAP YY_STR portpair sequential
868 			{ if (strcmp($2, "icmp") != 0 &&
869 			      strcmp($2, "ipv6-icmp") != 0) {
870 				yyerror("icmpidmap not followed by icmp");
871 			  }
872 			  free($2);
873 			  if ($3.p1 < 0 || $3.p1 > 65535)
874 				yyerror("invalid 1st ICMP Id number");
875 			  if ($3.p2 < 0 || $3.p2 > 65535)
876 				yyerror("invalid 2nd ICMP Id number");
877 			  if (strcmp($2, "ipv6-icmp") == 0) {
878 				nat->in_pr[0] = IPPROTO_ICMPV6;
879 				nat->in_pr[1] = IPPROTO_ICMPV6;
880 			  } else {
881 				nat->in_pr[0] = IPPROTO_ICMP;
882 				nat->in_pr[1] = IPPROTO_ICMP;
883 			  }
884 			  nat->in_flags = IPN_ICMPQUERY;
885 			  nat->in_spmin = $3.p1;
886 			  nat->in_spmax = $3.p2;
887 			}
888 	;
889 
890 sobject:
891 	saddr				{ $$ = $1; }
892 	| saddr port portstuff		{ nat->in_osport = $3.p1;
893 					  nat->in_stop = $3.p2;
894 					  nat->in_scmp = $3.pc;
895 					  $$ = $1;
896 					}
897 	;
898 
899 saddr:	addr				{ nat->in_osrcatype = $1.t;
900 					  bcopy(&$1.a,
901 						&nat->in_osrc.na_addr[0],
902 						sizeof($1.a));
903 					  bcopy(&$1.m,
904 						&nat->in_osrc.na_addr[1],
905 						sizeof($1.m));
906 					  $$ = $1.f;
907 					}
908 	;
909 
910 dobject:
911 	daddr				{ $$ = $1; }
912 	| daddr port portstuff		{ nat->in_odport = $3.p1;
913 					  nat->in_dtop = $3.p2;
914 					  nat->in_dcmp = $3.pc;
915 					  $$ = $1;
916 					}
917 	;
918 
919 daddr:	addr				{ nat->in_odstatype = $1.t;
920 					  bcopy(&$1.a,
921 						&nat->in_odst.na_addr[0],
922 						sizeof($1.a));
923 					  bcopy(&$1.m,
924 						&nat->in_odst.na_addr[1],
925 						sizeof($1.m));
926 					  $$ = $1.f;
927 					}
928 	;
929 
930 addr:	IPNY_ANY			{ yyexpectaddr = 0;
931 					  bzero(&$$, sizeof($$));
932 					  $$.t = FRI_NORMAL;
933 					}
934 	| hostname			{ bzero(&$$, sizeof($$));
935 					  $$.a = $1.a;
936 					  $$.t = FRI_NORMAL;
937 					  $$.v = ftov($1.f);
938 					  $$.f = $1.f;
939 					  if ($$.f == AF_INET) {
940 						  $$.m.in4.s_addr = 0xffffffff;
941 					  } else if ($$.f == AF_INET6) {
942 						  $$.m.i6[0] = 0xffffffff;
943 						  $$.m.i6[1] = 0xffffffff;
944 						  $$.m.i6[2] = 0xffffffff;
945 						  $$.m.i6[3] = 0xffffffff;
946 					  }
947 					  yyexpectaddr = 0;
948 					}
949 	| hostname slash YY_NUMBER
950 					{ bzero(&$$, sizeof($$));
951 					  $$.a = $1.a;
952 					  $$.f = $1.f;
953 					  $$.v = ftov($1.f);
954 					  $$.t = FRI_NORMAL;
955 					  ntomask($$.f, $3, (u_32_t *)&$$.m);
956 					  $$.a.i6[0] &= $$.m.i6[0];
957 					  $$.a.i6[1] &= $$.m.i6[1];
958 					  $$.a.i6[2] &= $$.m.i6[2];
959 					  $$.a.i6[3] &= $$.m.i6[3];
960 					  yyexpectaddr = 0;
961 					}
962 	| hostname slash ipaddr		{ bzero(&$$, sizeof($$));
963 					  if ($1.f != $3.f) {
964 						yyerror("1.address family "
965 							"mismatch");
966 					  }
967 					  $$.a = $1.a;
968 					  $$.m = $3.a;
969 					  $$.t = FRI_NORMAL;
970 					  $$.a.i6[0] &= $$.m.i6[0];
971 					  $$.a.i6[1] &= $$.m.i6[1];
972 					  $$.a.i6[2] &= $$.m.i6[2];
973 					  $$.a.i6[3] &= $$.m.i6[3];
974 					  $$.f = $1.f;
975 					  $$.v = ftov($1.f);
976 					  yyexpectaddr = 0;
977 					}
978 	| hostname slash hexnumber	{ bzero(&$$, sizeof($$));
979 					  $$.a = $1.a;
980 					  $$.m.in4.s_addr = htonl($3);
981 					  $$.t = FRI_NORMAL;
982 					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
983 					  $$.f = $1.f;
984 					  $$.v = ftov($1.f);
985 					  if ($$.f == AF_INET6)
986 						yyerror("incorrect inet6 mask");
987 					}
988 	| hostname mask ipaddr		{ bzero(&$$, sizeof($$));
989 					  if ($1.f != $3.f) {
990 						yyerror("2.address family "
991 							"mismatch");
992 					  }
993 					  $$.a = $1.a;
994 					  $$.m = $3.a;
995 					  $$.t = FRI_NORMAL;
996 					  $$.a.i6[0] &= $$.m.i6[0];
997 					  $$.a.i6[1] &= $$.m.i6[1];
998 					  $$.a.i6[2] &= $$.m.i6[2];
999 					  $$.a.i6[3] &= $$.m.i6[3];
1000 					  $$.f = $1.f;
1001 					  $$.v = ftov($1.f);
1002 					  yyexpectaddr = 0;
1003 					}
1004 	| hostname mask hexnumber	{ bzero(&$$, sizeof($$));
1005 					  $$.a = $1.a;
1006 					  $$.m.in4.s_addr = htonl($3);
1007 					  $$.t = FRI_NORMAL;
1008 					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
1009 					  $$.f = AF_INET;
1010 					  $$.v = 4;
1011 					}
1012 	| pool slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1013 					  $$.a.iplookupnum = $3;
1014 					  $$.a.iplookuptype = IPLT_POOL;
1015 					  $$.a.iplookupsubtype = 0;
1016 					  $$.t = FRI_LOOKUP;
1017 					}
1018 	| pool slash YY_STR		{ bzero(&$$, sizeof($$));
1019 					  $$.a.iplookupname = addname(&nat,$3);
1020 					  $$.a.iplookuptype = IPLT_POOL;
1021 					  $$.a.iplookupsubtype = 1;
1022 					  $$.t = FRI_LOOKUP;
1023 					}
1024 	| hash slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1025 					  $$.a.iplookupnum = $3;
1026 					  $$.a.iplookuptype = IPLT_HASH;
1027 					  $$.a.iplookupsubtype = 0;
1028 					  $$.t = FRI_LOOKUP;
1029 					}
1030 	| hash slash YY_STR		{ bzero(&$$, sizeof($$));
1031 					  $$.a.iplookupname = addname(&nat,$3);
1032 					  $$.a.iplookuptype = IPLT_HASH;
1033 					  $$.a.iplookupsubtype = 1;
1034 					  $$.t = FRI_LOOKUP;
1035 					}
1036 	;
1037 
1038 slash:	'/'				{ yyexpectaddr = 0; }
1039 	;
1040 
1041 mask:	IPNY_MASK			{ yyexpectaddr = 0; }
1042 	;
1043 
1044 pool:	IPNY_POOL			{ if (!(nat->in_flags & IPN_FILTER)) {
1045 						yyerror("Can only use pool with from/to rules\n");
1046 					  }
1047 					  yyexpectaddr = 0;
1048 					  yyresetdict();
1049 					}
1050 	;
1051 
1052 hash:	IPNY_HASH			{ if (!(nat->in_flags & IPN_FILTER)) {
1053 						yyerror("Can only use hash with from/to rules\n");
1054 					  }
1055 					  yyexpectaddr = 0;
1056 					  yyresetdict();
1057 					}
1058 	;
1059 
1060 portstuff:
1061 	compare portspec		{ $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1062 	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1063 	;
1064 
1065 mapoptions:
1066 	rr frag age mssclamp nattag setproto purge
1067 	;
1068 
1069 rdroptions:
1070 	rr frag age sticky mssclamp rdrproxy nattag purge
1071 	;
1072 
1073 nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
1074 						  sizeof(nat->in_tag.ipt_tag));
1075 					}
1076 rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
1077 	;
1078 
1079 frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
1080 	;
1081 
1082 age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
1083 						  nat->in_age[1] = $2; }
1084 	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
1085 						  nat->in_age[1] = $4; }
1086 	;
1087 
1088 sticky: | IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
1089 					      !(nat->in_flags & IPN_SPLIT)) {
1090 						FPRINTF(stderr,
1091 		"'sticky' for use with round-robin/IP splitting only\n");
1092 					  } else
1093 						nat->in_flags |= IPN_STICKY;
1094 					}
1095 	;
1096 
1097 mssclamp:
1098 	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
1099 	;
1100 
1101 tcpudp:	IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
1102 	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
1103 	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
1104 					  nat->in_pr[0] = 0;
1105 					  nat->in_pr[1] = 0;
1106 					}
1107 	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
1108 					  nat->in_pr[0] = 0;
1109 					  nat->in_pr[1] = 0;
1110 					}
1111 	;
1112 
1113 sequential:
1114 	| IPNY_SEQUENTIAL		{ nat->in_flags |= IPN_SEQUENTIAL; }
1115 	;
1116 
1117 purge:
1118 	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1119 	;
1120 
1121 rdrproxy:
1122 	IPNY_PROXY YY_STR
1123 					{ int pos;
1124 					  pos = addname(&nat, $2);
1125 					  nat->in_plabel = pos;
1126 					  nat->in_odport = nat->in_dpnext;
1127 					  nat->in_dtop = nat->in_odport;
1128 					  free($2);
1129 					}
1130 	| proxy			{ if (nat->in_plabel != -1) {
1131 					nat->in_ndport = nat->in_odport;
1132 					nat->in_dpmin = nat->in_odport;
1133 					nat->in_dpmax = nat->in_dpmin;
1134 					nat->in_dtop = nat->in_dpmin;
1135 					nat->in_dpnext = nat->in_dpmin;
1136 				  }
1137 				}
1138 	;
1139 
1140 newopts:
1141 	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1142 	;
1143 
1144 proto:	YY_NUMBER			{ $$ = $1;
1145 					  if ($$ != IPPROTO_TCP &&
1146 					      $$ != IPPROTO_UDP)
1147 						suggest_port = 0;
1148 					}
1149 	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
1150 	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
1151 	| YY_STR			{ $$ = getproto($1);
1152 					  free($1);
1153 					  if ($$ == -1)
1154 						yyerror("unknown protocol");
1155 					  if ($$ != IPPROTO_TCP &&
1156 					      $$ != IPPROTO_UDP)
1157 						suggest_port = 0;
1158 					}
1159 	;
1160 
1161 hexnumber:
1162 	YY_HEX				{ $$ = $1; }
1163 	;
1164 
1165 hostname:
1166 	YY_STR				{ i6addr_t addr;
1167 					  int family;
1168 
1169 #ifdef USE_INET6
1170 					  if (nat->in_v[0] == 6)
1171 						family = AF_INET6;
1172 					  else
1173 #endif
1174 						family = AF_INET;
1175 					  memset(&($$), 0, sizeof($$));
1176 					  memset(&addr, 0, sizeof(addr));
1177 					  $$.f = family;
1178 					  if (gethost(family, $1,
1179 						      &addr) == 0) {
1180 						$$.a = addr;
1181 					  } else {
1182 						FPRINTF(stderr,
1183 							"Unknown host '%s'\n",
1184 							$1);
1185 					  }
1186 					  free($1);
1187 					}
1188 	| YY_NUMBER			{ memset(&($$), 0, sizeof($$));
1189 					  $$.a.in4.s_addr = htonl($1);
1190 					  if ($$.a.in4.s_addr != 0)
1191 						$$.f = AF_INET;
1192 					}
1193 	| ipv4				{ $$ = $1; }
1194 	| YY_IPV6			{ memset(&($$), 0, sizeof($$));
1195 					  $$.a = $1;
1196 					  $$.f = AF_INET6;
1197 					}
1198 	| YY_NUMBER YY_IPV6		{ memset(&($$), 0, sizeof($$));
1199 					  $$.a = $2;
1200 					  $$.f = AF_INET6;
1201 					}
1202 	;
1203 
1204 compare:
1205 	'='				{ $$ = FR_EQUAL; }
1206 	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1207 	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1208 	| YY_CMP_LT			{ $$ = FR_LESST; }
1209 	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1210 	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1211 	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1212 
1213 range:
1214 	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1215 	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1216 	| ':'				{ $$ = FR_INCRANGE; }
1217 	;
1218 
1219 ipaddr:	ipv4				{ $$ = $1; }
1220 	| YY_IPV6			{ $$.a = $1;
1221 					  $$.f = AF_INET6;
1222 					}
1223 	;
1224 
1225 ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1226 		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1227 			yyerror("Invalid octet string for IP address");
1228 			return 0;
1229 		  }
1230 		  bzero((char *)&$$, sizeof($$));
1231 		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1232 		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1233 		  $$.f = AF_INET;
1234 		}
1235 	;
1236 
1237 %%
1238 
1239 
1240 static	wordtab_t	proxies[] = {
1241 	{ "dns",	IPNY_DNS }
1242 };
1243 
1244 static	wordtab_t	dnswords[] = {
1245 	{ "allow",	IPNY_ALLOW },
1246 	{ "block",	IPNY_DENY },
1247 	{ "deny",	IPNY_DENY },
1248 	{ "drop",	IPNY_DENY },
1249 	{ "pass",	IPNY_ALLOW },
1250 
1251 };
1252 
1253 static	wordtab_t	yywords[] = {
1254 	{ "age",	IPNY_AGE },
1255 	{ "any",	IPNY_ANY },
1256 	{ "auto",	IPNY_AUTO },
1257 	{ "bimap",	IPNY_BIMAP },
1258 	{ "config",	IPNY_CONFIG },
1259 	{ "divert",	IPNY_DIVERT },
1260 	{ "dst",	IPNY_DST },
1261 	{ "dstlist",	IPNY_DSTLIST },
1262 	{ "frag",	IPNY_FRAG },
1263 	{ "from",	IPNY_FROM },
1264 	{ "hash",	IPNY_HASH },
1265 	{ "icmpidmap",	IPNY_ICMPIDMAP },
1266 	{ "in",		IPNY_IN },
1267 	{ "inet",	IPNY_INET },
1268 	{ "inet6",	IPNY_INET6 },
1269 	{ "mask",	IPNY_MASK },
1270 	{ "map",	IPNY_MAP },
1271 	{ "map-block",	IPNY_MAPBLOCK },
1272 	{ "mssclamp",	IPNY_MSSCLAMP },
1273 	{ "netmask",	IPNY_MASK },
1274 	{ "no",		IPNY_NO },
1275 	{ "on",		IPNY_ON },
1276 	{ "out",	IPNY_OUT },
1277 	{ "pool",	IPNY_POOL },
1278 	{ "port",	IPNY_PORT },
1279 	{ "portmap",	IPNY_PORTMAP },
1280 	{ "ports",	IPNY_PORTS },
1281 	{ "proto",	IPNY_PROTO },
1282 	{ "proxy",	IPNY_PROXY },
1283 	{ "purge",	IPNY_PURGE },
1284 	{ "range",	IPNY_RANGE },
1285 	{ "rewrite",	IPNY_REWRITE },
1286 	{ "rdr",	IPNY_RDR },
1287 	{ "round-robin",IPNY_ROUNDROBIN },
1288 	{ "sequential",	IPNY_SEQUENTIAL },
1289 	{ "src",	IPNY_SRC },
1290 	{ "sticky",	IPNY_STICKY },
1291 	{ "tag",	IPNY_TAG },
1292 	{ "tcp",	IPNY_TCP },
1293 	{ "tcpudp",	IPNY_TCPUDP },
1294 	{ "to",		IPNY_TO },
1295 	{ "udp",	IPNY_UDP },
1296 	{ "-",		'-' },
1297 	{ "->",		IPNY_TLATE },
1298 	{ "eq",		YY_CMP_EQ },
1299 	{ "ne",		YY_CMP_NE },
1300 	{ "lt",		YY_CMP_LT },
1301 	{ "gt",		YY_CMP_GT },
1302 	{ "le",		YY_CMP_LE },
1303 	{ "ge",		YY_CMP_GE },
1304 	{ NULL,		0 }
1305 };
1306 
1307 
1308 int
ipnat_parsefile(fd,addfunc,ioctlfunc,filename)1309 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1310 	int fd;
1311 	addfunc_t addfunc;
1312 	ioctlfunc_t ioctlfunc;
1313 	char *filename;
1314 {
1315 	FILE *fp = NULL;
1316 	int rval;
1317 	char *s;
1318 
1319 	yylineNum = 1;
1320 
1321 	(void) yysettab(yywords);
1322 
1323 	s = getenv("YYDEBUG");
1324 	if (s)
1325 		yydebug = atoi(s);
1326 	else
1327 		yydebug = 0;
1328 
1329 	if (strcmp(filename, "-")) {
1330 		fp = fopen(filename, "r");
1331 		if (!fp) {
1332 			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1333 				STRERROR(errno));
1334 			return -1;
1335 		}
1336 	} else
1337 		fp = stdin;
1338 
1339 	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1340 		;
1341 	if (fp != NULL)
1342 		fclose(fp);
1343 	if (rval == -1)
1344 		rval = 0;
1345 	else if (rval != 0)
1346 		rval = 1;
1347 	return rval;
1348 }
1349 
1350 
1351 int
ipnat_parsesome(fd,addfunc,ioctlfunc,fp)1352 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1353 	int fd;
1354 	addfunc_t addfunc;
1355 	ioctlfunc_t ioctlfunc;
1356 	FILE *fp;
1357 {
1358 	char *s;
1359 	int i;
1360 
1361 	natfd = fd;
1362 	parser_error = 0;
1363 	nataddfunc = addfunc;
1364 	natioctlfunc = ioctlfunc;
1365 
1366 	if (feof(fp))
1367 		return -1;
1368 	i = fgetc(fp);
1369 	if (i == EOF)
1370 		return -1;
1371 	if (ungetc(i, fp) == EOF)
1372 		return -1;
1373 	if (feof(fp))
1374 		return -1;
1375 	s = getenv("YYDEBUG");
1376 	if (s)
1377 		yydebug = atoi(s);
1378 	else
1379 		yydebug = 0;
1380 
1381 	yyin = fp;
1382 	yyparse();
1383 	return parser_error;
1384 }
1385 
1386 
1387 static void
newnatrule()1388 newnatrule()
1389 {
1390 	ipnat_t *n;
1391 
1392 	n = calloc(1, sizeof(*n));
1393 	if (n == NULL)
1394 		return;
1395 
1396 	if (nat == NULL) {
1397 		nattop = nat = n;
1398 		n->in_pnext = &nattop;
1399 	} else {
1400 		nat->in_next = n;
1401 		n->in_pnext = &nat->in_next;
1402 		nat = n;
1403 	}
1404 
1405 	n->in_flineno = yylineNum;
1406 	n->in_ifnames[0] = -1;
1407 	n->in_ifnames[1] = -1;
1408 	n->in_plabel = -1;
1409 	n->in_pconfig = -1;
1410 	n->in_size = sizeof(*n);
1411 
1412 	suggest_port = 0;
1413 }
1414 
1415 
1416 static void
setnatproto(p)1417 setnatproto(p)
1418 	int p;
1419 {
1420 	nat->in_pr[0] = p;
1421 	nat->in_pr[1] = p;
1422 
1423 	switch (p)
1424 	{
1425 	case IPPROTO_TCP :
1426 		nat->in_flags |= IPN_TCP;
1427 		nat->in_flags &= ~IPN_UDP;
1428 		break;
1429 	case IPPROTO_UDP :
1430 		nat->in_flags |= IPN_UDP;
1431 		nat->in_flags &= ~IPN_TCP;
1432 		break;
1433 #ifdef USE_INET6
1434 	case IPPROTO_ICMPV6 :
1435 #endif
1436 	case IPPROTO_ICMP :
1437 		nat->in_flags &= ~IPN_TCPUDP;
1438 		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1439 		    !(nat->in_redir & NAT_DIVERTUDP)) {
1440 			nat->in_dcmp = 0;
1441 			nat->in_scmp = 0;
1442 			nat->in_dpmin = 0;
1443 			nat->in_dpmax = 0;
1444 			nat->in_dpnext = 0;
1445 			nat->in_spmin = 0;
1446 			nat->in_spmax = 0;
1447 			nat->in_spnext = 0;
1448 		}
1449 		break;
1450 	default :
1451 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1452 			nat->in_flags &= ~IPN_TCPUDP;
1453 			nat->in_dcmp = 0;
1454 			nat->in_scmp = 0;
1455 			nat->in_dpmin = 0;
1456 			nat->in_dpmax = 0;
1457 			nat->in_dpnext = 0;
1458 			nat->in_spmin = 0;
1459 			nat->in_spmax = 0;
1460 			nat->in_spnext = 0;
1461 		}
1462 		break;
1463 	}
1464 
1465 	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1466 		nat->in_stop = 0;
1467 		nat->in_dtop = 0;
1468 		nat->in_osport = 0;
1469 		nat->in_odport = 0;
1470 		nat->in_stop = 0;
1471 		nat->in_osport = 0;
1472 		nat->in_dtop = 0;
1473 		nat->in_odport = 0;
1474 	}
1475 	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1476 		nat->in_flags &= ~IPN_FIXEDDPORT;
1477 }
1478 
1479 
1480 int
ipnat_addrule(fd,ioctlfunc,ptr)1481 ipnat_addrule(fd, ioctlfunc, ptr)
1482 	int fd;
1483 	ioctlfunc_t ioctlfunc;
1484 	void *ptr;
1485 {
1486 	ioctlcmd_t add, del;
1487 	ipfobj_t obj;
1488 	ipnat_t *ipn;
1489 
1490 	ipn = ptr;
1491 	bzero((char *)&obj, sizeof(obj));
1492 	obj.ipfo_rev = IPFILTER_VERSION;
1493 	obj.ipfo_size = ipn->in_size;
1494 	obj.ipfo_type = IPFOBJ_IPNAT;
1495 	obj.ipfo_ptr = ptr;
1496 
1497 	if ((opts & OPT_DONOTHING) != 0)
1498 		fd = -1;
1499 
1500 	if (opts & OPT_ZERORULEST) {
1501 		add = SIOCZRLST;
1502 		del = 0;
1503 	} else if (opts & OPT_PURGE) {
1504 		add = 0;
1505 		del = SIOCPURGENAT;
1506 	} else {
1507 		add = SIOCADNAT;
1508 		del = SIOCRMNAT;
1509 	}
1510 
1511 	if ((opts & OPT_VERBOSE) != 0)
1512 		printnat(ipn, opts);
1513 
1514 	if (opts & OPT_DEBUG)
1515 		binprint(ipn, ipn->in_size);
1516 
1517 	if ((opts & OPT_ZERORULEST) != 0) {
1518 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1519 			if ((opts & OPT_DONOTHING) == 0) {
1520 				char msg[80];
1521 
1522 				sprintf(msg, "%d:ioctl(zero nat rule)",
1523 					ipn->in_flineno);
1524 				return ipf_perror_fd(fd, ioctlfunc, msg);
1525 			}
1526 		} else {
1527 			PRINTF("hits %lu ", ipn->in_hits);
1528 #ifdef USE_QUAD_T
1529 			PRINTF("bytes %"PRIu64" ",
1530 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1531 #else
1532 			PRINTF("bytes %lu ",
1533 			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1534 #endif
1535 			printnat(ipn, opts);
1536 		}
1537 	} else if ((opts & OPT_REMOVE) != 0) {
1538 		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1539 			if ((opts & OPT_DONOTHING) == 0) {
1540 				char msg[80];
1541 
1542 				sprintf(msg, "%d:ioctl(delete nat rule)",
1543 					ipn->in_flineno);
1544 				return ipf_perror_fd(fd, ioctlfunc, msg);
1545 			}
1546 		}
1547 	} else {
1548 		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1549 			if ((opts & OPT_DONOTHING) == 0) {
1550 				char msg[80];
1551 
1552 				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1553 					ipn->in_flineno);
1554 				if (errno == EEXIST) {
1555 					sprintf(msg + strlen(msg), "(line %d)",
1556 						ipn->in_flineno);
1557 				}
1558 				return ipf_perror_fd(fd, ioctlfunc, msg);
1559 			}
1560 		}
1561 	}
1562 	return 0;
1563 }
1564 
1565 
1566 static void
setmapifnames()1567 setmapifnames()
1568 {
1569 	if (nat->in_ifnames[1] == -1)
1570 		nat->in_ifnames[1] = nat->in_ifnames[0];
1571 
1572 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1573 		nat->in_flags |= IPN_TCPUDP;
1574 
1575 	if ((nat->in_flags & IPN_TCPUDP) == 0)
1576 		setnatproto(nat->in_pr[1]);
1577 
1578 	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1579 	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1580 		nat_setgroupmap(nat);
1581 }
1582 
1583 
1584 static void
setrdrifnames()1585 setrdrifnames()
1586 {
1587 	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1588 		nat->in_flags |= IPN_TCPUDP;
1589 
1590 	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1591 	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1592 		setnatproto(IPPROTO_TCP);
1593 
1594 	if (nat->in_ifnames[1] == -1)
1595 		nat->in_ifnames[1] = nat->in_ifnames[0];
1596 }
1597 
1598 
1599 static void
proxy_setconfig(proxy)1600 proxy_setconfig(proxy)
1601 	int proxy;
1602 {
1603 	if (proxy == IPNY_DNS) {
1604 		yysetfixeddict(dnswords);
1605 	}
1606 }
1607 
1608 
1609 static void
proxy_unsetconfig()1610 proxy_unsetconfig()
1611 {
1612 	yyresetdict();
1613 }
1614 
1615 
1616 static namelist_t *
proxy_dns_add_pass(prefix,name)1617 proxy_dns_add_pass(prefix, name)
1618 	char *prefix, *name;
1619 {
1620 	namelist_t *n;
1621 
1622 	n = calloc(1, sizeof(*n));
1623 	if (n != NULL) {
1624 		if (prefix == NULL || *prefix == '\0') {
1625 			n->na_name = strdup(name);
1626 		} else {
1627 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1628 			strcpy(n->na_name, prefix);
1629 			strcat(n->na_name, name);
1630 		}
1631 	}
1632 	return n;
1633 }
1634 
1635 
1636 static namelist_t *
proxy_dns_add_block(prefix,name)1637 proxy_dns_add_block(prefix, name)
1638 	char *prefix, *name;
1639 {
1640 	namelist_t *n;
1641 
1642 	n = calloc(1, sizeof(*n));
1643 	if (n != NULL) {
1644 		if (prefix == NULL || *prefix == '\0') {
1645 			n->na_name = strdup(name);
1646 		} else {
1647 			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1648 			strcpy(n->na_name, prefix);
1649 			strcat(n->na_name, name);
1650 		}
1651 		n->na_value = 1;
1652 	}
1653 	return n;
1654 }
1655 
1656 
1657 static void
proxy_addconfig(proxy,proto,conf,list)1658 proxy_addconfig(proxy, proto, conf, list)
1659 	char *proxy, *conf;
1660 	int proto;
1661 	namelist_t *list;
1662 {
1663 	proxyrule_t *pr;
1664 
1665 	pr = calloc(1, sizeof(*pr));
1666 	if (pr != NULL) {
1667 		pr->pr_proto = proto;
1668 		pr->pr_proxy = proxy;
1669 		pr->pr_conf = conf;
1670 		pr->pr_names = list;
1671 		pr->pr_next = prules;
1672 		prules = pr;
1673 	}
1674 }
1675 
1676 
1677 static void
proxy_loadrules(fd,ioctlfunc,rules)1678 proxy_loadrules(fd, ioctlfunc, rules)
1679 	int fd;
1680 	ioctlfunc_t ioctlfunc;
1681 	proxyrule_t *rules;
1682 {
1683 	proxyrule_t *pr;
1684 
1685 	while ((pr = rules) != NULL) {
1686 		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1687 				 pr->pr_conf, pr->pr_names);
1688 		rules = pr->pr_next;
1689 		free(pr->pr_conf);
1690 		free(pr);
1691 	}
1692 }
1693 
1694 
1695 static void
proxy_loadconfig(fd,ioctlfunc,proxy,proto,conf,list)1696 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1697 	int fd;
1698 	ioctlfunc_t ioctlfunc;
1699 	char *proxy, *conf;
1700 	int proto;
1701 	namelist_t *list;
1702 {
1703 	namelist_t *na;
1704 	ipfobj_t obj;
1705 	ap_ctl_t pcmd;
1706 
1707 	obj.ipfo_rev = IPFILTER_VERSION;
1708 	obj.ipfo_type = IPFOBJ_PROXYCTL;
1709 	obj.ipfo_size = sizeof(pcmd);
1710 	obj.ipfo_ptr = &pcmd;
1711 
1712 	while ((na = list) != NULL) {
1713 		if ((opts & OPT_REMOVE) != 0)
1714 			pcmd.apc_cmd = APC_CMD_DEL;
1715 		else
1716 			pcmd.apc_cmd = APC_CMD_ADD;
1717 		pcmd.apc_dsize = strlen(na->na_name) + 1;
1718 		pcmd.apc_data = na->na_name;
1719 		pcmd.apc_arg = na->na_value;
1720 		pcmd.apc_p = proto;
1721 
1722 		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1723 		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1724 
1725 		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1726 		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1727 
1728 		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1729                         if ((opts & OPT_DONOTHING) == 0) {
1730                                 char msg[80];
1731 
1732                                 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1733 					yylineNum);
1734                                 ipf_perror_fd(fd, ioctlfunc, msg);
1735 				return;
1736                         }
1737 		}
1738 
1739 		list = na->na_next;
1740 		free(na->na_name);
1741 		free(na);
1742 	}
1743 }
1744 
1745 
1746 static void
setifname(np,idx,name)1747 setifname(np, idx, name)
1748 	ipnat_t **np;
1749 	int idx;
1750 	char *name;
1751 {
1752 	int pos;
1753 
1754 	pos = addname(np, name);
1755 	if (pos == -1)
1756 		return;
1757 	(*np)->in_ifnames[idx] = pos;
1758 }
1759 
1760 
1761 static int
addname(np,name)1762 addname(np, name)
1763 	ipnat_t **np;
1764 	char *name;
1765 {
1766 	ipnat_t *n;
1767 	int nlen;
1768 	int pos;
1769 
1770 	nlen = strlen(name) + 1;
1771 	n = calloc(1, (*np)->in_size + nlen);
1772 	memcpy(n, *np, (*np)->in_size);
1773 	free(*np);
1774 	if (*np == nattop)
1775 		nattop = n;
1776 	*np = n;
1777 	if (n == NULL)
1778 		return -1;
1779 	if (n->in_pnext != NULL)
1780 		*n->in_pnext = n;
1781 	n->in_size += nlen;
1782 	pos = n->in_namelen;
1783 	n->in_namelen += nlen;
1784 	strcpy(n->in_names + pos, name);
1785 	n->in_names[n->in_namelen] = '\0';
1786 	return pos;
1787 }
1788